aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/juick/CommandsManager.java67
-rw-r--r--src/main/java/com/juick/TelegramBotManager.java7
-rw-r--r--src/main/java/com/juick/XMPPManager.java7
-rw-r--r--src/main/java/com/juick/config/StorageConfig.java37
-rw-r--r--src/main/java/com/juick/config/WebConfig.java14
-rw-r--r--src/main/java/com/juick/service/FileSystemStorageService.java (renamed from src/main/java/com/juick/service/ImagesServiceImpl.java)99
-rw-r--r--src/main/java/com/juick/service/MessagesServiceImpl.java6
-rw-r--r--src/main/java/com/juick/service/StorageService.java (renamed from src/main/java/com/juick/service/ImagesService.java)26
-rw-r--r--src/main/java/com/juick/util/ImageUtils.java48
-rw-r--r--src/main/java/com/juick/www/WebApp.java5
-rw-r--r--src/main/java/com/juick/www/api/Post.java52
-rw-r--r--src/main/java/com/juick/www/api/Service.java7
-rw-r--r--src/main/java/com/juick/www/api/Users.java8
-rw-r--r--src/main/java/com/juick/www/controllers/Settings.java8
-rw-r--r--src/main/java/com/juick/www/rss/MessagesView.java43
-rw-r--r--src/test/java/com/juick/server/tests/ServerTests.java30
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)),