diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/BucketService.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/BucketService.java index b03aaa7cc..251bd3ae6 100644 --- a/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/BucketService.java +++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/BucketService.java @@ -8,6 +8,7 @@ import de.bund.digitalservice.ris.norms.utils.XmlMapper; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import lombok.extern.slf4j.Slf4j; @@ -51,8 +52,8 @@ public class BucketService PublishPrivateNormPort, DeletePublicNormPort, DeletePrivateNormPort, - DeleteAllPublicNormsPort, - DeleteAllPrivateNormsPort, + DeleteAllPublicDokumentePort, + DeleteAllPrivateDokumentePort, PublishChangelogsPort { @Value("${otc.obs.private.bucket-name}") @@ -103,13 +104,23 @@ public void deletePublicNorm(DeletePublicNormPort.Command command) throws Bucket } @Override - public void deleteAllPublicNorms() { - deleteAllExceptChangelog(publicS3Client, publicBucketName); + public void deleteAllPublicDokumente(DeleteAllPublicDokumentePort.Command command) { + deleteAllDokumenteLastModifiedBefore( + publicS3Client, + publicBucketName, + publicChangelog, + command.lastChangeBefore() + ); } @Override - public void deleteAllPrivateNorms() { - deleteAllExceptChangelog(privateS3Client, privateBucketName); + public void deleteAllPrivateDokumente(DeleteAllPrivateDokumentePort.Command command) { + deleteAllDokumenteLastModifiedBefore( + privateS3Client, + privateBucketName, + privateChangelog, + command.lastChangeBefore() + ); } @Override @@ -235,7 +246,8 @@ private void deleteFromBucket( } /** - * Deletes all objects in the specified S3 bucket, except for the changelog files, which are contained within the "changelogs" folder + * Deletes all Dokumente in the specified S3 bucket, (not the changelog files) which have not been changed since the + * given date. * The deletion process handles pagination automatically if there are more than 1,000 objects in the bucket. *
* AWS S3 allows a maximum of 1,000 keys to be processed per delete request. This method retrieves and deletes objects
@@ -244,10 +256,20 @@ private void deleteFromBucket(
*
* @param s3Client the S3 client used to interact with the S3 service
* @param bucketName the name of the S3 bucket where the objects are located
+ * @param lastChangeBefore Dokumente that have been changed since this date are ignored
*/
- private void deleteAllExceptChangelog(final S3Client s3Client, final String bucketName) {
+ private void deleteAllDokumenteLastModifiedBefore(
+ final S3Client s3Client,
+ final String bucketName,
+ Changelog changelog,
+ Instant lastChangeBefore
+ ) {
try {
- ListObjectsV2Request listRequest = ListObjectsV2Request.builder().bucket(bucketName).build();
+ ListObjectsV2Request listRequest = ListObjectsV2Request
+ .builder()
+ .bucket(bucketName)
+ .prefix("eli")
+ .build();
ListObjectsV2Response listResponse;
int objectsDeleted = 0;
do {
@@ -256,7 +278,10 @@ private void deleteAllExceptChangelog(final S3Client s3Client, final String buck
for (S3Object s3Object : listResponse.contents()) {
final String key = s3Object.key();
- if (!key.startsWith(Changelog.FOLDER + "/")) {
+ if (
+ !key.startsWith(Changelog.FOLDER + "/") &&
+ s3Object.lastModified().isBefore(lastChangeBefore)
+ ) {
objectsToDelete.add(ObjectIdentifier.builder().key(key).build());
}
}
@@ -268,6 +293,9 @@ private void deleteAllExceptChangelog(final S3Client s3Client, final String buck
.build();
s3Client.deleteObjects(deleteRequest);
objectsDeleted += objectsToDelete.size();
+ objectsToDelete.forEach(objectIdentifier ->
+ changelog.addContent(Changelog.DELETED, objectIdentifier.key())
+ );
}
listRequest =
@@ -278,7 +306,7 @@ private void deleteAllExceptChangelog(final S3Client s3Client, final String buck
throw new BucketException(
BucketException.Operation.DELETE,
bucketName,
- "All norms could not be deleted",
+ "All dokumente could not be deleted",
e
);
}
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/Changelog.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/Changelog.java
index 594d17b28..fa8a6bc86 100644
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/Changelog.java
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/Changelog.java
@@ -5,7 +5,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.file.Paths;
-import java.time.LocalDate;
+import java.time.Instant;
import java.util.*;
import lombok.Getter;
@@ -15,7 +15,7 @@
public class Changelog {
public static final String FOLDER = "changelogs";
- public static final String FILE_NAME_FORMAT = "changelog-%s.json";
+ public static final String FILE_NAME_FORMAT = "%s-norms.json";
public static final String CHANGED = "changed";
public static final String DELETED = "deleted";
@@ -27,7 +27,8 @@ public class Changelog {
private final String fileName;
public Changelog() {
- this.fileName = Paths.get(FOLDER, FILE_NAME_FORMAT.formatted(LocalDate.now())).toString();
+ this.fileName =
+ Paths.get(FOLDER, FILE_NAME_FORMAT.formatted(Instant.now().toString())).toString();
}
/**
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/S3MockClient.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/S3MockClient.java
index 9af7ceb26..959cb485e 100644
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/S3MockClient.java
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/adapter/output/s3/S3MockClient.java
@@ -3,6 +3,7 @@
import jakarta.annotation.PostConstruct;
import java.io.*;
import java.nio.file.*;
+import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
@@ -73,7 +74,11 @@ public ListObjectsV2Response listObjectsV2(ListObjectsV2Request listObjectsV2Req
// If the file is not under 'eli', return only the file name
key = path.getFileName().toString();
}
- return S3Object.builder().key(key).build();
+ return S3Object
+ .builder()
+ .key(key)
+ .lastModified(Instant.ofEpochMilli(path.toFile().lastModified()))
+ .build();
})
.toList();
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPrivateDokumentePort.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPrivateDokumentePort.java
new file mode 100644
index 000000000..52d55a50a
--- /dev/null
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPrivateDokumentePort.java
@@ -0,0 +1,25 @@
+package de.bund.digitalservice.ris.norms.application.port.output;
+
+import de.bund.digitalservice.ris.norms.domain.entity.Dokument;
+import java.time.Instant;
+
+/**
+ * Interface representing the output port for deleting multiple {@link Dokument} entities from a storage location designated
+ * for private data.
+ */
+public interface DeleteAllPrivateDokumentePort {
+ /**
+ * Deletes all {@link Dokument} entities that have not been edited since the given date from a designated private
+ * storage location.
+ *
+ * @param command command for deleting Dokumente
+ */
+ void deleteAllPrivateDokumente(DeleteAllPrivateDokumentePort.Command command);
+
+ /**
+ * Command for deleting dokumente
+ *
+ * @param lastChangeBefore Dokumente last edited after the given date are not deleted.
+ */
+ record Command(Instant lastChangeBefore) {}
+}
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPrivateNormsPort.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPrivateNormsPort.java
deleted file mode 100644
index 8c154d416..000000000
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPrivateNormsPort.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package de.bund.digitalservice.ris.norms.application.port.output;
-
-import de.bund.digitalservice.ris.norms.domain.entity.Norm;
-
-/**
- * Interface representing the output port for deleting multiple {@link Norm} entities from a storage location designated
- * for private data.
- */
-public interface DeleteAllPrivateNormsPort {
- /**
- * Deletes the specified {@link Norm} entities from a designated private storage location.
- *
- */
- void deleteAllPrivateNorms();
-}
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPublicDokumentePort.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPublicDokumentePort.java
new file mode 100644
index 000000000..6b347f724
--- /dev/null
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPublicDokumentePort.java
@@ -0,0 +1,25 @@
+package de.bund.digitalservice.ris.norms.application.port.output;
+
+import de.bund.digitalservice.ris.norms.domain.entity.Dokument;
+import java.time.Instant;
+
+/**
+ * Interface representing the output port for deleting all {@link Dokument} entities from a storage location designated
+ * for public data.
+ */
+public interface DeleteAllPublicDokumentePort {
+ /**
+ * Deletes all {@link Dokument} entities that have not been edited since the given date from a designated public
+ * storage location.
+ *
+ * @param command command for deleting Dokumente
+ */
+ void deleteAllPublicDokumente(DeleteAllPublicDokumentePort.Command command);
+
+ /**
+ * Command for deleting dokumente
+ *
+ * @param lastChangeBefore Dokumente last edited after the given date are not deleted.
+ */
+ record Command(Instant lastChangeBefore) {}
+}
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPublicNormsPort.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPublicNormsPort.java
deleted file mode 100644
index dd150e450..000000000
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/port/output/DeleteAllPublicNormsPort.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package de.bund.digitalservice.ris.norms.application.port.output;
-
-import de.bund.digitalservice.ris.norms.domain.entity.Norm;
-
-/**
- * Interface representing the output port for deleting all {@link Norm} entities from a storage location designated
- * for public data.
- */
-public interface DeleteAllPublicNormsPort {
- /**
- * Deletes all {@link Norm} entities from a designated public storage location.
- */
- void deleteAllPublicNorms();
-}
diff --git a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PublishService.java b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PublishService.java
index c3a43eaca..79d5d181b 100644
--- a/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PublishService.java
+++ b/backend/src/main/java/de/bund/digitalservice/ris/norms/application/service/PublishService.java
@@ -7,6 +7,7 @@
import de.bund.digitalservice.ris.norms.domain.entity.eli.NormManifestationEli;
import de.bund.digitalservice.ris.norms.utils.NodeParser;
import de.bund.digitalservice.ris.norms.utils.exceptions.StorageException;
+import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
@@ -33,8 +34,8 @@ public class PublishService implements PublishNormUseCase {
private final DeletePublicNormPort deletePublicNormPort;
private final DeletePrivateNormPort deletePrivateNormPort;
private final LoadLastMigrationLogPort loadLastMigrationLogPort;
- private final DeleteAllPublicNormsPort deleteAllPublicNormsPort;
- private final DeleteAllPrivateNormsPort deleteAllPrivateNormsPort;
+ private final DeleteAllPublicDokumentePort deleteAllPublicDokumentePort;
+ private final DeleteAllPrivateDokumentePort deleteAllPrivateDokumentePort;
private final PublishChangelogsPort publishChangelogsPort;
public PublishService(
@@ -46,8 +47,8 @@ public PublishService(
DeletePublicNormPort deletePublicNormPort,
DeletePrivateNormPort deletePrivateNormPort,
LoadLastMigrationLogPort loadLastMigrationLogPort,
- DeleteAllPublicNormsPort deleteAllPublicNormsPort,
- DeleteAllPrivateNormsPort deleteAllPrivateNormsPort,
+ DeleteAllPublicDokumentePort deleteAllPublicDokumentePort,
+ DeleteAllPrivateDokumentePort deleteAllPrivateDokumentePort,
PublishChangelogsPort publishChangelogsPort
) {
this.loadNormManifestationElisByPublishStatePort = loadNormManifestationElisByPublishStatePort;
@@ -58,13 +59,32 @@ public PublishService(
this.deletePublicNormPort = deletePublicNormPort;
this.deletePrivateNormPort = deletePrivateNormPort;
this.loadLastMigrationLogPort = loadLastMigrationLogPort;
- this.deleteAllPublicNormsPort = deleteAllPublicNormsPort;
- this.deleteAllPrivateNormsPort = deleteAllPrivateNormsPort;
+ this.deleteAllPublicDokumentePort = deleteAllPublicDokumentePort;
+ this.deleteAllPrivateDokumentePort = deleteAllPrivateDokumentePort;
this.publishChangelogsPort = publishChangelogsPort;
}
@Override
public void processQueuedFilesForPublish() {
+ final Instant startOfProcessing = Instant.now();
+ final LocalDate today = startOfProcessing.atZone(ZoneId.systemDefault()).toLocalDate();
+
+ List