diff options
author | Vitaly Takmazov | 2021-10-23 08:09:05 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2021-10-23 08:10:06 +0300 |
commit | 4b96a9b2e71b7a67effdd55b26ca532ff849d0ef (patch) | |
tree | 597a9b268622a10b440f3b119c529e624b8fdb62 | |
parent | 6b31c254b5a7ab6735c625459ba7936d9b2851e6 (diff) |
ImagesService -> StorageService
img_path -> storage_path property
16 files changed, 217 insertions, 247 deletions
diff --git a/src/main/java/com/juick/CommandsManager.java b/src/main/java/com/juick/CommandsManager.java index e2a50444..6d315a7d 100644 --- a/src/main/java/com/juick/CommandsManager.java +++ b/src/main/java/com/juick/CommandsManager.java @@ -17,20 +17,44 @@ package com.juick; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.inject.Inject; + +import com.juick.model.CommandResult; import com.juick.model.Message; import com.juick.model.Tag; -import com.juick.model.User; -import com.juick.util.formatters.PlainTextFormatter; -import com.juick.model.CommandResult; import com.juick.model.TagStats; -import com.juick.www.api.SystemActivity; -import com.juick.util.annotation.UserCommand; -import com.juick.util.HttpUtils; -import com.juick.www.WebApp; -import com.juick.service.*; +import com.juick.model.User; +import com.juick.service.MessagesService; +import com.juick.service.PMQueriesService; +import com.juick.service.PrivacyQueriesService; +import com.juick.service.ShowQueriesService; +import com.juick.service.StorageService; +import com.juick.service.SubscriptionService; +import com.juick.service.TagService; +import com.juick.service.UserService; import com.juick.service.activities.DeleteMessageEvent; -import com.juick.service.component.*; +import com.juick.service.component.PingEvent; +import com.juick.service.component.SystemEvent; +import com.juick.util.HttpUtils; import com.juick.util.MessageUtils; +import com.juick.util.annotation.UserCommand; +import com.juick.util.formatters.PlainTextFormatter; +import com.juick.www.WebApp; +import com.juick.www.api.SystemActivity; + import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; @@ -39,19 +63,8 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; -import javax.annotation.Nonnull; -import javax.inject.Inject; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.URI; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - /** * * @author ugnich @@ -72,12 +85,10 @@ public class CommandsManager { private PrivacyQueriesService privacyQueriesService; @Inject private SubscriptionService subscriptionService; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; @Inject - private ApplicationEventPublisher applicationEventPublisher; + private StorageService storageService; @Inject - private ImagesService imagesService; + private ApplicationEventPublisher applicationEventPublisher; @Inject private WebApp webApp; @Inject @@ -125,7 +136,7 @@ public class CommandsManager { String attachmentType = null; if (haveAttachment) { attachmentFName = attachment.getScheme().equals("juick") ? attachment.getHost() - : HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost(); + : HttpUtils.downloadImage(attachment.toURL(), storageService.getTemporaryDirectory()).getHost(); attachmentType = attachmentFName.substring(attachmentFName.length() - 3); } if (StringUtils.isEmpty(body) && !haveAttachment) { @@ -134,7 +145,7 @@ public class CommandsManager { int mid = messagesService.createMessage(user.getUid(), body, attachmentType, tags.getRight()); if (haveAttachment) { String fname = String.format("%d.%s", mid, attachmentType); - imagesService.saveImageWithPreviews(attachmentFName, fname); + storageService.saveImageWithPreviews(attachmentFName, fname); } Message msg = messagesService.getMessage(mid).orElseThrow(IllegalStateException::new); msg.getUser().setAvatar(webApp.getAvatarUrl(msg.getUser())); @@ -548,7 +559,7 @@ public class CommandsManager { attachmentType = attachmentFName.substring(attachmentFName.length() - 3); } else { try { - attachmentFName = HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost(); + attachmentFName = HttpUtils.downloadImage(attachment.toURL(), storageService.getTemporaryDirectory()).getHost(); attachmentType = attachmentFName.substring(attachmentFName.length() - 3); } catch (IOException e) { logger.warn("Can not download {}", attachment.toURL()); @@ -561,7 +572,7 @@ public class CommandsManager { if (newrid > 0) { if (haveAttachment && attachmentProcessed) { String fname = String.format("%d-%d.%s", mid, newrid, attachmentType); - imagesService.saveImageWithPreviews(attachmentFName, fname); + storageService.saveImageWithPreviews(attachmentFName, fname); } applicationEventPublisher.publishEvent( new SystemEvent(this, SystemActivity.read(user, msg.get()))); diff --git a/src/main/java/com/juick/TelegramBotManager.java b/src/main/java/com/juick/TelegramBotManager.java index 33cac896..abed77fc 100644 --- a/src/main/java/com/juick/TelegramBotManager.java +++ b/src/main/java/com/juick/TelegramBotManager.java @@ -23,6 +23,7 @@ import com.juick.model.CommandResult; import com.juick.www.api.SystemActivity; import com.juick.util.HttpUtils; import com.juick.service.MessagesService; +import com.juick.service.StorageService; import com.juick.service.TelegramService; import com.juick.service.UserService; import com.juick.service.component.SystemEvent; @@ -91,8 +92,8 @@ public class TelegramBotManager implements NotificationListener { private CommandsManager commandsManager; @Inject private ApplicationEventPublisher applicationEventPublisher; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; + @Inject + private StorageService storageService; @Inject private User serviceUser; @@ -170,7 +171,7 @@ public class TelegramBotManager implements NotificationListener { logger.info("got file {}", response.file()); try { URL fileURL = new URL(bot.getFullFilePath(response.file())); - attachment = HttpUtils.downloadImage(fileURL, tmpDir); + attachment = HttpUtils.downloadImage(fileURL, storageService.getTemporaryDirectory()); } catch (Exception e) { logger.warn("attachment exception", e); } diff --git a/src/main/java/com/juick/XMPPManager.java b/src/main/java/com/juick/XMPPManager.java index b42b4b9f..be1f8fd6 100644 --- a/src/main/java/com/juick/XMPPManager.java +++ b/src/main/java/com/juick/XMPPManager.java @@ -25,6 +25,7 @@ import com.juick.www.WebApp; import com.juick.util.xmpp.iq.MessageQuery; import com.juick.service.MessagesService; import com.juick.service.PMQueriesService; +import com.juick.service.StorageService; import com.juick.service.UserService; import com.juick.service.component.*; import com.juick.util.MessageUtils; @@ -102,8 +103,8 @@ public class XMPPManager implements NotificationListener { private String componentHost; @Value("${xmpp_password:secret}") private String password; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; + @Inject + private StorageService storageService; @Value("classpath:juick.png") private Resource vCardImage; @@ -199,7 +200,7 @@ public class XMPPManager implements NotificationListener { DigestUtils.md5Hex(String.format("%s-%s", e.getInitiator().toString(), e.getSessionId()).getBytes()), attachmentExtension); if (allowedTypes.contains(attachmentExtension)) { - Path filePath = Paths.get(tmpDir, targetFilename); + Path filePath = Paths.get(storageService.getTemporaryDirectory(), targetFilename); FileTransfer ft = e.accept(filePath).get(); ft.addFileTransferStatusListener(st -> { logger.debug("{}: received {} of {}", e.getName(), st.getBytesTransferred(), e.getSize()); diff --git a/src/main/java/com/juick/config/StorageConfig.java b/src/main/java/com/juick/config/StorageConfig.java deleted file mode 100644 index d105ec72..00000000 --- a/src/main/java/com/juick/config/StorageConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008-2020, Juick - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package com.juick.config; - -import com.juick.service.ImagesService; -import com.juick.service.ImagesServiceImpl; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class StorageConfig { - - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; - @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String imgDir; - @Bean - public ImagesService imagesService() { - return new ImagesServiceImpl(imgDir, tmpDir); - } -} diff --git a/src/main/java/com/juick/config/WebConfig.java b/src/main/java/com/juick/config/WebConfig.java index fcc61b72..94f30bd5 100644 --- a/src/main/java/com/juick/config/WebConfig.java +++ b/src/main/java/com/juick/config/WebConfig.java @@ -20,6 +20,8 @@ package com.juick.config; import com.juick.*; import com.juick.model.User; import com.juick.service.HelpService; +import com.juick.service.StorageService; +import com.juick.service.FileSystemStorageService; import com.juick.service.UserService; import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.extension.FormatterExtension; @@ -64,8 +66,14 @@ import javax.inject.Inject; @EnableAsync(proxyTargetClass = true) @EnableScheduling public class WebConfig implements WebMvcConfigurer { - @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String imgDir; + @Value("${upload_tmp_dir:#{systemProperties['java.io.tmpdir']}}") + private String tmpDir; + @Value("${storage_path:#{systemProperties['java.io.tmpdir']}}") + private String baseDir; + @Bean + public StorageService storageService() { + return new FileSystemStorageService(baseDir, tmpDir); + } @Bean public CaffeineCacheManager cacheManager() { return new CaffeineCacheManager("help"); @@ -172,7 +180,7 @@ public class WebConfig implements WebMvcConfigurer { try { registry .addResourceHandler("/**", "/i/a/**") - .addResourceLocations("classpath:/static/", Paths.get(imgDir, "/a/").toUri().toURL().toString()) + .addResourceLocations("classpath:/static/", Paths.get(baseDir, "/i/a/").toUri().toURL().toString()) .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)) .resourceChain(false) .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**", "/i/a/**")); diff --git a/src/main/java/com/juick/service/ImagesServiceImpl.java b/src/main/java/com/juick/service/FileSystemStorageService.java index 6687a59b..021e5a9f 100644 --- a/src/main/java/com/juick/service/ImagesServiceImpl.java +++ b/src/main/java/com/juick/service/FileSystemStorageService.java @@ -17,9 +17,24 @@ package com.juick.service; +import java.awt.image.BufferedImage; +import java.io.File; +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; + import com.juick.model.Attachment; import com.juick.model.Message; import com.juick.model.Photo; +import com.juick.model.User; + import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.Imaging; import org.apache.commons.imaging.common.ImageMetadata; @@ -32,33 +47,29 @@ 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 { +public class FileSystemStorageService implements StorageService { - private static final Logger logger = LoggerFactory.getLogger(ImagesService.class); + private static final Logger logger = LoggerFactory.getLogger(StorageService.class); + private final String baseDir; private final String imgDir; private final String tmpDir; + private final String avatarDir, avatarSmallDir, avatarOriginalDir; + private final String fullImageDir, mediumImageDir, smallImageDir, thumbnailImageDir; - public ImagesServiceImpl(String imgDir, String tmpDir) { - this.imgDir = imgDir; + public FileSystemStorageService(String baseDir, String tmpDir) { + this.baseDir = baseDir; + this.imgDir = Paths.get(baseDir, "i").toString(); this.tmpDir = tmpDir; + this.avatarDir = Paths.get(imgDir, "a").toString(); + this.avatarOriginalDir = Paths.get(imgDir, "ao").toString(); + this.avatarSmallDir = Paths.get(imgDir, "as").toString(); + this.fullImageDir = Paths.get(imgDir, "p").toString(); + this.mediumImageDir = Paths.get(imgDir, "photos-1024").toString(); + this.smallImageDir = Paths.get(imgDir, "photos-512").toString(); + this.thumbnailImageDir = Paths.get(imgDir, "ps").toString(); } @Override @@ -82,10 +93,10 @@ public class ImagesServiceImpl implements ImagesService { if (msg.getRid() > 0) { imageName = String.format("%s-%s.%s", msg.getMid(), msg.getRid(), msg.getAttachmentType()); } - File fullImage = Paths.get(imgDir, "p", imageName).toFile(); - File mediumImage = Paths.get(imgDir, "photos-1024", imageName).toFile(); - File smallImage = Paths.get(imgDir, "photos-512", imageName).toFile(); - File thumbnailImage = Paths.get(imgDir, "ps", imageName).toFile(); + File fullImage = Paths.get(fullImageDir, imageName).toFile(); + File mediumImage = Paths.get(mediumImageDir, imageName).toFile(); + File smallImage = Paths.get(smallImageDir, imageName).toFile(); + File thumbnailImage = Paths.get(thumbnailImageDir, imageName).toFile(); StringBuilder builder = new StringBuilder(); builder.append(baseUrl); builder.append(msg.getAttachmentType().equals("mp4") ? "video" : "p"); @@ -115,11 +126,6 @@ public class ImagesServiceImpl implements ImagesService { } } - @Override - public Attachment getImageMetadata(String resourceLocation) throws FileNotFoundException, IOException { - return getAttachment(ResourceUtils.getFile(resourceLocation)); - } - /** * Returns <code>BufferedImage</code>, same as <code>ImageIO.read()</code> does. * @@ -185,7 +191,7 @@ public class ImagesServiceImpl implements ImagesService { public void saveImageWithPreviews(String tempFilename, String outputFilename) throws IOException { String ext = FilenameUtils.getExtension(outputFilename); - Path outputImagePath = Paths.get(imgDir, "p", outputFilename); + Path outputImagePath = Paths.get(fullImageDir, outputFilename); // this throws strange exceptions // Files.move(Paths.get(tmpDir, tempFilename), outputImagePath); FileUtils.moveFile(Paths.get(tmpDir, tempFilename).toFile(), outputImagePath.toFile()); @@ -197,22 +203,28 @@ public class ImagesServiceImpl implements ImagesService { 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()); + ImageIO.write(image1024, ext, Paths.get(mediumImageDir, outputFilename).toFile()); + ImageIO.write(image0512, ext, Paths.get(smallImageDir, outputFilename).toFile()); + ImageIO.write(image0160, ext, Paths.get(thumbnailImageDir, outputFilename).toFile()); } - public void saveAvatar(String tempFilename, int uid) throws IOException { + private String getAvatarFileName(User user, String targetExtension) { + return String.format("%s.%s", user.getUid(), targetExtension); + } + + private Path getAvatarPath(User user) { + return Paths.get(avatarDir, getAvatarFileName(user, "png")); + } + + public void saveAvatar(String tempFilename, User user) throws IOException { String ext = FilenameUtils.getExtension(tempFilename); - String originalName = String.format("%s.%s", uid, ext); - Path originalPath = Paths.get(imgDir, "ao", originalName); + String originalName = getAvatarFileName(user, ext); + Path originalPath = Paths.get(avatarOriginalDir, 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()); + ImageIO.write(Scalr.resize(originalImage, 96), targetExt, getAvatarPath(user).toFile()); + ImageIO.write(Scalr.resize(originalImage, 32), targetExt, Paths.get(avatarSmallDir, getAvatarFileName(user, targetExt)).toFile()); } public Attachment getAttachment(File imgFile) throws IOException { @@ -243,6 +255,15 @@ public class ImagesServiceImpl implements ImagesService { return attachment; } + public Attachment getAvatarMetadata(User user) throws IOException { + return getAttachment(getAvatarPath(user).toFile()); + } + + @Override + public String getBaseDirectory() { + return baseDir; + } + @Override public String getImageDirectory() { return imgDir; diff --git a/src/main/java/com/juick/service/MessagesServiceImpl.java b/src/main/java/com/juick/service/MessagesServiceImpl.java index b6a2edb7..a787779b 100644 --- a/src/main/java/com/juick/service/MessagesServiceImpl.java +++ b/src/main/java/com/juick/service/MessagesServiceImpl.java @@ -63,7 +63,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Inject private SearchService searchService; @Inject - private ImagesService imagesService; + private StorageService storageService; @Inject private WebApp webApp; @Value("${photos_url:https://i.juick.com/}") @@ -113,7 +113,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ msg.setUnread(rs.getBoolean(26)); if (StringUtils.isNotEmpty(msg.getAttachmentType())) { try { - imagesService.setAttachmentMetadata(baseImagesUrl, msg); + storageService.setAttachmentMetadata(baseImagesUrl, msg); } catch (Exception e) { logger.warn("exception reading images for mid {} rid {}", msg.getMid(), msg.getRid(), e); } @@ -434,7 +434,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ msg.setReplyToUri(URI.create(Optional.ofNullable(rs.getString(15)).orElse(StringUtils.EMPTY))); if (StringUtils.isNotEmpty(msg.getAttachmentType())) { try { - imagesService.setAttachmentMetadata(baseImagesUrl, msg); + storageService.setAttachmentMetadata(baseImagesUrl, msg); } catch (Exception e) { logger.warn("exception reading images for mid {} rid {}", msg.getMid(), msg.getRid(), e); } diff --git a/src/main/java/com/juick/service/ImagesService.java b/src/main/java/com/juick/service/StorageService.java index 0891dca9..f1f72a60 100644 --- a/src/main/java/com/juick/service/ImagesService.java +++ b/src/main/java/com/juick/service/StorageService.java @@ -17,13 +17,14 @@ package com.juick.service; +import java.io.File; +import java.io.IOException; + import com.juick.model.Attachment; import com.juick.model.Message; +import com.juick.model.User; -import java.io.FileNotFoundException; -import java.io.IOException; - -public interface ImagesService { +public interface StorageService { void setAttachmentMetadata(String baseUrl, Message msg) throws Exception; /** @@ -38,18 +39,17 @@ public interface ImagesService { * Save new avatar in all required sizes. * * @param tempFilename Name of the image file in the temp folder. - * @param uid User id that is used to build image file names. + * @param user User hat is used to build image file names. */ - void saveAvatar(String tempFilename, int uid) throws IOException; + void saveAvatar(String tempFilename, User user) throws IOException; + + public Attachment getAttachment(File imgFile) throws IOException; + + public Attachment getAvatarMetadata(User user) throws IOException; + + String getBaseDirectory(); 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/util/ImageUtils.java b/src/main/java/com/juick/util/ImageUtils.java deleted file mode 100644 index 6ba6882c..00000000 --- a/src/main/java/com/juick/util/ImageUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008-2020, Juick - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package com.juick.util; - -import com.juick.model.Attachment; -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 javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; -import java.awt.image.BufferedImage; -import java.io.File; -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; - -public class ImageUtils { - -}
\ 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 cebedb9b..85e21b1a 100644 --- a/src/main/java/com/juick/www/WebApp.java +++ b/src/main/java/com/juick/www/WebApp.java @@ -19,6 +19,7 @@ package com.juick.www; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -30,9 +31,11 @@ import java.util.stream.Stream; import javax.annotation.PostConstruct; import javax.inject.Inject; +import com.juick.model.Attachment; import com.juick.model.Message; import com.juick.model.Tag; import com.juick.model.User; +import com.juick.service.StorageService; import com.juick.service.TagService; import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.template.PebbleTemplate; @@ -50,6 +53,8 @@ import org.springframework.web.util.UriComponentsBuilder; @Component public class WebApp { @Inject + private StorageService storageService; + @Inject private TagService tagService; @Inject private ResourceUrlProvider resourceUrlProvider; diff --git a/src/main/java/com/juick/www/api/Post.java b/src/main/java/com/juick/www/api/Post.java index c993ebe3..bced92bf 100644 --- a/src/main/java/com/juick/www/api/Post.java +++ b/src/main/java/com/juick/www/api/Post.java @@ -17,38 +17,46 @@ package com.juick.www.api; +import java.net.URI; +import java.net.URL; +import java.util.List; +import java.util.Optional; + +import javax.inject.Inject; +import javax.validation.constraints.NotNull; + +import com.juick.ActivityPubManager; +import com.juick.CommandsManager; +import com.juick.model.CommandResult; import com.juick.model.Message; import com.juick.model.Reaction; import com.juick.model.Status; import com.juick.model.User; -import com.juick.model.CommandResult; -import com.juick.ActivityPubManager; -import com.juick.CommandsManager; -import com.juick.util.HttpBadRequestException; -import com.juick.util.HttpForbiddenException; -import com.juick.util.HttpNotFoundException; -import com.juick.util.HttpUtils; import com.juick.service.MessagesService; +import com.juick.service.StorageService; import com.juick.service.UserService; import com.juick.service.activities.UpdateEvent; import com.juick.service.security.annotation.Visitor; +import com.juick.util.HttpBadRequestException; +import com.juick.util.HttpForbiddenException; +import com.juick.util.HttpNotFoundException; +import com.juick.util.HttpUtils; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import javax.inject.Inject; -import javax.validation.constraints.NotNull; -import java.net.URI; -import java.net.URL; -import java.util.List; -import java.util.Optional; - /** * Created by vt on 24/11/2016. */ @@ -60,8 +68,8 @@ public class Post { private UserService userService; @Inject private MessagesService messagesService; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; + @Inject + private StorageService storageService; @Inject CommandsManager commandsManager; @Inject @@ -78,7 +86,7 @@ public class Post { @RequestParam(required = false) MultipartFile attach) throws Exception { body = body.replace("\r", StringUtils.EMPTY); - URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, tmpDir); + URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, storageService.getTemporaryDirectory()); if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { URI juickUri = URI.create(img); @@ -87,7 +95,7 @@ public class Post { } else { try { URL imgUrl = new URL(img); - attachmentFName = HttpUtils.downloadImage(imgUrl, tmpDir); + attachmentFName = HttpUtils.downloadImage(imgUrl, storageService.getTemporaryDirectory()); } catch (Exception e) { logger.error("DOWNLOAD ERROR", e); throw new HttpBadRequestException(); @@ -135,11 +143,11 @@ public class Post { throw new HttpForbiddenException(); } - URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, tmpDir); + URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, storageService.getTemporaryDirectory()); if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) { try { - attachmentFName = HttpUtils.downloadImage(new URL(img), tmpDir); + attachmentFName = HttpUtils.downloadImage(new URL(img), storageService.getTemporaryDirectory()); } catch (Exception e) { logger.error("DOWNLOAD ERROR", e); throw new HttpBadRequestException(); diff --git a/src/main/java/com/juick/www/api/Service.java b/src/main/java/com/juick/www/api/Service.java index fc0132b1..f7c7a4aa 100644 --- a/src/main/java/com/juick/www/api/Service.java +++ b/src/main/java/com/juick/www/api/Service.java @@ -27,6 +27,7 @@ import com.juick.util.HttpBadRequestException; import com.juick.util.HttpForbiddenException; import com.juick.service.EmailService; import com.juick.service.MessagesService; +import com.juick.service.StorageService; import com.juick.service.UserService; import com.juick.service.component.AccountVerificationEvent; import com.juick.service.security.annotation.Visitor; @@ -77,8 +78,8 @@ public class Service { private ApplicationEventPublisher applicationEventPublisher; @Inject private User serviceUser; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; + @Inject + private StorageService storageService; @Value("${banned_emails:}") private String[] ignoredEmails; @Inject @@ -139,7 +140,7 @@ public class Service { try { logger.info("got inputstream: {}", a.getInputStream()); FileOutputStream fos = new FileOutputStream( - Paths.get(tmpDir, attachmentFName[0]).toString()); + Paths.get(storageService.getTemporaryDirectory(), attachmentFName[0]).toString()); IOUtils.copy(a.getInputStream(), fos); fos.close(); } catch (IOException e) { diff --git a/src/main/java/com/juick/www/api/Users.java b/src/main/java/com/juick/www/api/Users.java index 0294ec53..49a4494f 100644 --- a/src/main/java/com/juick/www/api/Users.java +++ b/src/main/java/com/juick/www/api/Users.java @@ -63,9 +63,7 @@ public class Users { @Inject private WebApp webApp; @Inject - private ImagesService imagesService; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; + private StorageService storageService; @Inject private ApplicationEventPublisher applicationEventPublisher; @@ -168,9 +166,9 @@ public class Users { @PostMapping("/api/me/upload") public void updateInfo(@Visitor User visitor, @RequestParam MultipartFile avatar) throws IOException { - String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost(); + String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, storageService.getTemporaryDirectory()).getHost(); if (StringUtils.isNotEmpty(avatarTmpPath)) { - imagesService.saveAvatar(avatarTmpPath, visitor.getUid()); + storageService.saveAvatar(avatarTmpPath, visitor); applicationEventPublisher.publishEvent(new UpdateUserEvent(this, visitor)); } } diff --git a/src/main/java/com/juick/www/controllers/Settings.java b/src/main/java/com/juick/www/controllers/Settings.java index 50b4ea14..a5597735 100644 --- a/src/main/java/com/juick/www/controllers/Settings.java +++ b/src/main/java/com/juick/www/controllers/Settings.java @@ -63,8 +63,6 @@ import java.util.stream.IntStream; public class Settings { private static final Logger logger = LoggerFactory.getLogger(Settings.class); - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; @Inject private TagService tagService; @Inject @@ -76,7 +74,7 @@ public class Settings { @Inject private TelegramService telegramService; @Inject - private ImagesService imagesService; + private StorageService storageService; @Inject private WebApp webApp; @Inject @@ -166,9 +164,9 @@ public class Settings { visitor.setCountry(request.getParameter("country")); visitor.setUrl(request.getParameter("url")); visitor.setDescription(request.getParameter("descr")); - String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost(); + String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, storageService.getTemporaryDirectory()).getHost(); if (StringUtils.isNotEmpty(avatarTmpPath)) { - imagesService.saveAvatar(avatarTmpPath, visitor.getUid()); + storageService.saveAvatar(avatarTmpPath, visitor); } if (userService.updateUserInfo(visitor)) { result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getName()); diff --git a/src/main/java/com/juick/www/rss/MessagesView.java b/src/main/java/com/juick/www/rss/MessagesView.java index 6355c47d..2c7d4a7d 100644 --- a/src/main/java/com/juick/www/rss/MessagesView.java +++ b/src/main/java/com/juick/www/rss/MessagesView.java @@ -17,14 +17,29 @@ package com.juick.www.rss; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import com.juick.model.Attachment; import com.juick.model.Message; import com.juick.model.User; -import com.juick.service.ImagesService; +import com.juick.service.StorageService; +import com.juick.util.MessageUtils; +import com.juick.www.WebApp; import com.juick.www.rss.extension.JuickModule; import com.juick.www.rss.extension.JuickModuleImpl; -import com.juick.www.WebApp; -import com.juick.util.MessageUtils; import com.rometools.modules.atom.modules.AtomLinkModule; import com.rometools.modules.atom.modules.AtomLinkModuleImpl; import com.rometools.modules.mediarss.MediaEntryModuleImpl; @@ -47,21 +62,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.view.feed.AbstractRssFeedView; -import javax.annotation.Nonnull; -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; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - /** * Created by vitalyster on 13.12.2016. */ @@ -70,9 +70,9 @@ public class MessagesView extends AbstractRssFeedView { private static final Logger logger = LoggerFactory.getLogger(Feeds.class); @Inject - private WebApp webApp; + private StorageService storageService; @Inject - private ImagesService imagesService; + private WebApp webApp; @PostConstruct public void init() { @@ -99,12 +99,11 @@ public class MessagesView extends AbstractRssFeedView { String link = String.format("https://juick.com/%s/", user.getName()); feed.setLink(link); try { + Attachment avatar = storageService.getAvatarMetadata(user); 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); diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java index dc88cfbd..5aee3af8 100644 --- a/src/test/java/com/juick/server/tests/ServerTests.java +++ b/src/test/java/com/juick/server/tests/ServerTests.java @@ -132,6 +132,7 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -203,7 +204,7 @@ public class ServerTests { @Inject private KeystoreManager keystoreManager; @Inject - private ImagesService imagesService; + private StorageService storageService; @Inject private PebbleEngine pebbleEngine; @Value("${ios_app_id:}") @@ -281,7 +282,7 @@ public class ServerTests { @BeforeEach public void setUp() throws Exception { - String imgDir = imagesService.getImageDirectory(); + String imgDir = storageService.getImageDirectory(); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "p")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512")); @@ -312,7 +313,7 @@ public class ServerTests { @AfterEach public void teardown() throws IOException { - String imgDir = imagesService.getImageDirectory(); + String imgDir = storageService.getImageDirectory(); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "p")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024")); FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512")); @@ -761,7 +762,7 @@ public class ServerTests { @Test public void protocolTests() throws Exception { - String tmpDir = imagesService.getTemporaryDirectory(); + String tmpDir = storageService.getTemporaryDirectory(); User user = userService.createUser("me", "secret").orElseThrow(IllegalStateException::new); Tag yo = tagService.getTag("yo", true); Message msg = commandsManager @@ -1126,9 +1127,12 @@ public class ServerTests { @Test public void attachmentSizeTests() throws IOException { - Attachment attachment = imagesService.getImageMetadata(invisiblePixel.getURI().toASCIIString()); - assertThat(attachment.getHeight(), is(1)); - assertThat(attachment.getWidth(), is(1)); + String tmpPng = "tmp.png"; + Files.copy(defaultAvatar.getFile().toPath(), Paths.get(storageService.getTemporaryDirectory(), tmpPng), StandardCopyOption.REPLACE_EXISTING); + storageService.saveAvatar(tmpPng, serviceUser); + Attachment attachment = storageService.getAvatarMetadata(serviceUser); + assertThat(attachment.getHeight(), is(96)); + assertThat(attachment.getWidth(), is(96)); } @Test @@ -1188,7 +1192,7 @@ public class ServerTests { @Test public void cmykJpegShouldBeProcessedCorrectly() throws Exception { - String imgDir = imagesService.getImageDirectory(); + String imgDir = storageService.getImageDirectory(); CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", cmykJpeg.getURI()); assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); int mid = postJpgCmyk.getNewMessage().get().getMid(); @@ -1204,7 +1208,7 @@ public class ServerTests { @Test public void JpegWithoutJfifShouldBeProcessedCorrectly() throws Exception { - String imgDir = imagesService.getImageDirectory(); + String imgDir = storageService.getImageDirectory(); CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", nojfif.getURI()); assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); int mid = postJpgCmyk.getNewMessage().get().getMid(); @@ -1220,8 +1224,8 @@ public class ServerTests { @Test public void JpegFromJuickUriShouldBeProcessedCorrectly() throws Exception { - String imgDir = imagesService.getImageDirectory(); - String tmpDir = imagesService.getTemporaryDirectory(); + String imgDir = storageService.getImageDirectory(); + String tmpDir = storageService.getTemporaryDirectory(); Path tmpFile = Paths.get(tmpDir, "2915104.jpg"); Files.copy(Paths.get(new ClassPathResource("2915104.jpg").getURI()), tmpFile, StandardCopyOption.REPLACE_EXISTING); @@ -1248,7 +1252,7 @@ public class ServerTests { @Test public void changeExtensionWhenReceiveFileWithWrongContentType() throws Exception { - String tmpDir = imagesService.getTemporaryDirectory(); + String tmpDir = storageService.getTemporaryDirectory(); Path pngOutput = Paths.get(tmpDir, "cmyk.png"); Files.deleteIfExists(pngOutput); Files.copy(Paths.get(cmykJpeg.getURI()), pngOutput); @@ -2043,7 +2047,7 @@ public class ServerTests { @Test public void changeProfileOverApi() throws Exception { - String imgDir = imagesService.getImageDirectory(); + String imgDir = storageService.getImageDirectory(); ClassPathResource defaultAvatar = new ClassPathResource("static/av-96.png"); String hash = DigestUtils.md5DigestAsHex(IOUtils.toByteArray(defaultAvatar.getInputStream())); assertThat(webApp.getAvatarUrl(userService.getUserByName(freefdName)), |