You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/05/24 07:18:47 UTC
[james-project] 03/06: JAMES-3909 Task for delete user data
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 6d3443116e22d44cc789a5228a3b1772b2c9a187
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Thu May 18 15:10:37 2023 +0700
JAMES-3909 Task for delete user data
Simple task wrapper around the service
Co-authored-by: Benoit Tellier <bt...@linagora.com>
---
.../james/webadmin/service/DeleteUserDataTask.java | 108 ++++++++++++++++
...DeleteUserDataTaskAdditionalInformationDTO.java | 98 +++++++++++++++
.../webadmin/service/DeleteUserDataTaskDTO.java | 78 ++++++++++++
.../DeleteUserDataTaskSerializationTest.java | 136 +++++++++++++++++++++
4 files changed, 420 insertions(+)
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTask.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTask.java
new file mode 100644
index 0000000000..2f068eb418
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTask.java
@@ -0,0 +1,108 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.webadmin.service;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.james.core.Username;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskExecutionDetails;
+import org.apache.james.task.TaskType;
+import org.apache.james.user.api.DeleteUserDataTaskStep.StepName;
+
+import reactor.core.publisher.Mono;
+
+public class DeleteUserDataTask implements Task {
+ static final TaskType TYPE = TaskType.of("DeleteUserDataTask");
+
+ public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
+ private final Instant timestamp;
+ private final Username username;
+ private final Map<StepName, DeleteUserDataService.StepState> status;
+ private final Optional<StepName> fromStep;
+
+ public AdditionalInformation(Instant timestamp, Username username, Map<StepName, DeleteUserDataService.StepState> status, Optional<StepName> fromStep) {
+ this.timestamp = timestamp;
+ this.username = username;
+ this.status = status;
+ this.fromStep = fromStep;
+ }
+
+ public Optional<StepName> getFromStep() {
+ return fromStep;
+ }
+
+ public Username getUsername() {
+ return username;
+ }
+
+ public Map<StepName, DeleteUserDataService.StepState> getStatus() {
+ return status;
+ }
+
+ @Override
+ public Instant timestamp() {
+ return timestamp;
+ }
+ }
+
+ private final Username username;
+ private final DeleteUserDataService.Performer performer;
+ private final Optional<StepName> fromStep;
+
+ public DeleteUserDataTask(DeleteUserDataService service, Username username, Optional<StepName> fromStep) {
+ this.username = username;
+ this.performer = service.performer(fromStep);
+ this.fromStep = fromStep;
+ }
+
+
+ @Override
+ public Result run() {
+ return performer.deleteUserData(username)
+ .thenReturn(Result.COMPLETED)
+ .onErrorResume(e -> {
+ LOGGER.error("Error while deleting data of the user {}", username.asString(), e);
+ return Mono.just(Result.PARTIAL);
+ })
+ .block();
+ }
+
+ @Override
+ public TaskType type() {
+ return TYPE;
+ }
+
+ @Override
+ public Optional<TaskExecutionDetails.AdditionalInformation> details() {
+ return Optional.of(new AdditionalInformation(Clock.systemUTC().instant(), username, performer.getStatus().getStates(), fromStep));
+ }
+
+ public Username getUsername() {
+ return username;
+ }
+
+ public Optional<StepName> getFromStep() {
+ return fromStep;
+ }
+}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTaskAdditionalInformationDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTaskAdditionalInformationDTO.java
new file mode 100644
index 0000000000..491acbd0eb
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTaskAdditionalInformationDTO.java
@@ -0,0 +1,98 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.webadmin.service;
+
+import java.time.Instant;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.james.core.Username;
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
+import org.apache.james.user.api.DeleteUserDataTaskStep.StepName;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableMap;
+
+public class DeleteUserDataTaskAdditionalInformationDTO implements AdditionalInformationDTO {
+ public static AdditionalInformationDTOModule<DeleteUserDataTask.AdditionalInformation, DeleteUserDataTaskAdditionalInformationDTO> module() {
+ return DTOModule.forDomainObject(DeleteUserDataTask.AdditionalInformation.class)
+ .convertToDTO(DeleteUserDataTaskAdditionalInformationDTO.class)
+ .toDomainObjectConverter(dto -> new DeleteUserDataTask.AdditionalInformation(
+ dto.timestamp,
+ Username.of(dto.username),
+ dto.status.entrySet().stream()
+ .collect(ImmutableMap.toImmutableMap(
+ entry -> new StepName(entry.getKey()),
+ entry -> DeleteUserDataService.StepState.valueOf(entry.getValue()))),
+ dto.fromStep.map(StepName::new)))
+ .toDTOConverter((details, type) -> new DeleteUserDataTaskAdditionalInformationDTO(
+ type,
+ details.getUsername().asString(),
+ details.getStatus().entrySet().stream()
+ .collect(ImmutableMap.toImmutableMap(
+ entry -> entry.getKey().asString(),
+ entry -> entry.getValue().toString())),
+ details.getFromStep().map(StepName::asString),
+ details.timestamp()))
+ .typeName(DeleteUserDataTask.TYPE.asString())
+ .withFactory(AdditionalInformationDTOModule::new);
+ }
+
+ private final String type;
+ private final String username;
+ private final Map<String, String> status;
+ private final Optional<String> fromStep;
+ private final Instant timestamp;
+
+ public DeleteUserDataTaskAdditionalInformationDTO(@JsonProperty("type") String type,
+ @JsonProperty("username") String username,
+ @JsonProperty("status") Map<String, String> status,
+ @JsonProperty("fromStep") Optional<String> fromStep,
+ @JsonProperty("timestamp") Instant timestamp) {
+ this.type = type;
+ this.username = username;
+ this.status = status;
+ this.timestamp = timestamp;
+ this.fromStep = fromStep;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public Map<String, String> getStatus() {
+ return status;
+ }
+
+ public Instant getTimestamp() {
+ return timestamp;
+ }
+
+ public Optional<String> getFromStep() {
+ return fromStep;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTaskDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTaskDTO.java
new file mode 100644
index 0000000000..93e28db9a3
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUserDataTaskDTO.java
@@ -0,0 +1,78 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.webadmin.service;
+
+import java.util.Optional;
+
+import org.apache.james.core.Username;
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.TaskDTO;
+import org.apache.james.server.task.json.dto.TaskDTOModule;
+import org.apache.james.user.api.DeleteUserDataTaskStep.StepName;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class DeleteUserDataTaskDTO implements TaskDTO {
+
+ public static TaskDTOModule<DeleteUserDataTask, DeleteUserDataTaskDTO> module(DeleteUserDataService service) {
+ return DTOModule
+ .forDomainObject(DeleteUserDataTask.class)
+ .convertToDTO(DeleteUserDataTaskDTO.class)
+ .toDomainObjectConverter(dto -> dto.fromDTO(service))
+ .toDTOConverter(DeleteUserDataTaskDTO::toDTO)
+ .typeName(DeleteUserDataTask.TYPE.asString())
+ .withFactory(TaskDTOModule::new);
+ }
+
+ public static DeleteUserDataTaskDTO toDTO(DeleteUserDataTask domainObject, String typeName) {
+ return new DeleteUserDataTaskDTO(typeName,
+ domainObject.getUsername().asString(),
+ domainObject.getFromStep().map(StepName::asString));
+ }
+
+ private final String type;
+ private final String username;
+ private final Optional<String> fromStep;
+
+ public DeleteUserDataTaskDTO(@JsonProperty("type") String type,
+ @JsonProperty("username") String username,
+ @JsonProperty("fromStep") Optional<String> fromStep) {
+ this.type = type;
+ this.username = username;
+ this.fromStep = fromStep;
+ }
+
+ public DeleteUserDataTask fromDTO(DeleteUserDataService service) {
+ return new DeleteUserDataTask(service, Username.of(username), fromStep.map(StepName::new));
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public Optional<String> getFromStep() {
+ return fromStep;
+ }
+}
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUserDataTaskSerializationTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUserDataTaskSerializationTest.java
new file mode 100644
index 0000000000..0a6ba532ff
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUserDataTaskSerializationTest.java
@@ -0,0 +1,136 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.webadmin.service;
+
+import java.time.Instant;
+import java.util.Optional;
+
+import org.apache.james.JsonSerializationVerifier;
+import org.apache.james.core.Username;
+import org.apache.james.user.api.DeleteUserDataTaskStep;
+import org.junit.jupiter.api.Test;
+import org.reactivestreams.Publisher;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import reactor.core.publisher.Mono;
+
+class DeleteUserDataTaskSerializationTest {
+ private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
+ private static final Username USERNAME = Username.of("user");
+ private static final DeleteUserDataTaskStep.StepName STEP_A = new DeleteUserDataTaskStep.StepName("A");
+ private static final DeleteUserDataTaskStep.StepName STEP_B = new DeleteUserDataTaskStep.StepName("B");
+ private static final DeleteUserDataTaskStep.StepName STEP_C = new DeleteUserDataTaskStep.StepName("C");
+ private static final DeleteUserDataTaskStep.StepName STEP_D = new DeleteUserDataTaskStep.StepName("D");
+ private static final DeleteUserDataTaskStep A = asStep(STEP_A);
+ private static final DeleteUserDataTaskStep B = asStep(STEP_B);
+ private static final DeleteUserDataTaskStep C = asStep(STEP_C);
+ private static final DeleteUserDataTaskStep D = asStep(STEP_D);
+
+ private static DeleteUserDataTaskStep asStep(DeleteUserDataTaskStep.StepName name) {
+ return new DeleteUserDataTaskStep() {
+ @Override
+ public StepName name() {
+ return name;
+ }
+
+ @Override
+ public int priority() {
+ return 0;
+ }
+
+ @Override
+ public Publisher<Void> deleteUserData(Username username) {
+ return Mono.empty();
+ }
+ };
+ }
+
+ private static final String SERIALIZED_TASK = "{\"username\":\"user\",\"type\":\"DeleteUserDataTask\"}";
+ private static final String SERIALIZED_TASK_WITH_FROM_STEP = "{\"fromStep\":\"B\",\"username\":\"user\",\"type\":\"DeleteUserDataTask\"}";
+ private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{" +
+ " \"username\":\"user\"," +
+ " \"status\":{" +
+ " \"A\":\"DONE\"," +
+ " \"B\":\"WAITING\"," +
+ " \"C\":\"FAILED\"," +
+ " \"D\":\"ABORTED\"}," +
+ " \"timestamp\":\"2018-11-13T12:00:55Z\"," +
+ " \"type\":\"DeleteUserDataTask\"" +
+ "}";
+ private static final String SERIALIZED_ADDITIONAL_INFORMATION_WITH_STEP_NAME = "{" +
+ " \"username\":\"user\"," +
+ " \"fromStep\":\"B\"," +
+ " \"status\":{" +
+ " \"A\":\"DONE\"," +
+ " \"B\":\"WAITING\"," +
+ " \"C\":\"FAILED\"," +
+ " \"D\":\"ABORTED\"}," +
+ " \"timestamp\":\"2018-11-13T12:00:55Z\"," +
+ " \"type\":\"DeleteUserDataTask\"" +
+ "}";
+
+ private static final DeleteUserDataService SERVICE = new DeleteUserDataService(ImmutableSet.of(A, B, C, D));
+
+ @Test
+ void taskShouldBeSerializable() throws Exception {
+ JsonSerializationVerifier.dtoModule(DeleteUserDataTaskDTO.module(SERVICE))
+ .bean(new DeleteUserDataTask(SERVICE, USERNAME, Optional.empty()))
+ .json(SERIALIZED_TASK)
+ .verify();
+ }
+
+ @Test
+ void taskShouldBeSerializableWithFromStep() throws Exception {
+ JsonSerializationVerifier.dtoModule(DeleteUserDataTaskDTO.module(SERVICE))
+ .bean(new DeleteUserDataTask(SERVICE, USERNAME, Optional.of(STEP_B)))
+ .json(SERIALIZED_TASK_WITH_FROM_STEP)
+ .verify();
+ }
+
+ @Test
+ void additionalInformationShouldBeSerializable() throws Exception {
+ JsonSerializationVerifier.dtoModule(DeleteUserDataTaskAdditionalInformationDTO.module())
+ .bean(new DeleteUserDataTask.AdditionalInformation(
+ TIMESTAMP,
+ USERNAME,
+ ImmutableMap.of(STEP_A, DeleteUserDataService.StepState.DONE,
+ STEP_B, DeleteUserDataService.StepState.WAITING,
+ STEP_C, DeleteUserDataService.StepState.FAILED,
+ STEP_D, DeleteUserDataService.StepState.ABORTED), Optional.empty()))
+ .json(SERIALIZED_ADDITIONAL_INFORMATION)
+ .verify();
+ }
+
+ @Test
+ void additionalInformationShouldBeSerializableWithStepName() throws Exception {
+ JsonSerializationVerifier.dtoModule(DeleteUserDataTaskAdditionalInformationDTO.module())
+ .bean(new DeleteUserDataTask.AdditionalInformation(
+ TIMESTAMP,
+ USERNAME,
+ ImmutableMap.of(STEP_A, DeleteUserDataService.StepState.DONE,
+ STEP_B, DeleteUserDataService.StepState.WAITING,
+ STEP_C, DeleteUserDataService.StepState.FAILED,
+ STEP_D, DeleteUserDataService.StepState.ABORTED), Optional.of(STEP_B)))
+ .json(SERIALIZED_ADDITIONAL_INFORMATION_WITH_STEP_NAME)
+ .verify();
+ }
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org