Mercurial Hosting > nabble
diff src/nabble/view/web/user/ChangeAvatar2.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children | 18cf4872fd7f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/view/web/user/ChangeAvatar2.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,252 @@ + +package nabble.view.web.user; + +import fschmidt.util.java.HtmlUtils; +import fschmidt.util.java.ImageUtils; +import fschmidt.util.servlet.JtpContext; +import nabble.model.FileUpload; +import nabble.model.Init; +import nabble.model.Message; +import nabble.model.ModelException; +import nabble.model.User; +import nabble.view.lib.Jtp; +import nabble.view.lib.Shared; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.util.Map; +import java.util.Random; + + +public final class ChangeAvatar2 extends HttpServlet { + + private static final Logger logger = LoggerFactory.getLogger(ChangeAvatar2.class); + + private static final long SIZE_LIMIT = 4194304; // 4 Mb + + private void handleError(HttpServletRequest request, String errorMessage, PrintWriter out) { + + out.print( "\r\n<html>\r\n <head>\r\n " ); + Shared.loadJavascript(request, out); + out.print( "\r\n <script type=\"text/javascript\">\r\n function say() {\r\n alert(\"" ); + out.print( (HtmlUtils.javascriptStringEncode(errorMessage)) ); + out.print( "\");\r\n location.replace(\"" ); + out.print( (request.getContextPath()) ); + out.print( "/user/ChangeAvatar.jtp\");\r\n };\r\n </script>\r\n </head>\r\n <body onload=\"say()\"></body>\r\n</html>\r\n" ); + + } + + protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + JtpContext jtpContext = (JtpContext)getServletContext().getAttribute(JtpContext.attrName); + jtpContext.setTimeLimit(request,0L); + PrintWriter out = response.getWriter(); + String context = request.getContextPath(); + User user = Jtp.getUser(request, response); + if (user == null) { + Jtp.login("You must login to change your avatar.", request, response); + return; + } + + String errorMessage = null; + + String action = request.getParameter("action"); + if ("crop".equals(action)) { + String imageName = request.getParameter("image"); + int x = Jtp.getInt(request, "crop_x"); + int y = Jtp.getInt(request, "crop_y"); + int width = Jtp.getInt(request, "crop_width"); + int height = Jtp.getInt(request, "crop_height"); + try { + Message.Source srcTemp = Message.SourceType.getType('t').getSource(user.getSite(),user.getId()); + InputStream in = FileUpload.getFileContent(srcTemp, imageName); + if (in == null) { + handleError(request, "Error uploading image. Please try again.", out); + return; + } + BufferedImage originalImage = ImageIO.read(in); + in.close(); + if (originalImage.getWidth() < 100 || originalImage.getHeight() < 100) { + handleError(request, "The width and height must be greater than 100 pixels.", out); + return; + } + + BufferedImage croppedImage100 = ImageUtils.cropImage(originalImage, x, y, width, height); + croppedImage100 = ImageUtils.getThumbnail(croppedImage100, 100, 100); + + BufferedImage croppedImage24 = ImageUtils.blurImage(croppedImage100); + croppedImage24 = ImageUtils.resizeImage(croppedImage24, 24, 24); + + user.saveAvatar(croppedImage24,croppedImage100); + FileUpload.deleteFile(imageName, srcTemp); + } catch (ModelException e) { + logger.error(toString(), e); + errorMessage = e.getMessage(); + } + + if (errorMessage == null) { + response.sendRedirect("/user/ChangeAvatar2$ReloadAvatars.jtp"); + return; + } else { + handleError(request, errorMessage, out); + return; + } + } else if ("delete".equals(action)) { + user.deleteAvatar(); + response.sendRedirect("/user/ChangeAvatar2$ReloadAvatars.jtp"); + return; + } + + int imageWidth = 0; + int imageHeight = 0; + String fileName = "_user" + user.getId() + ".png"; + try { + final Map<String, FileItem> map; + try { + map = Jtp.getFileItems(request); + } catch (FileUploadException e) { + logger.warn("",e); + throw ModelException.newInstance("upload_avatar_failed","upload failed - " + e.getMessage()); + } + FileItem fi = map.get("image"); + + if (fi == null) { + handleError(request, "Image upload failed.", out); + return; + } else if (fi.getSize() > SIZE_LIMIT) { + handleError(request, "The file you uploaded is too big. Please upload a smaller image (less than 4Mb).", out); + return; + } + + InputStream in = fi.getInputStream(); + BufferedImage image; + try { + image = ImageIO.read(in); + } catch (javax.imageio.IIOException e) { + handleError(request, "The uploaded image is broken.", out); + return; + } finally { + in.close(); + } + if (image == null) { + handleError(request, "Please upload the image again.", out); + return; + } else if (image.getWidth() < 100 || image.getHeight() < 100) { + handleError(request, "The width and height must be greater than 100 pixels.", out); + return; + } else if (image.getWidth() > 800 || image.getHeight() > 800) { + try { + image = ImageUtils.getThumbnail(image, 800, 800); + } catch (RuntimeException e) { + // This catch block will be improved later when I discover the exact line that throws + // a RuntimeException in ImageUtils [Hugo - April/2010] + if (fi.getSize() <= FileUpload.MAX_IMAGE_SIZE) { + if( Init.tempDir == null ) { + logger.info("Init.tempDir == null"); + } else { + FileOutputStream fos = new FileOutputStream(Init.tempDir + FileUpload.getName(fi)); + fos.write(fi.get()); + fos.close(); + } + } + handleError(request, "Unable to handle this image.", out); + return; + } + } + + imageWidth = image.getWidth(); + imageHeight = image.getHeight(); + + Message.Source tempSrc = Message.SourceType.getType('t').getSource(user.getSite(),user.getId()); + FileUpload.saveImage(image, fileName, tempSrc); + } catch (ModelException e) { + errorMessage = e.getMessage(); + logger.warn("image upload failed", e); + } + + if (errorMessage != null) { + handleError(request, errorMessage, out); + return; + } + + out.print( "\r\n<html>\r\n<head>\r\n " ); + Shared.title(request,response,"Change Avatar"); + out.print( "\r\n <style type=\"text/css\">\r\n #imageContainer{\r\n margin:15px;\r\n left:0px;\r\n top:0px;\r\n position:relative;\r\n }\r\n\r\n .crop_transparentDiv{\r\n background-color:#FFF;\r\n filter:alpha(opacity=80);\r\n -khtml-opacity: 0.8;\r\n -moz-opacity: 0.8;\r\n opacity:0.8;\r\n position:absolute;\r\n }\r\n .crop_dottedDiv{\r\n position:absolute;\r\n border:1px dotted red;\r\n z-index:10000;\r\n }\r\n\r\n .crop_dottedDiv div{\r\n filter:alpha(opacity=0);\r\n opacity:0;\r\n -khtml-opacity: 0;\r\n -moz-opacity: 0;\r\n width:100%;\r\n height:100%;\r\n background-color:#FFF;\r\n }\r\n </style>\r\n <script type=\"text/javascript\">\r\n var crop_script_alwaysPreserveAspectRatio = true; // Always preserve aspect ratio\r\n var crop_script_fixedRatio = 1; // Width relative to height 2 = ratio 2:1\r\n\r\n var cropToolBorderWidth = 1; // Width of dotted border around crop rectangle\r\n var smallSquareWidth = 7; // Size of small squares used to resize crop rectangle\r\n\r\n // Size of image shown in crop tool\r\n var crop_imageWidth = " ); + out.print( (imageWidth) ); + out.print( ";\r\n var crop_imageHeight = " ); + out.print( (imageHeight) ); + out.print( ";\r\n\r\n // Size of original image\r\n var crop_originalImageWidth = crop_imageWidth;\r\n var crop_originalImageHeight = crop_imageHeight;\r\n\r\n var crop_minimumPercent = 10; // Minimum percent - resize\r\n var crop_maximumPercent = 100; // Maximum percent -resize\r\n\r\n var crop_minimumWidthHeight = 100; // Minimum width and height of crop area\r\n\r\n var updateFormValuesAsYouDrag = true; // This variable indicates if form values should be updated as we drag. This process could make the script work a little bit slow. That's why this option is set as a variable.\r\n if(!document.all)updateFormValuesAsYouDrag = false; // Enable this feature only in IE\r\n </script>\r\n <script src=\"" ); + out.print( (context) ); + out.print( "/util/image-crop.js\" type=\"text/javascript\"></script>\r\n</head>\r\n<body>\r\n" ); + + Shared.minHeaderGlobal(request, response); + Shared.profileHeading(request,out,user,"Change Avatar - Crop Image"); + + out.print( "\r\n<b>Please select a square region on the image below.</b><br/>\r\nYou can drag the red handles to resize the square or drag the whole selected area.\r\n<br/><br/>\r\n<form action=\"/user/ChangeAvatar2.jtp\" method=\"POST\" accept-charset=\"UTF-8\">\r\n <input type=\"hidden\" name=\"action\" value=\"crop\">\r\n <input type=\"hidden\" name=\"image\" value=\"" ); + out.print( (fileName) ); + out.print( "\">\r\n <input type=\"hidden\" name=\"crop_x\" id=\"input_crop_x\">\r\n <input type=\"hidden\" name=\"crop_y\" id=\"input_crop_y\">\r\n <input type=\"hidden\" name=\"crop_width\" id=\"input_crop_width\">\r\n <input type=\"hidden\" name=\"crop_height\" id=\"input_crop_height\">\r\n <input type=\"hidden\" name=\"crop_percent_size\" id=\"crop_percent_size\">\r\n <input type=\"submit\" value=\"Crop Image\">\r\n</form>\r\n<div class=\"crop_content\">\r\n <div id=\"imageContainer\">\r\n " ); + + // Here I create a random number that is appended to the end + // of the image URL. This prevents the browser from showing an + // old cached image. + Random random = new Random(); + int any = random.nextInt(1000); + + out.print( "\r\n<img src=\"/file/t" ); + out.print( (user.getId()) ); + out.print( "/" ); + out.print( (fileName) ); + out.print( "?" ); + out.print( (any) ); + out.print( "\"/>\r\n</div>\r\n</div>\r\n\r\n<script type=\"text/javascript\">\r\ninit_imageCrop('http://" ); + out.print( (request.getHeader("host")) ); + out.print( "');\r\n\r\nif (Nabble.isEmbedded) {\r\n$(window).load(Nabble.resizeFrames);\r\n}\r\n</script>\r\n\r\n" ); + Shared.footer(request,response); + out.print( "\r\n" ); + Shared.analytics(request,response); + out.print( "\r\n</body>\r\n</html>\r\n" ); + + } + + public static class ReloadAvatars extends HttpServlet { + + protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + /* + This servlet is a tricky way to force the browser to reload the user avatars. + Since we don't specify cache headers for images, browsers cache them using + internal algorithms. The only way to update those images is by refreshing the page + either by pressing F5 or using location.reload(true). + */ + PrintWriter out = response.getWriter(); + User user = Jtp.getUser(request, response); + if (user == null) + return; + Jtp.dontCache(response); + + out.print( "\r\n<html>\r\n <head>\r\n " ); + Shared.loadJavascript(request, out); + out.print( "\r\n <script type=\"text/javascript\">\r\n function init() {\r\n var done = Nabble.getCookie('done');\r\n if (done) {\r\n Nabble.deleteCookie('done');\r\n location = '/template/NamlServlet.jtp?macro=user_profile';\r\n } else {\r\n Nabble.setCookie('done','y');\r\n location.reload(true);\r\n }\r\n };\r\n </script>\r\n </head>\r\n <body onload=\"init()\">\r\n <div style=\"display:none\">\r\n <img src=\"" ); + out.print( (Shared.getAvatarImageURL(user, false)) ); + out.print( "\"/>\r\n <img src=\"" ); + out.print( (Shared.getAvatarImageURL(user, true)) ); + out.print( "\"/>\r\n </div>\r\n </body>\r\n</html>\r\n" ); + + } + + } +} +