Add admin endpoints for editing and removing punishments and implement frontend dialog for punishment management
This commit is contained in:
@@ -47,6 +47,7 @@ public class SecurityConfig {
|
||||
.requestMatchers("/api/head_mod/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
||||
.requestMatchers("/api/particles/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
||||
.requestMatchers("/api/files/save/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
||||
.requestMatchers("/api/history/admin/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
|
||||
.requestMatchers("/api/login/userLogin/**").permitAll()
|
||||
.anyRequest().permitAll()
|
||||
)
|
||||
|
||||
+108
-1
@@ -1,6 +1,7 @@
|
||||
package com.alttd.altitudeweb.controllers.history;
|
||||
|
||||
import com.alttd.altitudeweb.api.HistoryApi;
|
||||
import com.alttd.altitudeweb.controllers.data_from_auth.AuthenticatedUuid;
|
||||
import com.alttd.altitudeweb.services.limits.RateLimit;
|
||||
import com.alttd.altitudeweb.model.HistoryCountDto;
|
||||
import com.alttd.altitudeweb.model.PunishmentHistoryListDto;
|
||||
@@ -10,7 +11,8 @@ import com.alttd.altitudeweb.database.litebans.*;
|
||||
import com.alttd.altitudeweb.model.PunishmentHistoryDto;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@@ -229,4 +231,109 @@ public class HistoryApiController implements HistoryApi {
|
||||
.type(type)
|
||||
.id(historyRecord.getId());
|
||||
}
|
||||
|
||||
// Admin edit endpoints (restricted to head_mod scope)
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('SCOPE_head_mod')")
|
||||
public ResponseEntity<PunishmentHistoryDto> updatePunishmentReason(String type, Integer id, String reason) {
|
||||
HistoryType historyTypeEnum = HistoryType.getHistoryType(type);
|
||||
CompletableFuture<PunishmentHistoryDto> result = new CompletableFuture<>();
|
||||
|
||||
Connection.getConnection(Databases.LITE_BANS).runQuery(sqlSession -> {
|
||||
try {
|
||||
IdHistoryMapper idMapper = sqlSession.getMapper(IdHistoryMapper.class);
|
||||
EditHistoryMapper editMapper = sqlSession.getMapper(EditHistoryMapper.class);
|
||||
HistoryRecord before = idMapper.getRecentHistory(historyTypeEnum, id);
|
||||
if (before == null) {
|
||||
result.complete(null);
|
||||
return;
|
||||
}
|
||||
int changed = editMapper.setReason(historyTypeEnum, id, reason);
|
||||
HistoryRecord after = idMapper.getRecentHistory(historyTypeEnum, id);
|
||||
UUID actor = AuthenticatedUuid.getAuthenticatedUserUuid();
|
||||
log.info("[Punishment Edit] Actor={} Type={} Id={} Reason: '{}' -> '{}' (rows={})",
|
||||
actor, historyTypeEnum, id, before.getReason(), after != null ? after.getReason() : null, changed);
|
||||
result.complete(after != null ? mapPunishmentHistory(after) : null);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to update reason for {} id {}", type, id, e);
|
||||
result.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
PunishmentHistoryDto body = result.join();
|
||||
if (body == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('SCOPE_head_mod')")
|
||||
public ResponseEntity<PunishmentHistoryDto> updatePunishmentUntil(String type, Integer id, Long until) {
|
||||
HistoryType historyTypeEnum = HistoryType.getHistoryType(type);
|
||||
CompletableFuture<PunishmentHistoryDto> result = new CompletableFuture<>();
|
||||
|
||||
Connection.getConnection(Databases.LITE_BANS).runQuery(sqlSession -> {
|
||||
try {
|
||||
IdHistoryMapper idMapper = sqlSession.getMapper(IdHistoryMapper.class);
|
||||
EditHistoryMapper editMapper = sqlSession.getMapper(EditHistoryMapper.class);
|
||||
HistoryRecord before = idMapper.getRecentHistory(historyTypeEnum, id);
|
||||
if (before == null) {
|
||||
result.complete(null);
|
||||
return;
|
||||
}
|
||||
int changed = editMapper.setUntil(historyTypeEnum, id, until);
|
||||
HistoryRecord after = idMapper.getRecentHistory(historyTypeEnum, id);
|
||||
UUID actor = AuthenticatedUuid.getAuthenticatedUserUuid();
|
||||
log.info("[Punishment Edit] Actor={} Type={} Id={} Until: '{}' -> '{}' (rows={})",
|
||||
actor, historyTypeEnum, id, before.getUntil(), after != null ? after.getUntil() : null, changed);
|
||||
result.complete(after != null ? mapPunishmentHistory(after) : null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Invalid until edit for type {} id {}: {}", type, id, e.getMessage());
|
||||
result.complete(null);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to update until for {} id {}", type, id, e);
|
||||
result.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
PunishmentHistoryDto body = result.join();
|
||||
if (body == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('SCOPE_head_mod')")
|
||||
public ResponseEntity<Void> removePunishment(String type, Integer id) {
|
||||
HistoryType historyTypeEnum = HistoryType.getHistoryType(type);
|
||||
CompletableFuture<Boolean> result = new CompletableFuture<>();
|
||||
|
||||
Connection.getConnection(Databases.LITE_BANS).runQuery(sqlSession -> {
|
||||
try {
|
||||
IdHistoryMapper idMapper = sqlSession.getMapper(IdHistoryMapper.class);
|
||||
EditHistoryMapper editMapper = sqlSession.getMapper(EditHistoryMapper.class);
|
||||
HistoryRecord before = idMapper.getRecentHistory(historyTypeEnum, id);
|
||||
if (before == null) {
|
||||
result.complete(false);
|
||||
return;
|
||||
}
|
||||
UUID actorUuid = AuthenticatedUuid.getAuthenticatedUserUuid();
|
||||
String actorName = sqlSession.getMapper(RecentNamesMapper.class).getUsername(actorUuid.toString());
|
||||
int changed = editMapper.remove(historyTypeEnum, id);
|
||||
log.info("[Punishment Remove] Actor={} ({}) Type={} Id={} Before(active={} removedBy={} reason='{}') (rows={})",
|
||||
actorName, actorUuid, historyTypeEnum, id,
|
||||
before.getRemovedByName() == null ? 1 : 0, before.getRemovedByName(), before.getRemovedByReason(),
|
||||
changed);
|
||||
result.complete(changed > 0);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to remove punishment for {} id {}", type, id, e);
|
||||
result.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
Boolean ok = result.join();
|
||||
if (ok == null || !ok) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user