From 37e6d26e02d51a4de257200bbf207712fa3a6980 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sat, 23 Oct 2021 05:37:09 +0300 Subject: ImagesService refactoring * Merge ImagesService and ImageUtils * add avatar metadata to RSS feeds --- src/main/java/com/juick/ActivityPubManager.java | 72 ++++---- src/main/java/com/juick/service/ImagesService.java | 14 ++ .../java/com/juick/service/ImagesServiceImpl.java | 187 +++++++++++++++++++-- src/main/java/com/juick/util/ImageUtils.java | 132 +-------------- src/main/java/com/juick/www/WebApp.java | 24 ++- src/main/java/com/juick/www/rss/Feeds.java | 1 + src/main/java/com/juick/www/rss/MessagesView.java | 44 +++-- .../java/com/juick/server/tests/ServerTests.java | 18 +- 8 files changed, 288 insertions(+), 204 deletions(-) diff --git a/src/main/java/com/juick/ActivityPubManager.java b/src/main/java/com/juick/ActivityPubManager.java index 57110729..5df89527 100644 --- a/src/main/java/com/juick/ActivityPubManager.java +++ b/src/main/java/com/juick/ActivityPubManager.java @@ -17,30 +17,63 @@ package com.juick; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.inject.Inject; + import com.juick.model.Message; import com.juick.model.Reaction; +import com.juick.model.Tag; import com.juick.model.User; +import com.juick.service.MessagesService; +import com.juick.service.SocialService; +import com.juick.service.activities.ActivityListener; +import com.juick.service.activities.AnnounceEvent; +import com.juick.service.activities.DeleteMessageEvent; +import com.juick.service.activities.DeleteUserEvent; +import com.juick.service.activities.FollowEvent; +import com.juick.service.activities.UndoAnnounceEvent; +import com.juick.service.activities.UndoFollowEvent; +import com.juick.service.activities.UpdateEvent; +import com.juick.service.activities.UpdateUserEvent; +import com.juick.service.component.NotificationListener; +import com.juick.service.component.PingEvent; +import com.juick.service.component.SystemEvent; +import com.juick.util.HttpBadRequestException; +import com.juick.util.HttpUtils; +import com.juick.util.MessageUtils; import com.juick.util.formatters.PlainTextFormatter; -import com.juick.model.Tag; import com.juick.www.api.SystemActivity.ActivityType; import com.juick.www.api.activity.model.Context; -import com.juick.www.api.activity.model.activities.*; +import com.juick.www.api.activity.model.activities.Accept; +import com.juick.www.api.activity.model.activities.Announce; +import com.juick.www.api.activity.model.activities.Create; +import com.juick.www.api.activity.model.activities.Delete; +import com.juick.www.api.activity.model.activities.Update; import com.juick.www.api.activity.model.objects.Actor; import com.juick.www.api.activity.model.objects.Hashtag; import com.juick.www.api.activity.model.objects.Image; import com.juick.www.api.activity.model.objects.Mention; import com.juick.www.api.activity.model.objects.Note; import com.juick.www.api.activity.model.objects.Person; -import com.juick.util.HttpBadRequestException; -import com.juick.util.HttpUtils; -import com.juick.service.MessagesService; -import com.juick.service.SocialService; -import com.juick.service.UserService; -import com.juick.service.activities.*; -import com.juick.service.component.*; -import com.juick.util.MessageUtils; import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.template.PebbleTemplate; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,25 +81,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; -import javax.annotation.Nonnull; -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URI; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - public class ActivityPubManager implements ActivityListener, NotificationListener { private static final Logger logger = LoggerFactory.getLogger("ActivityPub"); @Inject diff --git a/src/main/java/com/juick/service/ImagesService.java b/src/main/java/com/juick/service/ImagesService.java index 3fb06c63..0891dca9 100644 --- a/src/main/java/com/juick/service/ImagesService.java +++ b/src/main/java/com/juick/service/ImagesService.java @@ -17,11 +17,14 @@ package com.juick.service; +import com.juick.model.Attachment; import com.juick.model.Message; +import java.io.FileNotFoundException; import java.io.IOException; public interface ImagesService { + void setAttachmentMetadata(String baseUrl, Message msg) throws Exception; /** * Move attached image from temp folder to image folder. @@ -38,4 +41,15 @@ public interface ImagesService { * @param uid User id that is used to build image file names. */ void saveAvatar(String tempFilename, int uid) throws IOException; + + String getTemporaryDirectory(); + + String getImageDirectory(); + + /** + * Get image metadata + * @param resource URL + * @return image metadata + */ + Attachment getImageMetadata(String resourceUrl) throws FileNotFoundException, IOException; } diff --git a/src/main/java/com/juick/service/ImagesServiceImpl.java b/src/main/java/com/juick/service/ImagesServiceImpl.java index 72d5b97c..6687a59b 100644 --- a/src/main/java/com/juick/service/ImagesServiceImpl.java +++ b/src/main/java/com/juick/service/ImagesServiceImpl.java @@ -20,29 +20,58 @@ package com.juick.service; import com.juick.model.Attachment; import com.juick.model.Message; import com.juick.model.Photo; -import com.juick.util.ImageUtils; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.Imaging; +import org.apache.commons.imaging.common.ImageMetadata; +import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata; +import org.apache.commons.imaging.formats.tiff.TiffField; +import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Rotation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; +import java.awt.image.BufferedImage; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Iterator; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; public class ImagesServiceImpl implements ImagesService { - private final ImageUtils imageUtils; + + private static final Logger logger = LoggerFactory.getLogger(ImagesService.class); + private final String imgDir; + private final String tmpDir; public ImagesServiceImpl(String imgDir, String tmpDir) { this.imgDir = imgDir; - imageUtils = new ImageUtils(imgDir, tmpDir); + this.tmpDir = tmpDir; } + @Override public void setAttachmentMetadata(String baseUrl, Message msg) throws Exception { if (!StringUtils.isEmpty(msg.getAttachmentType())) { Photo photo = new Photo(); - if (msg.getRid()> 0) { - photo.setSmall(String.format("%sphotos-512/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType())); - photo.setMedium(String.format("%sphotos-1024/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType())); - photo.setThumbnail(String.format("%sps/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType())); + if (msg.getRid() > 0) { + photo.setSmall(String.format("%sphotos-512/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), + msg.getAttachmentType())); + photo.setMedium(String.format("%sphotos-1024/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), + msg.getAttachmentType())); + photo.setThumbnail( + String.format("%sps/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType())); } else { photo.setSmall(String.format("%sphotos-512/%d.%s", baseUrl, msg.getMid(), msg.getAttachmentType())); photo.setMedium(String.format("%sphotos-1024/%d.%s", baseUrl, msg.getMid(), msg.getAttachmentType())); @@ -65,20 +94,20 @@ public class ImagesServiceImpl implements ImagesService { builder.append("-").append(msg.getRid()); } builder.append(".").append(msg.getAttachmentType()); - String originalUrl = builder.toString(); + String originalUrl = builder.toString(); - Attachment original = imageUtils.getAttachment(fullImage); + Attachment original = getAttachment(fullImage); original.setUrl(originalUrl); - Attachment medium = imageUtils.getAttachment(mediumImage); + Attachment medium = getAttachment(mediumImage); medium.setUrl(photo.getMedium()); original.setMedium(medium); - Attachment small = imageUtils.getAttachment(smallImage); + Attachment small = getAttachment(smallImage); small.setUrl(photo.getSmall()); original.setSmall(small); - Attachment thumb = imageUtils.getAttachment(thumbnailImage); + Attachment thumb = getAttachment(thumbnailImage); thumb.setUrl(photo.getMedium()); original.setThumbnail(thumb); @@ -87,12 +116,140 @@ public class ImagesServiceImpl implements ImagesService { } @Override - public void saveImageWithPreviews(String tempFilename, String outputFilename) throws IOException { - imageUtils.saveImageWithPreviews(tempFilename, outputFilename); + public Attachment getImageMetadata(String resourceLocation) throws FileNotFoundException, IOException { + return getAttachment(ResourceUtils.getFile(resourceLocation)); + } + + /** + * Returns BufferedImage, same as ImageIO.read() does. + * + *

+ * JPEG images with EXIF metadata are rotated according to Orientation tag. + * + * @param imageFile a File to read from. + */ + private static BufferedImage readImageWithOrientation(File imageFile) throws IOException { + + BufferedImage image = ImageIO.read(imageFile); + if (!FilenameUtils.getExtension(imageFile.getName()).equals("jpg")) { + return image; + } + + try { + ImageMetadata metadata = Imaging.getMetadata(imageFile); + + if (metadata instanceof JpegImageMetadata) { + JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata; + TiffField orientationField = jpegMetadata.findEXIFValue(TiffTagConstants.TIFF_TAG_ORIENTATION); + + if (orientationField != null) { + int orientation = orientationField.getIntValue(); + switch (orientation) { + case TiffTagConstants.ORIENTATION_VALUE_ROTATE_90_CW: + image = Scalr.rotate(image, Rotation.CW_90); + break; + case TiffTagConstants.ORIENTATION_VALUE_ROTATE_180: + image = Scalr.rotate(image, Rotation.CW_180); + break; + case TiffTagConstants.ORIENTATION_VALUE_ROTATE_270_CW: + image = Scalr.rotate(image, Rotation.CW_270); + break; + case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL: + image = Scalr.rotate(image, Rotation.FLIP_HORZ); + break; + case TiffTagConstants.ORIENTATION_VALUE_MIRROR_VERTICAL: + image = Scalr.rotate(image, Rotation.FLIP_VERT); + break; + case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_90_CW: + image = Scalr.rotate(Scalr.rotate(image, Rotation.FLIP_HORZ), Rotation.CW_90); + break; + case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_270_CW: + image = Scalr.rotate(Scalr.rotate(image, Rotation.FLIP_HORZ), Rotation.CW_270); + break; + case TiffTagConstants.ORIENTATION_VALUE_HORIZONTAL_NORMAL: + default: + // do nothing + break; + } + } + } + } catch (ImageReadException | IOException e) { + // failed to read metadata. + // nothing to do here, return image as is. + } + + return image; } @Override + public void saveImageWithPreviews(String tempFilename, String outputFilename) throws IOException { + String ext = FilenameUtils.getExtension(outputFilename); + + Path outputImagePath = Paths.get(imgDir, "p", outputFilename); + // this throws strange exceptions + // Files.move(Paths.get(tmpDir, tempFilename), outputImagePath); + FileUtils.moveFile(Paths.get(tmpDir, tempFilename).toFile(), outputImagePath.toFile()); + BufferedImage originalImage = readImageWithOrientation(outputImagePath.toFile()); + + int width = originalImage.getWidth(); + int height = originalImage.getHeight(); + int maxDimension = Math.max(width, height); + BufferedImage image1024 = (maxDimension > 1024) ? Scalr.resize(originalImage, 1024) : originalImage; + BufferedImage image0512 = (maxDimension > 512) ? Scalr.resize(originalImage, 512) : originalImage; + BufferedImage image0160 = (maxDimension > 160) ? Scalr.resize(originalImage, 160) : originalImage; + ImageIO.write(image1024, ext, Paths.get(imgDir, "photos-1024", outputFilename).toFile()); + ImageIO.write(image0512, ext, Paths.get(imgDir, "photos-512", outputFilename).toFile()); + ImageIO.write(image0160, ext, Paths.get(imgDir, "ps", outputFilename).toFile()); + } + public void saveAvatar(String tempFilename, int uid) throws IOException { - imageUtils.saveAvatar(tempFilename, uid); + String ext = FilenameUtils.getExtension(tempFilename); + String originalName = String.format("%s.%s", uid, ext); + Path originalPath = Paths.get(imgDir, "ao", originalName); + Files.move(Paths.get(tmpDir, tempFilename), originalPath, StandardCopyOption.REPLACE_EXISTING); + BufferedImage originalImage = ImageIO.read(originalPath.toFile()); + + String targetExt = "png"; + String targetName = String.format("%s.%s", uid, targetExt); + ImageIO.write(Scalr.resize(originalImage, 96), targetExt, Paths.get(imgDir, "a", targetName).toFile()); + ImageIO.write(Scalr.resize(originalImage, 32), targetExt, Paths.get(imgDir, "as", targetName).toFile()); + } + + public Attachment getAttachment(File imgFile) throws IOException { + Attachment attachment = new Attachment(); + if (imgFile.exists()) { + try (ImageInputStream stream = ImageIO.createImageInputStream(imgFile)) { + Iterator iter = ImageIO.getImageReaders(stream); + while (iter.hasNext()) { + ImageReader reader = iter.next(); + try { + reader.setInput(stream); + attachment.setWidth(reader.getWidth(reader.getMinIndex())); + attachment.setHeight(reader.getHeight(reader.getMinIndex())); + return attachment; + } catch (Exception e) { + logger.debug("Error reading {}, trying next reader", imgFile.getAbsolutePath()); + } finally { + reader.dispose(); + } + } + } + } else { + logger.warn("File not exists yet: {}", imgFile.getAbsolutePath()); + return attachment; + } + + logger.warn("Not a known image file {}", imgFile.getAbsolutePath()); + return attachment; + } + + @Override + public String getImageDirectory() { + return imgDir; + } + + @Override + public String getTemporaryDirectory() { + return tmpDir; } } diff --git a/src/main/java/com/juick/util/ImageUtils.java b/src/main/java/com/juick/util/ImageUtils.java index 3549a89a..6ba6882c 100644 --- a/src/main/java/com/juick/util/ImageUtils.java +++ b/src/main/java/com/juick/util/ImageUtils.java @@ -44,135 +44,5 @@ import java.nio.file.StandardCopyOption; import java.util.Iterator; public class ImageUtils { - private static final Logger logger = LoggerFactory.getLogger(ImageUtils.class); - - private final String imgDir; - private final String tmpDir; - - public ImageUtils(String imgDir, String tmpDir) { - this.imgDir = imgDir; - this.tmpDir = tmpDir; - } -/** - * Returns BufferedImage, same as ImageIO.read() does. - * - *

JPEG images with EXIF metadata are rotated according to Orientation tag. - * - * @param imageFile a File to read from. - */ - private static BufferedImage readImageWithOrientation(File imageFile) - throws IOException { - - BufferedImage image = ImageIO.read(imageFile); - if (!FilenameUtils.getExtension(imageFile.getName()).equals("jpg")) { - return image; - } - - try { - ImageMetadata metadata = Imaging.getMetadata(imageFile); - - if (metadata instanceof JpegImageMetadata) { - JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata; - TiffField orientationField = jpegMetadata.findEXIFValue(TiffTagConstants.TIFF_TAG_ORIENTATION); - - if (orientationField != null) { - int orientation = orientationField.getIntValue(); - switch (orientation) { - case TiffTagConstants.ORIENTATION_VALUE_ROTATE_90_CW: - image = Scalr.rotate(image, Rotation.CW_90); - break; - case TiffTagConstants.ORIENTATION_VALUE_ROTATE_180: - image = Scalr.rotate(image, Rotation.CW_180); - break; - case TiffTagConstants.ORIENTATION_VALUE_ROTATE_270_CW: - image = Scalr.rotate(image, Rotation.CW_270); - break; - case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL: - image = Scalr.rotate(image, Rotation.FLIP_HORZ); - break; - case TiffTagConstants.ORIENTATION_VALUE_MIRROR_VERTICAL: - image = Scalr.rotate(image, Rotation.FLIP_VERT); - break; - case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_90_CW: - image = Scalr.rotate(Scalr.rotate(image, Rotation.FLIP_HORZ), Rotation.CW_90); - break; - case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_270_CW: - image = Scalr.rotate(Scalr.rotate(image, Rotation.FLIP_HORZ), Rotation.CW_270); - break; - case TiffTagConstants.ORIENTATION_VALUE_HORIZONTAL_NORMAL: - default: - // do nothing - break; - } - } - } - } catch (ImageReadException | IOException e) { - // failed to read metadata. - // nothing to do here, return image as is. - } - - return image; - } - - public void saveImageWithPreviews(String tempFilename, String outputFilename) - throws IOException { - String ext = FilenameUtils.getExtension(outputFilename); - - Path outputImagePath = Paths.get(imgDir, "p", outputFilename); - // this throws strange exceptions - // Files.move(Paths.get(tmpDir, tempFilename), outputImagePath); - FileUtils.moveFile(Paths.get(tmpDir, tempFilename).toFile(), outputImagePath.toFile()); - BufferedImage originalImage = readImageWithOrientation(outputImagePath.toFile()); - - int width = originalImage.getWidth(); - int height = originalImage.getHeight(); - int maxDimension = Math.max(width, height); - BufferedImage image1024 = (maxDimension > 1024) ? Scalr.resize(originalImage, 1024) : originalImage; - BufferedImage image0512 = (maxDimension > 512) ? Scalr.resize(originalImage, 512) : originalImage; - BufferedImage image0160 = (maxDimension > 160) ? Scalr.resize(originalImage, 160) : originalImage; - ImageIO.write(image1024, ext, Paths.get(imgDir, "photos-1024", outputFilename).toFile()); - ImageIO.write(image0512, ext, Paths.get(imgDir, "photos-512", outputFilename).toFile()); - ImageIO.write(image0160, ext, Paths.get(imgDir, "ps", outputFilename).toFile()); - } - - public void saveAvatar(String tempFilename, int uid) - throws IOException { - String ext = FilenameUtils.getExtension(tempFilename); - String originalName = String.format("%s.%s", uid, ext); - Path originalPath = Paths.get(imgDir, "ao", originalName); - Files.move(Paths.get(tmpDir, tempFilename), originalPath, StandardCopyOption.REPLACE_EXISTING); - BufferedImage originalImage = ImageIO.read(originalPath.toFile()); - - String targetExt = "png"; - String targetName = String.format("%s.%s", uid, targetExt); - ImageIO.write(Scalr.resize(originalImage, 96), targetExt, Paths.get(imgDir, "a", targetName).toFile()); - ImageIO.write(Scalr.resize(originalImage, 32), targetExt, Paths.get(imgDir, "as", targetName).toFile()); - } - public Attachment getAttachment(File imgFile) throws IOException { - Attachment attachment = new Attachment(); - if (imgFile.exists()) { - try (ImageInputStream stream = ImageIO.createImageInputStream(imgFile)) { - Iterator iter = ImageIO.getImageReaders(stream); - while (iter.hasNext()) { - ImageReader reader = iter.next(); - try { - reader.setInput(stream); - attachment.setWidth(reader.getWidth(reader.getMinIndex())); - attachment.setHeight(reader.getHeight(reader.getMinIndex())); - return attachment; - } catch (Exception e) { - logger.debug("Error reading {}, trying next reader", imgFile.getAbsolutePath()); - } finally { - reader.dispose(); - } - } - } - } else { - logger.warn("File not exists yet: {}", imgFile.getAbsolutePath()); - return attachment; - } - - logger.warn("Not a known image file {}", imgFile.getAbsolutePath()); - return attachment; - } + } \ No newline at end of file diff --git a/src/main/java/com/juick/www/WebApp.java b/src/main/java/com/juick/www/WebApp.java index 08f9fcd0..cebedb9b 100644 --- a/src/main/java/com/juick/www/WebApp.java +++ b/src/main/java/com/juick/www/WebApp.java @@ -16,26 +16,33 @@ */ package com.juick.www; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + import com.juick.model.Message; import com.juick.model.Tag; import com.juick.model.User; import com.juick.service.TagService; import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.template.PebbleTemplate; + import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.servlet.resource.ResourceUrlProvider; import org.springframework.web.util.UriComponentsBuilder; -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.*; -import java.util.stream.Stream; - /** * * @author Ugnich Anton @@ -97,6 +104,7 @@ public class WebApp { avatarBuilder.replacePath(getAvatarWebPath(user)); return avatarBuilder.build().toUriString(); } + public Optional renderPlaintext(String body, String messageUrl) { PebbleTemplate noteTemplate = pebbleEngine.getTemplate("email/plaintext"); Map context = new HashMap<>(); diff --git a/src/main/java/com/juick/www/rss/Feeds.java b/src/main/java/com/juick/www/rss/Feeds.java index 8b396fd2..4423b263 100644 --- a/src/main/java/com/juick/www/rss/Feeds.java +++ b/src/main/java/com/juick/www/rss/Feeds.java @@ -55,6 +55,7 @@ public class Feeds { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("messagesView"); modelAndView.addObject("user", user); + modelAndView.addObject("feedType", feedType.name()); modelAndView.addObject("messages", messagesService.getMessages(visitor, mids)); return modelAndView; } diff --git a/src/main/java/com/juick/www/rss/MessagesView.java b/src/main/java/com/juick/www/rss/MessagesView.java index 06a42420..54983273 100644 --- a/src/main/java/com/juick/www/rss/MessagesView.java +++ b/src/main/java/com/juick/www/rss/MessagesView.java @@ -17,8 +17,10 @@ package com.juick.www.rss; +import com.juick.model.Attachment; import com.juick.model.Message; import com.juick.model.User; +import com.juick.service.ImagesService; import com.juick.www.rss.extension.JuickModule; import com.juick.www.rss.extension.JuickModuleImpl; import com.juick.www.WebApp; @@ -44,6 +46,8 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; @@ -57,10 +61,12 @@ import java.util.stream.Collectors; */ public class MessagesView extends AbstractRssFeedView { - private static final Logger logger = LoggerFactory.getLogger(MessagesView.class); + private static final Logger logger = LoggerFactory.getLogger(Feeds.class); @Inject private WebApp webApp; + @Inject + private ImagesService imagesService; @PostConstruct public void init() { @@ -69,16 +75,16 @@ public class MessagesView extends AbstractRssFeedView { @SuppressWarnings("unchecked") @Override - protected List buildFeedItems(@Nonnull Map model, - @Nonnull HttpServletRequest request, - @Nonnull HttpServletResponse response) { - List msgs = (List)model.get("messages"); + protected List buildFeedItems(@Nonnull Map model, @Nonnull HttpServletRequest request, + @Nonnull HttpServletResponse response) { + List msgs = (List) model.get("messages"); return msgs.stream().map(this::createRssItem).collect(Collectors.toList()); } @Override protected void buildFeedMetadata(Map model, Channel feed, HttpServletRequest request) { Object userObj = model.get("user"); + String feedType = (String) model.get("feedType"); if (userObj != null) { User user = (User) userObj; feed.setDescription(String.format("The latest messages by @%s at Juick", user.getName())); @@ -86,12 +92,21 @@ public class MessagesView extends AbstractRssFeedView { feed.setTitle(title); String link = String.format("https://juick.com/%s/", user.getName()); feed.setLink(link); - Image rssImage = new Image(); - rssImage.setUrl(webApp.getAvatarUrl(user)); - rssImage.setTitle(title); - rssImage.setLink(link); - feed.setImage(rssImage); - String href = String.format("https://rss.juick.com/%s/blog", user.getName()); + try { + Image rssImage = new Image(); + rssImage.setUrl(webApp.getAvatarUrl(user)); + rssImage.setTitle(title); + rssImage.setLink(link); + Attachment avatar; + avatar = imagesService.getImageMetadata(rssImage.getUrl()); + rssImage.setHeight(avatar.getHeight()); + rssImage.setWidth(avatar.getWidth()); + feed.setImage(rssImage); + } catch (IOException e) { + logger.warn("Feed avatar not found for {}", user.getName()); + } + + String href = String.format("https://rss.juick.com/%s/%s", user.getName(), feedType); AtomLinkModule atomLinkModule = new AtomLinkModuleImpl(); Link atomLink = new Link(); atomLink.setHref(href); @@ -109,7 +124,6 @@ public class MessagesView extends AbstractRssFeedView { MediaModule mediaModule = new MediaModuleImpl(); feed.getModules().add(mediaModule); - } private Item createRssItem(Message msg) { @@ -120,7 +134,7 @@ public class MessagesView extends AbstractRssFeedView { String messageDescription = isCode ? MessageUtils.formatMessageCode(StringUtils.defaultString(msg.getText())) : MessageUtils.formatMessage(StringUtils.defaultString(msg.getText())); item.setLink(messageUrl); - //item.setGuid(messageUrl); + // item.setGuid(messageUrl); item.setTitle(messageTitle); Description description = new Description(); description.setType("text/html"); @@ -144,9 +158,9 @@ public class MessagesView extends AbstractRssFeedView { MediaContent mediaContent = new MediaContent(reference); mediaContent.setType(type); Metadata metadata = new Metadata(); - metadata.setThumbnail(new Thumbnail[]{new Thumbnail(new URI(msg.getPhoto().getThumbnail()))}); + metadata.setThumbnail(new Thumbnail[] { new Thumbnail(new URI(msg.getPhoto().getThumbnail())) }); module.setMetadata(metadata); - module.setMediaContents(new MediaContent[]{mediaContent}); + module.setMediaContents(new MediaContent[] { mediaContent }); item.getModules().add(module); } catch (URISyntaxException e) { logger.error("Invalid URI", e); diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java index aceed0b9..dc88cfbd 100644 --- a/src/test/java/com/juick/server/tests/ServerTests.java +++ b/src/test/java/com/juick/server/tests/ServerTests.java @@ -202,10 +202,8 @@ public class ServerTests { private ServerManager serverManager; @Inject private KeystoreManager keystoreManager; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; - @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String imgDir; + @Inject + private ImagesService imagesService; @Inject private PebbleEngine pebbleEngine; @Value("${ios_app_id:}") @@ -283,6 +281,7 @@ public class ServerTests { @BeforeEach public void setUp() throws Exception { + String imgDir = imagesService.getImageDirectory(); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "p")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512")); @@ -313,6 +312,7 @@ public class ServerTests { @AfterEach public void teardown() throws IOException { + String imgDir = imagesService.getImageDirectory(); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "p")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512")); @@ -761,6 +761,7 @@ public class ServerTests { @Test public void protocolTests() throws Exception { + String tmpDir = imagesService.getTemporaryDirectory(); User user = userService.createUser("me", "secret").orElseThrow(IllegalStateException::new); Tag yo = tagService.getTag("yo", true); Message msg = commandsManager @@ -1125,8 +1126,7 @@ public class ServerTests { @Test public void attachmentSizeTests() throws IOException { - ImageUtils imageUtils = new ImageUtils(StringUtils.EMPTY, StringUtils.EMPTY); - Attachment attachment = imageUtils.getAttachment(new File(invisiblePixel.getURI())); + Attachment attachment = imagesService.getImageMetadata(invisiblePixel.getURI().toASCIIString()); assertThat(attachment.getHeight(), is(1)); assertThat(attachment.getWidth(), is(1)); } @@ -1188,6 +1188,7 @@ public class ServerTests { @Test public void cmykJpegShouldBeProcessedCorrectly() throws Exception { + String imgDir = imagesService.getImageDirectory(); CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", cmykJpeg.getURI()); assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); int mid = postJpgCmyk.getNewMessage().get().getMid(); @@ -1203,6 +1204,7 @@ public class ServerTests { @Test public void JpegWithoutJfifShouldBeProcessedCorrectly() throws Exception { + String imgDir = imagesService.getImageDirectory(); CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", nojfif.getURI()); assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); int mid = postJpgCmyk.getNewMessage().get().getMid(); @@ -1218,6 +1220,8 @@ public class ServerTests { @Test public void JpegFromJuickUriShouldBeProcessedCorrectly() throws Exception { + String imgDir = imagesService.getImageDirectory(); + String tmpDir = imagesService.getTemporaryDirectory(); Path tmpFile = Paths.get(tmpDir, "2915104.jpg"); Files.copy(Paths.get(new ClassPathResource("2915104.jpg").getURI()), tmpFile, StandardCopyOption.REPLACE_EXISTING); @@ -1244,6 +1248,7 @@ public class ServerTests { @Test public void changeExtensionWhenReceiveFileWithWrongContentType() throws Exception { + String tmpDir = imagesService.getTemporaryDirectory(); Path pngOutput = Paths.get(tmpDir, "cmyk.png"); Files.deleteIfExists(pngOutput); Files.copy(Paths.get(cmykJpeg.getURI()), pngOutput); @@ -2038,6 +2043,7 @@ public class ServerTests { @Test public void changeProfileOverApi() throws Exception { + String imgDir = imagesService.getImageDirectory(); ClassPathResource defaultAvatar = new ClassPathResource("static/av-96.png"); String hash = DigestUtils.md5DigestAsHex(IOUtils.toByteArray(defaultAvatar.getInputStream())); assertThat(webApp.getAvatarUrl(userService.getUserByName(freefdName)), -- cgit v1.2.3