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/02/21 01:16:06 UTC

[james-project] 03/09: JAMES-3885 Task to change of username

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 d76de2d27b4117ded54a632a83ca4df66a725c46
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Feb 16 15:32:33 2023 +0700

    JAMES-3885 Task to change of username
    
    Simple task wrapper around the service
---
 server/protocols/webadmin/webadmin-data/pom.xml    |   6 ++
 .../james/webadmin/service/UsernameChangeTask.java | 109 +++++++++++++++++++++
 ...UsernameChangeTaskAdditionalInformationDTO.java |  96 ++++++++++++++++++
 .../webadmin/service/UsernameChangeTaskDTO.java    |  72 ++++++++++++++
 .../UsernameChangeTaskSerializationTest.java       | 104 ++++++++++++++++++++
 5 files changed, 387 insertions(+)

diff --git a/server/protocols/webadmin/webadmin-data/pom.xml b/server/protocols/webadmin/webadmin-data/pom.xml
index ddf4a426ba..ee3c964475 100644
--- a/server/protocols/webadmin/webadmin-data/pom.xml
+++ b/server/protocols/webadmin/webadmin-data/pom.xml
@@ -50,6 +50,12 @@
             <groupId>${james.groupId}</groupId>
             <artifactId>james-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-json</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-data-api</artifactId>
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java
new file mode 100644
index 0000000000..cab6908686
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java
@@ -0,0 +1,109 @@
+/****************************************************************
+ * 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.UsernameChangeTaskStep;
+
+import reactor.core.publisher.Mono;
+
+public class UsernameChangeTask implements Task {
+    static final TaskType TYPE = TaskType.of("UsernameChangeTask");
+
+    public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
+        private final Instant timestamp;
+        private final Username oldUser;
+        private final Username newUser;
+        private final Map<UsernameChangeTaskStep.StepName, UsernameChangeService.StepState> status;
+
+        public AdditionalInformation(Instant timestamp, Username oldUser, Username newUser, Map<UsernameChangeTaskStep.StepName, UsernameChangeService.StepState> status) {
+            this.timestamp = timestamp;
+            this.oldUser = oldUser;
+            this.newUser = newUser;
+            this.status = status;
+        }
+
+        public Username getOldUser() {
+            return oldUser;
+        }
+
+        public Username getNewUser() {
+            return newUser;
+        }
+
+        public Map<UsernameChangeTaskStep.StepName, UsernameChangeService.StepState> getStatus() {
+            return status;
+        }
+
+        @Override
+        public Instant timestamp() {
+            return timestamp;
+        }
+    }
+
+    private final Username oldUser;
+    private final Username newUser;
+    private final UsernameChangeService.Performer performer;
+
+    public UsernameChangeTask(UsernameChangeService service, Username oldUser, Username newUser) {
+        this.oldUser = oldUser;
+        this.newUser = newUser;
+
+        this.performer = service.performer();
+    }
+
+
+    @Override
+    public Result run() {
+        return performer.changeUsername(oldUser, newUser)
+            .thenReturn(Result.COMPLETED)
+            .onErrorResume(e -> {
+                LOGGER.error("Error while changing username {} into {}", oldUser.asString(), newUser.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(), oldUser, newUser, performer.getStatus().getStates()));
+    }
+
+    public Username getOldUser() {
+        return oldUser;
+    }
+
+    public Username getNewUser() {
+        return newUser;
+    }
+}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java
new file mode 100644
index 0000000000..14e41f4e0c
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java
@@ -0,0 +1,96 @@
+/****************************************************************
+ * 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 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.UsernameChangeTaskStep;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableMap;
+
+public class UsernameChangeTaskAdditionalInformationDTO implements AdditionalInformationDTO {
+    public static AdditionalInformationDTOModule<UsernameChangeTask.AdditionalInformation, UsernameChangeTaskAdditionalInformationDTO> module() {
+        return DTOModule.forDomainObject(UsernameChangeTask.AdditionalInformation.class)
+            .convertToDTO(UsernameChangeTaskAdditionalInformationDTO.class)
+            .toDomainObjectConverter(dto -> new UsernameChangeTask.AdditionalInformation(
+                dto.timestamp,
+                Username.of(dto.oldUser),
+                Username.of(dto.newUser),
+                dto.status.entrySet().stream()
+                    .collect(ImmutableMap.toImmutableMap(
+                        entry -> new UsernameChangeTaskStep.StepName(entry.getKey()),
+                        entry -> UsernameChangeService.StepState.valueOf(entry.getValue())))))
+            .toDTOConverter((details, type) -> new UsernameChangeTaskAdditionalInformationDTO(
+                type,
+                details.getOldUser().asString(),
+                details.getNewUser().asString(),
+                details.getStatus().entrySet().stream()
+                    .collect(ImmutableMap.toImmutableMap(
+                        entry -> entry.getKey().asString(),
+                        entry -> entry.getValue().toString())),
+                details.timestamp()))
+            .typeName(UsernameChangeTask.TYPE.asString())
+            .withFactory(AdditionalInformationDTOModule::new);
+    }
+
+    private final String type;
+    private final String oldUser;
+    private final String newUser;
+    private final Map<String, String> status;
+    private final Instant timestamp;
+
+    public UsernameChangeTaskAdditionalInformationDTO(@JsonProperty("type") String type,
+                                                      @JsonProperty("oldUser") String oldUser,
+                                                      @JsonProperty("newUser") String newUser,
+                                                      @JsonProperty("status") Map<String, String> status,
+                                                      @JsonProperty("timestamp") Instant timestamp) {
+        this.type = type;
+        this.oldUser = oldUser;
+        this.newUser = newUser;
+        this.status = status;
+        this.timestamp = timestamp;
+    }
+
+    public String getOldUser() {
+        return oldUser;
+    }
+
+    public String getNewUser() {
+        return newUser;
+    }
+
+    public Map<String, String> getStatus() {
+        return status;
+    }
+
+    public Instant getTimestamp() {
+        return timestamp;
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java
new file mode 100644
index 0000000000..b833c9f1f8
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java
@@ -0,0 +1,72 @@
+/****************************************************************
+ * 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 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 com.fasterxml.jackson.annotation.JsonProperty;
+
+public class UsernameChangeTaskDTO implements TaskDTO {
+
+    public static TaskDTOModule<UsernameChangeTask, UsernameChangeTaskDTO> module(UsernameChangeService service) {
+        return DTOModule
+            .forDomainObject(UsernameChangeTask.class)
+            .convertToDTO(UsernameChangeTaskDTO.class)
+            .toDomainObjectConverter(dto -> dto.fromDTO(service))
+            .toDTOConverter(UsernameChangeTaskDTO::toDTO)
+            .typeName(UsernameChangeTask.TYPE.asString())
+            .withFactory(TaskDTOModule::new);
+    }
+
+    public static UsernameChangeTaskDTO toDTO(UsernameChangeTask domainObject, String typeName) {
+        return new UsernameChangeTaskDTO(typeName, domainObject.getOldUser().asString(), domainObject.getNewUser().asString());
+    }
+
+    private final String type;
+    private final String oldUser;
+    private final String newUser;
+
+    public UsernameChangeTaskDTO(@JsonProperty("type") String type,
+                                 @JsonProperty("oldUser") String oldUser,
+                                 @JsonProperty("newUser") String newUser) {
+        this.type = type;
+        this.oldUser = oldUser;
+        this.newUser = newUser;
+    }
+
+    public UsernameChangeTask fromDTO(UsernameChangeService service) {
+        return new UsernameChangeTask(service, Username.of(oldUser), Username.of(newUser));
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    public String getOldUser() {
+        return oldUser;
+    }
+
+    public String getNewUser() {
+        return newUser;
+    }
+}
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java
new file mode 100644
index 0000000000..d17a7c2ecb
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java
@@ -0,0 +1,104 @@
+/****************************************************************
+ * 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 org.apache.james.JsonSerializationVerifier;
+import org.apache.james.core.Username;
+import org.apache.james.user.api.UsernameChangeTaskStep;
+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 UsernameChangeTaskSerializationTest {
+    private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
+    private static final Username OLD_USERNAME = Username.of("user");
+    private static final Username NEW_USERNAME = Username.of("geraldine");
+    private static final UsernameChangeTaskStep.StepName STEP_A = new UsernameChangeTaskStep.StepName("A");
+    private static final UsernameChangeTaskStep.StepName STEP_B = new UsernameChangeTaskStep.StepName("B");
+    private static final UsernameChangeTaskStep.StepName STEP_C = new UsernameChangeTaskStep.StepName("C");
+    private static final UsernameChangeTaskStep.StepName STEP_D = new UsernameChangeTaskStep.StepName("D");
+    private static final UsernameChangeTaskStep A = asStep(STEP_A);
+    private static final UsernameChangeTaskStep B = asStep(STEP_B);
+    private static final UsernameChangeTaskStep C = asStep(STEP_C);
+    private static final UsernameChangeTaskStep D = asStep(STEP_D);
+
+    private static UsernameChangeTaskStep asStep(UsernameChangeTaskStep.StepName name) {
+        return new UsernameChangeTaskStep() {
+            @Override
+            public StepName name() {
+                return name;
+            }
+
+            @Override
+            public int priority() {
+                return 0;
+            }
+
+            @Override
+            public Publisher<Void> changeUsername(Username oldUsername, Username newUsername) {
+                return Mono.empty();
+            }
+        };
+    }
+
+    private static final String SERIALIZED_TASK = "{\"newUser\":\"geraldine\",\"oldUser\":\"user\",\"type\":\"UsernameChangeTask\"}";
+    private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{" +
+        "  \"newUser\":\"geraldine\"," +
+        "  \"oldUser\":\"user\"," +
+        "  \"status\":{" +
+        "    \"A\":\"DONE\"," +
+        "    \"B\":\"WAITING\"," +
+        "    \"C\":\"FAILED\"," +
+        "    \"D\":\"ABORTED\"}," +
+        "  \"timestamp\":\"2018-11-13T12:00:55Z\"," +
+        "  \"type\":\"UsernameChangeTask\"" +
+        "}";
+
+    private static final UsernameChangeService SERVICE = new UsernameChangeService(ImmutableSet.of(A, B, C, D));
+
+    @Test
+    void taskShouldBeSerializable() throws Exception {
+        JsonSerializationVerifier.dtoModule(UsernameChangeTaskDTO.module(SERVICE))
+            .bean(new UsernameChangeTask(SERVICE, OLD_USERNAME, NEW_USERNAME))
+            .json(SERIALIZED_TASK)
+            .verify();
+    }
+
+    @Test
+    void additionalInformationShouldBeSerializable() throws Exception {
+        JsonSerializationVerifier.dtoModule(UsernameChangeTaskAdditionalInformationDTO.module())
+            .bean(new UsernameChangeTask.AdditionalInformation(
+                TIMESTAMP,
+                OLD_USERNAME,
+                NEW_USERNAME,
+                ImmutableMap.of(STEP_A, UsernameChangeService.StepState.DONE,
+                    STEP_B, UsernameChangeService.StepState.WAITING,
+                    STEP_C, UsernameChangeService.StepState.FAILED,
+                    STEP_D, UsernameChangeService.StepState.ABORTED)))
+            .json(SERIALIZED_ADDITIONAL_INFORMATION)
+            .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