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/25 05:45:23 UTC
[james-project] 03/03: JAMES-3909 Add listing failedUsers to task additional information
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 375aebbd21cb4bf16a9a9cc74df221a86a6abc83
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Mon May 22 16:52:30 2023 +0700
JAMES-3909 Add listing failedUsers to task additional information
---
.../docs/modules/ROOT/pages/operate/webadmin.adoc | 3 +++
.../service/DeleteUsersDataOfDomainTask.java | 27 ++++++++++++++++++++--
...rsDataOfDomainTaskAdditionalInformationDTO.java | 26 +++++++++++++++++++--
.../james/webadmin/routes/DomainsRoutesTest.java | 7 ++++--
...leteUsersDataOfDomainTaskSerializationTest.java | 13 +++++++++--
.../service/DeleteUsersDataOfDomainTaskTest.java | 5 ++++
src/site/markdown/server/manage-webadmin.md | 3 +++
7 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc b/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc
index 0a69f5618f..fa1a311569 100644
--- a/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc
+++ b/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc
@@ -478,10 +478,13 @@ The scheduled task will have the following type `DeleteUsersDataOfDomainTask` an
"domain": "domain.tld",
"successfulUsersCount": 2,
"failedUsersCount": 1,
+ "failedUsers": ["faileduser@domain.tld"],
"timestamp": "2023-05-22T08:52:47.076261Z"
}
....
+Notes: `failedUsers` only lists maximum 100 failed users.
+
== Administrating users
=== Create a user
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTask.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTask.java
index 84487aade6..146fa7a787 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTask.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTask.java
@@ -23,6 +23,8 @@ import java.time.Clock;
import java.time.Instant;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
@@ -42,18 +44,21 @@ import reactor.core.publisher.Mono;
public class DeleteUsersDataOfDomainTask implements Task {
static final TaskType TYPE = TaskType.of("DeleteUsersDataOfDomainTask");
private static final int LOW_CONCURRENCY = 2;
+ private static final int MAX_STORED_FAILED_USERS = 100;
public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
private final Instant timestamp;
private final Domain domain;
private final long successfulUsersCount;
private final long failedUsersCount;
+ private final Set<Username> failedUsers;
- public AdditionalInformation(Instant timestamp, Domain domain, long successfulUsersCount, long failedUsersCount) {
+ public AdditionalInformation(Instant timestamp, Domain domain, long successfulUsersCount, long failedUsersCount, Set<Username> failedUsers) {
this.timestamp = timestamp;
this.domain = domain;
this.successfulUsersCount = successfulUsersCount;
this.failedUsersCount = failedUsersCount;
+ this.failedUsers = failedUsers;
}
public Domain getDomain() {
@@ -68,6 +73,10 @@ public class DeleteUsersDataOfDomainTask implements Task {
return failedUsersCount;
}
+ public Set<Username> getFailedUsers() {
+ return failedUsers;
+ }
+
@Override
public Instant timestamp() {
return timestamp;
@@ -95,10 +104,12 @@ public class DeleteUsersDataOfDomainTask implements Task {
static class Context {
private final AtomicLong successfulUsersCount;
private final AtomicLong failedUsersCount;
+ private final Set<Username> failedUsers;
public Context() {
this.successfulUsersCount = new AtomicLong();
this.failedUsersCount = new AtomicLong();
+ this.failedUsers = ConcurrentHashMap.newKeySet();
}
private void increaseSuccessfulUsers() {
@@ -109,6 +120,10 @@ public class DeleteUsersDataOfDomainTask implements Task {
failedUsersCount.incrementAndGet();
}
+ private void addFailedUser(Username username) {
+ failedUsers.add(username);
+ }
+
public long getSuccessfulUsersCount() {
return successfulUsersCount.get();
}
@@ -116,6 +131,10 @@ public class DeleteUsersDataOfDomainTask implements Task {
public long getFailedUsersCount() {
return failedUsersCount.get();
}
+
+ public Set<Username> getFailedUsers() {
+ return failedUsers;
+ }
}
private final Domain domain;
@@ -148,6 +167,9 @@ public class DeleteUsersDataOfDomainTask implements Task {
.onErrorResume(error -> {
LOGGER.error("Error when deleting data of user {}", username.asString(), error);
context.increaseFailedUsers();
+ if (context.failedUsers.size() < MAX_STORED_FAILED_USERS) {
+ context.addFailedUser(username);
+ }
return Mono.just(Result.PARTIAL);
});
}
@@ -159,7 +181,8 @@ public class DeleteUsersDataOfDomainTask implements Task {
@Override
public Optional<TaskExecutionDetails.AdditionalInformation> details() {
- return Optional.of(new AdditionalInformation(Clock.systemUTC().instant(), domain, context.getSuccessfulUsersCount(), context.getFailedUsersCount()));
+ return Optional.of(new AdditionalInformation(Clock.systemUTC().instant(), domain, context.getSuccessfulUsersCount(),
+ context.getFailedUsersCount(), context.getFailedUsers()));
}
public Domain getDomain() {
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskAdditionalInformationDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskAdditionalInformationDTO.java
index 7bcd3c033d..f601fe8785 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskAdditionalInformationDTO.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskAdditionalInformationDTO.java
@@ -20,8 +20,11 @@
package org.apache.james.webadmin.service;
import java.time.Instant;
+import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.james.core.Domain;
+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;
@@ -33,28 +36,43 @@ public class DeleteUsersDataOfDomainTaskAdditionalInformationDTO implements Addi
return DTOModule.forDomainObject(DeleteUsersDataOfDomainTask.AdditionalInformation.class)
.convertToDTO(DeleteUsersDataOfDomainTaskAdditionalInformationDTO.class)
.toDomainObjectConverter(dto -> new DeleteUsersDataOfDomainTask.AdditionalInformation(
- dto.timestamp, Domain.of(dto.domain), dto.successfulUsersCount, dto.failedUsersCount))
+ dto.timestamp, Domain.of(dto.domain), dto.successfulUsersCount, dto.failedUsersCount, toSetUsername(dto.failedUsers)))
.toDTOConverter((details, type) -> new DeleteUsersDataOfDomainTaskAdditionalInformationDTO(
- type, details.getDomain().asString(), details.getSuccessfulUsersCount(), details.getFailedUsersCount(), details.timestamp()))
+ type, details.getDomain().asString(), details.getSuccessfulUsersCount(), details.getFailedUsersCount(), toSetString(details.getFailedUsers()), details.timestamp()))
.typeName(DeleteUsersDataOfDomainTask.TYPE.asString())
.withFactory(AdditionalInformationDTOModule::new);
}
+ private static Set<Username> toSetUsername(Set<String> usernames) {
+ return usernames.stream()
+ .map(Username::of)
+ .collect(Collectors.toSet());
+ }
+
+ private static Set<String> toSetString(Set<Username> usernames) {
+ return usernames.stream()
+ .map(Username::asString)
+ .collect(Collectors.toSet());
+ }
+
private final String type;
private final String domain;
private final long successfulUsersCount;
private final long failedUsersCount;
+ private final Set<String> failedUsers;
private final Instant timestamp;
public DeleteUsersDataOfDomainTaskAdditionalInformationDTO(@JsonProperty("type") String type,
@JsonProperty("domain") String domain,
@JsonProperty("successfulUsersCount") long successfulUsersCount,
@JsonProperty("failedUsersCount") long failedUsersCount,
+ @JsonProperty("failedUsers") Set<String> failedUsers,
@JsonProperty("timestamp") Instant timestamp) {
this.type = type;
this.domain = domain;
this.successfulUsersCount = successfulUsersCount;
this.failedUsersCount = failedUsersCount;
+ this.failedUsers = failedUsers;
this.timestamp = timestamp;
}
@@ -70,6 +88,10 @@ public class DeleteUsersDataOfDomainTaskAdditionalInformationDTO implements Addi
return failedUsersCount;
}
+ public Set<String> getFailedUsers() {
+ return failedUsers;
+ }
+
public Instant getTimestamp() {
return timestamp;
}
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainsRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainsRoutesTest.java
index baefeaf289..82b88af391 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainsRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/DomainsRoutesTest.java
@@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
@@ -184,7 +185,8 @@ class DomainsRoutesTest {
.body("additionalInformation.type", is("DeleteUsersDataOfDomainTask"))
.body("additionalInformation.domain", is("localhost"))
.body("additionalInformation.successfulUsersCount", is(2))
- .body("additionalInformation.failedUsersCount", is(0));
+ .body("additionalInformation.failedUsersCount", is(0))
+ .body("additionalInformation.failedUsers", empty());
// then should delete data of the 2 users
assertThat(recordProcessedUsersStep.processedUsers)
@@ -244,7 +246,8 @@ class DomainsRoutesTest {
.body("additionalInformation.type", is("DeleteUsersDataOfDomainTask"))
.body("additionalInformation.domain", is("localhost"))
.body("additionalInformation.successfulUsersCount", is(2))
- .body("additionalInformation.failedUsersCount", is(0));
+ .body("additionalInformation.failedUsersCount", is(0))
+ .body("additionalInformation.failedUsers", empty());
// THEN users data of domain.tld should not be clear
assertThat(recordProcessedUsersStep.processedUsers)
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskSerializationTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskSerializationTest.java
index 8de0149656..9d1cf3ffb5 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskSerializationTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskSerializationTest.java
@@ -22,6 +22,7 @@ package org.apache.james.webadmin.service;
import static org.mockito.Mockito.mock;
import java.time.Instant;
+import java.util.Set;
import org.apache.james.JsonSerializationVerifier;
import org.apache.james.core.Domain;
@@ -40,6 +41,7 @@ class DeleteUsersDataOfDomainTaskSerializationTest {
private static final Domain DOMAIN = Domain.of("domain");
private static final long SUCCESSFUL_USERS_COUNT = 99L;
private static final long FAILED_USERS_COUNT = 1L;
+ private static final Set<Username> FAILED_USERS = Set.of(Username.of("faileduser@domain"));
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");
@@ -69,7 +71,14 @@ class DeleteUsersDataOfDomainTaskSerializationTest {
}
private static final String SERIALIZED_TASK = "{\"type\":\"DeleteUsersDataOfDomainTask\",\"domain\":\"domain\"}";
- private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{\"type\":\"DeleteUsersDataOfDomainTask\",\"domain\":\"domain\",\"successfulUsersCount\":99,\"failedUsersCount\":1,\"timestamp\":\"2018-11-13T12:00:55Z\"}";
+ private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{\n" +
+ " \"type\": \"DeleteUsersDataOfDomainTask\",\n" +
+ " \"domain\": \"domain\",\n" +
+ " \"successfulUsersCount\": 99,\n" +
+ " \"failedUsersCount\": 1,\n" +
+ " \"failedUsers\": [\"faileduser@domain\"],\n" +
+ " \"timestamp\": \"2018-11-13T12:00:55Z\"\n" +
+ "}";
private static final DeleteUserDataService SERVICE = new DeleteUserDataService(ImmutableSet.of(A, B, C, D));
@@ -86,7 +95,7 @@ class DeleteUsersDataOfDomainTaskSerializationTest {
void additionalInformationShouldBeSerializable() throws Exception {
JsonSerializationVerifier.dtoModule(DeleteUsersDataOfDomainTaskAdditionalInformationDTO.module())
.bean(new DeleteUsersDataOfDomainTask.AdditionalInformation(
- TIMESTAMP, DOMAIN, SUCCESSFUL_USERS_COUNT, FAILED_USERS_COUNT))
+ TIMESTAMP, DOMAIN, SUCCESSFUL_USERS_COUNT, FAILED_USERS_COUNT, FAILED_USERS))
.json(SERIALIZED_ADDITIONAL_INFORMATION)
.verify();
}
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskTest.java
index f9bc9cecea..d5650d1bde 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/DeleteUsersDataOfDomainTaskTest.java
@@ -147,6 +147,8 @@ class DeleteUsersDataOfDomainTaskTest {
softly.assertThat(result).isEqualTo(Task.Result.PARTIAL);
softly.assertThat(task.getContext().getSuccessfulUsersCount()).isEqualTo(0L);
softly.assertThat(task.getContext().getFailedUsersCount()).isEqualTo(2L);
+ softly.assertThat(task.getContext().getFailedUsers())
+ .containsExactlyInAnyOrder(Username.of("user1@domain1.tld"), Username.of("user2@domain1.tld"));
});
}
@@ -168,6 +170,8 @@ class DeleteUsersDataOfDomainTaskTest {
softly.assertThat(result).isEqualTo(Task.Result.PARTIAL);
softly.assertThat(task.getContext().getSuccessfulUsersCount()).isEqualTo(0L);
softly.assertThat(task.getContext().getFailedUsersCount()).isEqualTo(2L);
+ softly.assertThat(task.getContext().getFailedUsers())
+ .containsExactlyInAnyOrder(Username.of("user1@domain1.tld"), Username.of("user2@domain1.tld"));
});
}
@@ -189,6 +193,7 @@ class DeleteUsersDataOfDomainTaskTest {
softly.assertThat(result).isEqualTo(Task.Result.PARTIAL);
softly.assertThat(task.getContext().getSuccessfulUsersCount()).isEqualTo(2L);
softly.assertThat(task.getContext().getFailedUsersCount()).isEqualTo(1L);
+ softly.assertThat(task.getContext().getFailedUsers()).containsExactly(Username.of("user1@domain1.tld"));
});
}
}
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index 5864d0a644..5ea35c2dd3 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -326,10 +326,13 @@ The scheduled task will have the following type `DeleteUsersDataOfDomainTask` an
"domain": "domain.tld",
"successfulUsersCount": 2,
"failedUsersCount": 1,
+ "failedUsers": ["faileduser@domain.tld"],
"timestamp": "2023-05-22T08:52:47.076261Z"
}
```
+Notes: `failedUsers` only lists maximum 100 failed users.
+
## Administrating users
- [Create a user](#Create_a_user)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org