Администраторы почты из Jambotron: каждый ADMIN управляет ящиками
continuous-integration/drone/pr Build is passing
continuous-integration/drone/pr Build is passing
users.is_admin (V8) — ставит только служебное API (PUT /api/service/accounts с "admin"), ящик сам себя администратором не сделает. MailAdmins: список из конфигурации + выданные Jambotron (загружаются при старте, меняются сразу). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,10 +40,11 @@ public class ServiceController {
|
||||
private static final Logger log = LoggerFactory.getLogger(ServiceController.class);
|
||||
|
||||
/** @param displayName null — unchanged (new account: the name before @) */
|
||||
public record AccountRequest(@Size(max = 100) String displayName, Boolean active) {
|
||||
/** @param admin mail administrator (Jambotron ADMIN); null — leave as it is */
|
||||
public record AccountRequest(@Size(max = 100) String displayName, Boolean active, Boolean admin) {
|
||||
}
|
||||
|
||||
public record AccountView(String email, String displayName, boolean active, List<String> lists) {
|
||||
public record AccountView(String email, String displayName, boolean active, boolean admin, List<String> lists) {
|
||||
}
|
||||
|
||||
/** @param password generated, only when the account was just created or got a new password */
|
||||
@@ -59,10 +60,12 @@ public class ServiceController {
|
||||
private final MailLists lists;
|
||||
private final MailDirectory directory;
|
||||
private final MailboxAccess access;
|
||||
private final com.mailserver.config.MailAdmins admins;
|
||||
|
||||
public ServiceController(@Value("${mailserver.service-token:}") String token, UserService users, MailLists lists,
|
||||
MailDirectory directory, MailboxAccess access) {
|
||||
MailDirectory directory, MailboxAccess access, com.mailserver.config.MailAdmins admins) {
|
||||
this.access = access;
|
||||
this.admins = admins;
|
||||
this.token = token.isBlank() ? null : token.trim().getBytes(StandardCharsets.UTF_8);
|
||||
this.users = users;
|
||||
this.lists = lists;
|
||||
@@ -84,13 +87,14 @@ public class ServiceController {
|
||||
@PathVariable String email, @RequestBody Mono<AccountRequest> body) {
|
||||
check(auth);
|
||||
String address = directory.address(email);
|
||||
return body.defaultIfEmpty(new AccountRequest(null, null)).flatMap(request -> users.findOptional(address)
|
||||
return body.defaultIfEmpty(new AccountRequest(null, null, null)).flatMap(request -> users.findOptional(address)
|
||||
.flatMap(user -> update(user, request).flatMap(this::view)
|
||||
.map(view -> ResponseEntity.ok(new AccountResult(view, null))))
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
String password = MailDirectory.randomPassword();
|
||||
return directory.createMailbox(address, request.displayName(), password)
|
||||
.flatMap(user -> Boolean.FALSE.equals(request.active()) ? update(user, request) : Mono.just(user))
|
||||
.flatMap(user -> Boolean.FALSE.equals(request.active()) || Boolean.TRUE.equals(request.admin())
|
||||
? update(user, request) : Mono.just(user))
|
||||
.doOnNext(user -> log.info("Mailbox {} created by Jambotron", user.getEmail()))
|
||||
.flatMap(this::view)
|
||||
.map(view -> ResponseEntity.status(HttpStatus.CREATED).body(new AccountResult(view, password)));
|
||||
@@ -152,8 +156,14 @@ public class ServiceController {
|
||||
}
|
||||
|
||||
private Mono<User> update(User user, AccountRequest request) {
|
||||
Mono<User> named = request.displayName() == null || request.displayName().isBlank() ? Mono.just(user)
|
||||
Mono<User> renamed = request.displayName() == null || request.displayName().isBlank() ? Mono.just(user)
|
||||
: users.updateDisplayName(user, request.displayName());
|
||||
Mono<User> named = request.admin() == null || request.admin() == user.isAdmin() ? renamed
|
||||
: renamed.flatMap(u -> users.setAdmin(u, request.admin()))
|
||||
.doOnNext(u -> {
|
||||
admins.grant(u.getEmail(), u.isAdmin());
|
||||
log.info("Mailbox {} {} mail administrator by Jambotron", u.getEmail(), u.isAdmin() ? "made" : "is no longer");
|
||||
});
|
||||
if (request.active() == null || request.active() == user.isActive()) {
|
||||
return named;
|
||||
}
|
||||
@@ -166,7 +176,7 @@ public class ServiceController {
|
||||
|
||||
private Mono<AccountView> view(User user) {
|
||||
return lists.listsOf(user.getId()).collectList()
|
||||
.map(in -> new AccountView(user.getEmail(), user.getDisplayName(), user.isActive(), in));
|
||||
.map(in -> new AccountView(user.getEmail(), user.getDisplayName(), user.isActive(), admins.isAdmin(user.getEmail()), in));
|
||||
}
|
||||
|
||||
/** 404 when the API is off, 401 for a wrong token (constant-time compare). */
|
||||
|
||||
Reference in New Issue
Block a user