Merge branch 'master' into develop

# Conflicts:
#	backend/pom.xml
This commit is contained in:
Zaripov Emil 2024-11-08 13:25:25 +03:00
commit 6c99aa07e1
9 changed files with 135 additions and 29 deletions

View file

@ -245,8 +245,8 @@
<artifactId>log4j-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<groupId>com.github.lookfirst</groupId>
<artifactId>sardine</artifactId>
</dependency>
</dependencies>
<build>

View file

@ -10,7 +10,14 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import com.github.sardine.DavResource;
import com.github.sardine.Sardine;
import com.github.sardine.SardineFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@ -36,32 +43,29 @@ public class WebDavClient {
@Value("${file.webdav.upload.password}")
private String password;
@Retryable(value = {IOException.class, InterruptedException.class}, backoff = @Backoff(delay = 500L))
public boolean webDavUploadFile(String url, MultipartFile multipartFile) {
@Retryable(value = {IOException.class}, backoff = @Backoff(delayExpression = "${webdav.retry.delay:500}"))
public boolean uploadFile(String url, MultipartFile multipartFile) {
Sardine sardine = initClient(username, password);
try {
HttpClient httpClient = HttpClient.newBuilder()
.authenticator(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
})
.build();
HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create(url))
.PUT(HttpRequest.BodyPublishers.ofByteArray(multipartFile.getBytes())).build();
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
logger.debug("Response status code: {}", response.statusCode());
return (response.statusCode() >= 200) && (response.statusCode() <= 202);
sardine.put(url, multipartFile.getBytes());
return sardine.exists(url);
}
catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
catch (IOException e) {
throw new RuntimeException("Failed to put or check file in WebDAV", e);
}
finally {
try {
sardine.shutdown();
}
catch (IOException e) {
logger.error("Failed to shutdown WebDAV client", e);
}
}
}
@Retryable(value = {IOException.class, InterruptedException.class},
backoff = @Backoff(delay = 500L))
backoff = @Backoff(delayExpression = "${webdav.retry.delay:500}"))
public ResponseEntity<Resource> webDavDownloadFile(String url) {
try {
HttpClient httpClient = HttpClient.newBuilder()
@ -103,4 +107,55 @@ public class WebDavClient {
String path = URI.create(url).getPath();
return path.substring(path.lastIndexOf('/') + 1);
}
@Retryable(value = {IOException.class}, backoff = @Backoff(delayExpression = "${webdav.retry.delay:500}"))
public void deleteFilesOlderThan(long seconds, String url, String username, String password,
String... extensions) {
Sardine sardine = initClient(username, password);
try {
List<DavResource> resources = sardine.list(url);
resources.stream().filter(getPredicate(extensions))
.forEach(davResource -> {
long age = System.currentTimeMillis() - davResource.getModified().getTime();
if (age > seconds * 1000) {
try {
sardine.delete(url + davResource.getPath());
}
catch (IOException e) {
throw new RuntimeException("Failed to delete file " + davResource.getName(), e);
}
}
});
}
catch (IOException e) {
throw new RuntimeException("Failed to delete old files from WebDAV", e);
}
finally {
try {
sardine.shutdown();
}
catch (IOException e) {
logger.error("Failed to shutdown WebDAV client", e);
}
}
}
private Sardine initClient(String username, String password) {
return SardineFactory.begin(username, password);
}
private Predicate<DavResource> getPredicate(String... extensions) {
if (extensions.length == 0) {
return davResource -> true;
}
return davResource -> {
AtomicBoolean condition = new AtomicBoolean(false);
Arrays.stream(extensions).forEach(extension -> condition.set(
condition.get() || davResource.getName().endsWith(extension)));
return condition.get();
};
}
}

View file

@ -43,7 +43,7 @@ public class EmployeeInfoFileUploadService {
private static final Logger logger = LoggerFactory.getLogger(EmployeeInfoFileUploadService.class);
private static final String FORMAT = "dd.MM.yyyy HH:mm:ss";
private final WebDavClient fileWebDavUploadClient;
private final WebDavClient webDavClient;
private final EmployeeInfoKafkaMessageService employeeInfoKafkaMessageService;
private final KafkaTemplate<String, String> kafkaTemplate;
private final InteractionService interactionService;
@ -56,12 +56,12 @@ public class EmployeeInfoFileUploadService {
private String url;
public EmployeeInfoFileUploadService(
WebDavClient fileWebDavUploadClient,
WebDavClient webDavClient,
EmployeeInfoKafkaMessageService employeeInfoKafkaMessageService,
@Qualifier("avTemplate") KafkaTemplate<String, String> kafkaTemplate,
InteractionService interactionService,
UlDataService ulDataService, JwtTokenService jwtTokenService) {
this.fileWebDavUploadClient = fileWebDavUploadClient;
this.webDavClient = webDavClient;
this.employeeInfoKafkaMessageService = employeeInfoKafkaMessageService;
this.kafkaTemplate = kafkaTemplate;
this.interactionService = interactionService;
@ -73,7 +73,7 @@ public class EmployeeInfoFileUploadService {
String fileUploadUrl = this.url + "/" + getNewFilename(multipartFile.getOriginalFilename());
LocalDateTime now = LocalDateTime.now();
if (this.fileWebDavUploadClient.webDavUploadFile(fileUploadUrl, multipartFile)) {
if (this.webDavClient.uploadFile(fileUploadUrl, multipartFile)) {
FileStatus fileStatus = new FileStatus();
fileStatus.setStatus("Загрузка.");
fileStatus.setCode("01");

View file

@ -1,4 +1,4 @@
package ervu.service.scheduer;
package ervu.service.scheduler;
/**
* @author Artyom Hackimullin

View file

@ -1,4 +1,4 @@
package ervu.service.scheduer;
package ervu.service.scheduler;
import java.util.Arrays;
import java.util.List;

View file

@ -0,0 +1,37 @@
package ervu.service.scheduler;
import ervu.client.fileupload.WebDavClient;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
/**
* @author gulnaz
*/
@Service
public class WebDavSchedulerService {
private final WebDavClient webDavClient;
@Value("${file.webdav.upload.url}")
private String url;
@Value("${file.webdav.upload.username}")
private String username;
@Value("${file.webdav.upload.password}")
private String password;
@Value("${file.webdav.lifetime.seconds:300}")
private long fileLifetime;
@Value("${file.webdav.extensions:}")
private String[] fileExtensions;
public WebDavSchedulerService(WebDavClient webDavClient) {
this.webDavClient = webDavClient;
}
@Scheduled(cron = "${webdav.cleanup.cron:0 0 0 * * *}")
@SchedulerLock
public void deleteOldFiles() {
webDavClient.deleteFilesOlderThan(fileLifetime, url, username, password, fileExtensions);
}
}

View file

@ -49,4 +49,9 @@ ERVU_FILE_UPLOAD_MAX_REQUEST_SIZE=6291456
ERVU_FILE_UPLOAD_FILE_SIZE_THRESHOLD=0
ESIA_TOKEN_CLEAR_CRON=0 0 */1 * * *
COOKIE_PATH=/ul
COOKIE_PATH=/ul
WEBDAV_CLEANUP_CRON=0 0 0 * * *
WEBDAV_RETRY_DELAY=500
FILE_WEBDAV_LIFETIME_SECONDS=300
FILE_WEBDAV_EXTENSIONS=csv,xlsx

View file

@ -93,6 +93,10 @@
<property name="av.kafka.download.response" value="ervu.lkrp.av-fileupload-status"/>
<property name="esia.token.clear.cron" value="0 0 */1 * * *"/>
<property name="esia.upload.data.role" value="MNSV89_UPLOAD_DATA"/>
<property name="webdav.cleanup.cron" value="0 0 0 * * *"/>
<property name="webdav.retry.delay" value="500"/>
<property name="file.webdav.lifetime.seconds" value="300"/>
<property name="file.webdav.extensions" value="csv,xlsx"/>
</system-properties>
<management>
<audit-log>

View file

@ -387,6 +387,11 @@
<artifactId>log4j-web</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>com.github.lookfirst</groupId>
<artifactId>sardine</artifactId>
<version>5.12</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>