- Роль ADMIN = users.is_admin; встроенный администратор (mailserver.admins, по
умолчанию admin@) всегда ADMIN и получает роль в базе при старте.
- PUT /api/admin/mailboxes/{id}/role {ADMIN|USER}: только ADMIN; не свою, не
встроенного, общий ящик не может быть ADMIN.
- Admin panel (/admin, только ADMIN): USERS (логины и роли, MAKE ADMIN / MAKE USER),
MAILBOXES, LISTS. User panel (/settings): профиль, пароль, хранилище, вид, мои ящики.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,8 +45,13 @@ public class MailboxAdminController {
|
||||
private static final Logger log = LoggerFactory.getLogger(MailboxAdminController.class);
|
||||
private static final int MIN_PASSWORD = MailDirectory.MIN_PASSWORD;
|
||||
|
||||
/** @param role ADMIN or USER; @param builtIn the administrator from the configuration — the role stays */
|
||||
public record MailboxView(Long id, String email, String displayName, boolean active, boolean admin, boolean trap,
|
||||
boolean shared, List<String> members, long usedBytes, long quotaBytes, Instant createdAt) {
|
||||
boolean shared, List<String> members, long usedBytes, long quotaBytes, Instant createdAt,
|
||||
String role, boolean builtIn) {
|
||||
}
|
||||
|
||||
public record RoleRequest(String role) {
|
||||
}
|
||||
|
||||
/** @param password empty — the server generates one and returns it once */
|
||||
@@ -171,6 +176,30 @@ public class MailboxAdminController {
|
||||
}));
|
||||
}
|
||||
|
||||
/** Role ADMIN (manages mailboxes, lists, roles — Admin panel) or USER. Not your own, not the built-in administrator. */
|
||||
@PutMapping("/{id}/role")
|
||||
public Mono<MailboxView> role(Mono<Authentication> auth, @PathVariable Long id, @RequestBody Mono<RoleRequest> body) {
|
||||
return admin(auth).flatMap(me -> body.flatMap(request -> mailbox(id).flatMap(user -> {
|
||||
if (!"ADMIN".equals(request.role()) && !"USER".equals(request.role())) {
|
||||
return Mono.error(bad("Role: ADMIN or USER"));
|
||||
}
|
||||
boolean toAdmin = "ADMIN".equals(request.role());
|
||||
if (user.getEmail().equalsIgnoreCase(me)) {
|
||||
return Mono.error(bad("You can not change your own role"));
|
||||
}
|
||||
if (!toAdmin && admins.isBuiltIn(user.getEmail())) {
|
||||
return Mono.error(bad("The built-in administrator stays ADMIN"));
|
||||
}
|
||||
if (toAdmin && user.isShared()) {
|
||||
return Mono.error(bad("A shared mailbox has no login of its own — it can not be ADMIN"));
|
||||
}
|
||||
return users.setAdmin(user, toAdmin).doOnNext(u -> {
|
||||
admins.grant(u.getEmail(), toAdmin);
|
||||
log.warn("Mailbox {} role {} given by administrator {}", u.getEmail(), request.role(), me);
|
||||
});
|
||||
}))).flatMap(this::view);
|
||||
}
|
||||
|
||||
/** Trap: what the mailbox sends is stored in its own INBOX, nothing leaves the server (staging@). */
|
||||
@PutMapping("/{id}/trap")
|
||||
public Mono<MailboxView> trap(Mono<Authentication> auth, @PathVariable Long id, @RequestBody Mono<TrapRequest> body) {
|
||||
@@ -237,7 +266,7 @@ public class MailboxAdminController {
|
||||
return mail.usedBytes(user.getId()).defaultIfEmpty(0L).zipWith(access.members(user.getId()).collectList())
|
||||
.map(pair -> new MailboxView(user.getId(), user.getEmail(), user.getDisplayName(), user.isActive(),
|
||||
admins.isAdmin(user.getEmail()), user.isTrap(), user.isShared(), pair.getT2(), pair.getT1(), user.getQuotaBytes() == null ? 0 : user.getQuotaBytes(),
|
||||
user.getCreatedAt()));
|
||||
user.getCreatedAt(), admins.isAdmin(user.getEmail()) ? "ADMIN" : "USER", admins.isBuiltIn(user.getEmail())));
|
||||
}
|
||||
|
||||
private static ResponseStatusException bad(String message) {
|
||||
|
||||
Reference in New Issue
Block a user