diff --git a/README.md b/README.md
index 1e47bce..67aaff9 100644
--- a/README.md
+++ b/README.md
@@ -88,8 +88,9 @@ java -jar target/quickdrop-0.0.1-SNAPSHOT.jar
```
Using an external application.properties file:
- - Create an **application.properties** file in the same directory as the JAR file or specify its location in the
- start command.
+
+- Create an **application.properties** file in the same directory as the JAR file or specify its location in the
+ start command.
- Add your custom settings, for example (Listed below are the default values):
diff --git a/pom.xml b/pom.xml
index 8306494..2748451 100644
--- a/pom.xml
+++ b/pom.xml
@@ -185,6 +185,16 @@
test
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter
+ 4.1.3
+
+
diff --git a/src/main/java/org/rostislav/quickdrop/QuickdropApplication.java b/src/main/java/org/rostislav/quickdrop/QuickdropApplication.java
index 4a95011..7616e21 100644
--- a/src/main/java/org/rostislav/quickdrop/QuickdropApplication.java
+++ b/src/main/java/org/rostislav/quickdrop/QuickdropApplication.java
@@ -1,8 +1,5 @@
package org.rostislav.quickdrop;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,6 +8,9 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
@SpringBootApplication
@EnableScheduling
public class QuickdropApplication {
diff --git a/src/main/java/org/rostislav/quickdrop/config/MultipartConfig.java b/src/main/java/org/rostislav/quickdrop/config/MultipartConfig.java
index 6a61137..b075980 100644
--- a/src/main/java/org/rostislav/quickdrop/config/MultipartConfig.java
+++ b/src/main/java/org/rostislav/quickdrop/config/MultipartConfig.java
@@ -1,8 +1,9 @@
package org.rostislav.quickdrop.config;
import jakarta.servlet.MultipartConfigElement;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
@@ -10,16 +11,18 @@ import org.springframework.util.unit.DataSize;
@Configuration
public class MultipartConfig {
private final long ADDITIONAL_REQUEST_SIZE = 1024L * 1024L * 10L; // 10 MB
- @Value("${max-upload-file-size}")
- private String maxUploadFileSize;
+
+ @Autowired
+ private MultipartProperties multipartProperties;
@Bean
+ @RefreshScope
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
- factory.setMaxFileSize(DataSize.parse(maxUploadFileSize));
+ factory.setMaxFileSize(DataSize.parse(multipartProperties.getMaxFileSize()));
- DataSize maxRequestSize = DataSize.parse(maxUploadFileSize);
+ DataSize maxRequestSize = DataSize.parse(multipartProperties.getMaxFileSize());
maxRequestSize = DataSize.ofBytes(maxRequestSize.toBytes() + ADDITIONAL_REQUEST_SIZE);
factory.setMaxRequestSize(maxRequestSize);
diff --git a/src/main/java/org/rostislav/quickdrop/config/MultipartProperties.java b/src/main/java/org/rostislav/quickdrop/config/MultipartProperties.java
new file mode 100644
index 0000000..4aa4b4b
--- /dev/null
+++ b/src/main/java/org/rostislav/quickdrop/config/MultipartProperties.java
@@ -0,0 +1,19 @@
+package org.rostislav.quickdrop.config;
+
+import org.rostislav.quickdrop.repository.ApplicationSettingsRepository;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+@RefreshScope
+@Component
+public class MultipartProperties {
+ private final ApplicationSettingsRepository applicationSettingsRepository;
+
+ public MultipartProperties(ApplicationSettingsRepository applicationSettingsRepository) {
+ this.applicationSettingsRepository = applicationSettingsRepository;
+ }
+
+ public String getMaxFileSize() {
+ return "" + applicationSettingsRepository.findById(1L).orElseThrow().getMaxFileSize();
+ }
+}
diff --git a/src/main/java/org/rostislav/quickdrop/controller/AdminViewController.java b/src/main/java/org/rostislav/quickdrop/controller/AdminViewController.java
index 6d5c073..49bac78 100644
--- a/src/main/java/org/rostislav/quickdrop/controller/AdminViewController.java
+++ b/src/main/java/org/rostislav/quickdrop/controller/AdminViewController.java
@@ -28,9 +28,11 @@ public class AdminViewController {
@GetMapping("/settings")
public String getSettingsPage(Model model) {
ApplicationSettingsEntity settings = applicationSettingsService.getApplicationSettings();
- settings.setMaxFileSize(bytesToMegabytes(settings.getMaxFileSize()));
- model.addAttribute("settings", settings);
+ ApplicationSettingsEntity applicationSettingsEntity = new ApplicationSettingsEntity(settings);
+ applicationSettingsEntity.setMaxFileSize(bytesToMegabytes(settings.getMaxFileSize()));
+
+ model.addAttribute("settings", applicationSettingsEntity);
return "admin/settings";
}
diff --git a/src/main/java/org/rostislav/quickdrop/controller/FileViewController.java b/src/main/java/org/rostislav/quickdrop/controller/FileViewController.java
index fdde2c5..7e86a65 100644
--- a/src/main/java/org/rostislav/quickdrop/controller/FileViewController.java
+++ b/src/main/java/org/rostislav/quickdrop/controller/FileViewController.java
@@ -2,6 +2,7 @@ package org.rostislav.quickdrop.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.rostislav.quickdrop.model.FileEntity;
+import org.rostislav.quickdrop.service.ApplicationSettingsService;
import org.rostislav.quickdrop.service.FileService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
@@ -22,18 +23,18 @@ import static org.rostislav.quickdrop.util.FileUtils.populateModelAttributes;
@RequestMapping("/file")
public class FileViewController {
private final FileService fileService;
- @Value("${max-upload-file-size}")
- private String maxFileSize;
+ private final ApplicationSettingsService applicationSettingsService;
@Value("${file.max.age}")
private String maxFileLifeTime;
- public FileViewController(FileService fileService) {
+ public FileViewController(FileService fileService, ApplicationSettingsService applicationSettingsService) {
this.fileService = fileService;
+ this.applicationSettingsService = applicationSettingsService;
}
@GetMapping("/upload")
public String showUploadFile(Model model) {
- model.addAttribute("maxFileSize", maxFileSize);
+ model.addAttribute("maxFileSize", applicationSettingsService.getFormattedMaxFileSize());
model.addAttribute("maxFileLifeTime", maxFileLifeTime);
return "upload";
}
diff --git a/src/main/java/org/rostislav/quickdrop/model/ApplicationSettingsEntity.java b/src/main/java/org/rostislav/quickdrop/model/ApplicationSettingsEntity.java
index 319f47e..9d997c2 100644
--- a/src/main/java/org/rostislav/quickdrop/model/ApplicationSettingsEntity.java
+++ b/src/main/java/org/rostislav/quickdrop/model/ApplicationSettingsEntity.java
@@ -20,6 +20,21 @@ public class ApplicationSettingsEntity {
private String appPasswordHash;
private String adminPasswordHash;
+ public ApplicationSettingsEntity() {
+ }
+
+ public ApplicationSettingsEntity(ApplicationSettingsEntity settings) {
+ this.id = settings.id;
+ this.maxFileSize = settings.maxFileSize;
+ this.maxFileLifeTime = settings.maxFileLifeTime;
+ this.fileStoragePath = settings.fileStoragePath;
+ this.logStoragePath = settings.logStoragePath;
+ this.fileDeletionCron = settings.fileDeletionCron;
+ this.appPasswordEnabled = settings.appPasswordEnabled;
+ this.appPasswordHash = settings.appPasswordHash;
+ this.adminPasswordHash = settings.adminPasswordHash;
+ }
+
public long getMaxFileSize() {
return maxFileSize;
}
diff --git a/src/main/java/org/rostislav/quickdrop/model/FileEntity.java b/src/main/java/org/rostislav/quickdrop/model/FileEntity.java
index c11cef3..ab95497 100644
--- a/src/main/java/org/rostislav/quickdrop/model/FileEntity.java
+++ b/src/main/java/org/rostislav/quickdrop/model/FileEntity.java
@@ -1,12 +1,8 @@
package org.rostislav.quickdrop.model;
-import java.time.LocalDate;
+import jakarta.persistence.*;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.GenerationType;
-import jakarta.persistence.Id;
-import jakarta.persistence.PrePersist;
+import java.time.LocalDate;
@Entity
public class FileEntity {
diff --git a/src/main/java/org/rostislav/quickdrop/repository/FileRepository.java b/src/main/java/org/rostislav/quickdrop/repository/FileRepository.java
index 053a1fc..bd089d8 100644
--- a/src/main/java/org/rostislav/quickdrop/repository/FileRepository.java
+++ b/src/main/java/org/rostislav/quickdrop/repository/FileRepository.java
@@ -1,14 +1,14 @@
package org.rostislav.quickdrop.repository;
-import java.time.LocalDate;
-import java.util.List;
-import java.util.Optional;
-
import org.rostislav.quickdrop.model.FileEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+
public interface FileRepository extends JpaRepository {
@Query("SELECT f FROM FileEntity f WHERE f.uuid = :uuid")
Optional findByUUID(@Param("uuid") String uuid);
diff --git a/src/main/java/org/rostislav/quickdrop/service/ApplicationSettingsService.java b/src/main/java/org/rostislav/quickdrop/service/ApplicationSettingsService.java
index 6ab80cd..81842ef 100644
--- a/src/main/java/org/rostislav/quickdrop/service/ApplicationSettingsService.java
+++ b/src/main/java/org/rostislav/quickdrop/service/ApplicationSettingsService.java
@@ -2,17 +2,23 @@ package org.rostislav.quickdrop.service;
import org.rostislav.quickdrop.model.ApplicationSettingsEntity;
import org.rostislav.quickdrop.repository.ApplicationSettingsRepository;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Service;
+import static org.rostislav.quickdrop.util.FileUtils.formatFileSize;
+
@Service
public class ApplicationSettingsService {
private final ConfigurableApplicationContext applicationContext;
private final ApplicationSettingsRepository applicationSettingsRepository;
+ private final ContextRefresher contextRefresher;
private ApplicationSettingsEntity applicationSettings;
- public ApplicationSettingsService(ApplicationSettingsRepository applicationSettingsRepository, ApplicationContext applicationContext) {
+ public ApplicationSettingsService(ApplicationSettingsRepository applicationSettingsRepository, ApplicationContext applicationContext, @Qualifier("configDataContextRefresher") ContextRefresher contextRefresher) {
+ this.contextRefresher = contextRefresher;
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
this.applicationSettingsRepository = applicationSettingsRepository;
@@ -27,7 +33,6 @@ public class ApplicationSettingsService {
settings.setAppPasswordHash("");
settings.setAdminPasswordHash("");
settings = applicationSettingsRepository.save(settings);
- this.applicationContext.refresh();
return settings;
});
}
@@ -47,12 +52,18 @@ public class ApplicationSettingsService {
applicationSettingsRepository.save(applicationSettingsEntity);
+ this.applicationSettings = applicationSettingsEntity;
+ contextRefresher.refresh();
}
public long getMaxFileSize() {
return applicationSettings.getMaxFileSize();
}
+ public String getFormattedMaxFileSize() {
+ return formatFileSize(applicationSettings.getMaxFileSize());
+ }
+
public long getMaxFileLifeTime() {
return applicationSettings.getMaxFileLifeTime();
}
diff --git a/src/main/java/org/rostislav/quickdrop/service/FileService.java b/src/main/java/org/rostislav/quickdrop/service/FileService.java
index 95c2e6c..48c5791 100644
--- a/src/main/java/org/rostislav/quickdrop/service/FileService.java
+++ b/src/main/java/org/rostislav/quickdrop/service/FileService.java
@@ -33,11 +33,11 @@ import static org.rostislav.quickdrop.util.FileEncryptionUtils.encryptFile;
@Service
public class FileService {
- @Value("${file.save.path}")
- private String fileSavePath;
private static final Logger logger = LoggerFactory.getLogger(FileService.class);
private final FileRepository fileRepository;
private final PasswordEncoder passwordEncoder;
+ @Value("${file.save.path}")
+ private String fileSavePath;
public FileService(FileRepository fileRepository, PasswordEncoder passwordEncoder) {
this.fileRepository = fileRepository;
@@ -184,10 +184,10 @@ public class FileService {
Resource resource = new UrlResource(outputFile.toUri());
logger.info("Sending file: {}", fileEntity);
return ResponseEntity.ok()
- .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + URLEncoder.encode(fileEntity.name, StandardCharsets.UTF_8) + "\"")
- .header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
- .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(resource.contentLength()))
- .body(responseBody);
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + URLEncoder.encode(fileEntity.name, StandardCharsets.UTF_8) + "\"")
+ .header(HttpHeaders.CONTENT_TYPE, "application/octet-stream")
+ .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(resource.contentLength()))
+ .body(responseBody);
} catch (
Exception e) {
logger.error("Error reading file: {}", e.getMessage());
diff --git a/src/main/java/org/rostislav/quickdrop/service/ScheduleService.java b/src/main/java/org/rostislav/quickdrop/service/ScheduleService.java
index 14b1d2d..94c9352 100644
--- a/src/main/java/org/rostislav/quickdrop/service/ScheduleService.java
+++ b/src/main/java/org/rostislav/quickdrop/service/ScheduleService.java
@@ -1,8 +1,5 @@
package org.rostislav.quickdrop.service;
-import java.time.LocalDate;
-import java.util.List;
-
import org.rostislav.quickdrop.model.FileEntity;
import org.rostislav.quickdrop.repository.FileRepository;
import org.slf4j.Logger;
@@ -11,6 +8,9 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
+import java.time.LocalDate;
+import java.util.List;
+
@Service
public class ScheduleService {
private static final Logger logger = LoggerFactory.getLogger(ScheduleService.class);
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index ade4f5b..3f0f268 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -15,6 +15,5 @@ logging.file.name=log/quickdrop.log
file.deletion.cron=0 0 2 * * *
app.basic.password=test
app.enable.password=false
-max-upload-file-size=1GB
#logging.level.org.springframework=DEBUG
#logging.level.org.hibernate=DEBUG
\ No newline at end of file
diff --git a/src/test/java/org/rostislav/quickdrop/FileServiceTests.java b/src/test/java/org/rostislav/quickdrop/FileServiceTests.java
index 21fa544..43065da 100644
--- a/src/test/java/org/rostislav/quickdrop/FileServiceTests.java
+++ b/src/test/java/org/rostislav/quickdrop/FileServiceTests.java
@@ -1,9 +1,5 @@
package org.rostislav.quickdrop;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -20,46 +16,45 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.multipart.MultipartFile;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.rostislav.quickdrop.TestDataContainer.getEmptyFileUploadRequest;
-import static org.rostislav.quickdrop.TestDataContainer.getFileEntity;
-import static org.rostislav.quickdrop.TestDataContainer.getFileUploadRequest;
+import static org.rostislav.quickdrop.TestDataContainer.*;
@SpringBootTest
@ExtendWith(MockitoExtension.class)
public class FileServiceTests {
@Nested
class SaveFileTests {
- @Value("${file.save.path}")
- private String fileSavePath;
@Autowired
FileService fileService;
@MockBean
FileRepository fileRepository;
@MockBean
PasswordEncoder passwordEncoder;
+ @Value("${file.save.path}")
+ private String fileSavePath;
@AfterEach
void tearDown() {
//Delete the all files in the fileSavePath
try {
Files.walk(Path.of(fileSavePath))
- .filter(Files::isRegularFile)
- .forEach(file -> {
- try {
- Files.delete(file);
- } catch (
- IOException e) {
- e.printStackTrace();
- }
- });
+ .filter(Files::isRegularFile)
+ .forEach(file -> {
+ try {
+ Files.delete(file);
+ } catch (
+ IOException e) {
+ e.printStackTrace();
+ }
+ });
} catch (
IOException e) {
e.printStackTrace();
diff --git a/src/test/java/org/rostislav/quickdrop/TestDataContainer.java b/src/test/java/org/rostislav/quickdrop/TestDataContainer.java
index cbdffda..5ed08a2 100644
--- a/src/test/java/org/rostislav/quickdrop/TestDataContainer.java
+++ b/src/test/java/org/rostislav/quickdrop/TestDataContainer.java
@@ -1,10 +1,10 @@
package org.rostislav.quickdrop;
-import java.util.UUID;
-
import org.rostislav.quickdrop.model.FileEntity;
import org.rostislav.quickdrop.model.FileUploadRequest;
+import java.util.UUID;
+
public class TestDataContainer {
public static FileEntity getFileEntity() {
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index b1e6fc2..77b3b37 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -9,6 +9,8 @@ spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false
server.tomcat.connection-timeout=60000
+management.endpoint.refresh.enabled=true
+management.endpoints.web.exposure.include=refresh
file.save.path=files
file.max.age=30
logging.file.name=log/quickdrop.log