Add chat history retrieval: implement /api/site/chat/history endpoint, database query, service logic, and permission checks.

This commit is contained in:
stijn committed 2026-09-29 22:07:28 +02:00
1 parent 4623fbcc82
commit a4adff3845
5 files changed
+71

No files matched your search

@@ -75,6 +75,7 @@ public class SecurityConfig {
.requestMatchers("/api/history/admin/**").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
.requestMatchers("/api/login/userLogin/**").permitAll()
.requestMatchers("/api/site/chat/**").authenticated()
.requestMatchers("/api/site/chat/history").hasAuthority(PermissionClaimDto.HEAD_MOD.getValue())
.requestMatchers("/api/site/chat/send-admin-chat/**").hasAnyAuthority(PermissionClaimDto.HEAD_MOD.getValue(), PermissionClaimDto.MOD.getValue())
.requestMatchers("/api/site/chat/punish/**").hasAnyAuthority(PermissionClaimDto.HEAD_MOD.getValue(), PermissionClaimDto.MOD.getValue())
.requestMatchers("/api/chat/server/send/**").permitAll()
@@ -1,6 +1,7 @@
package com.alttd.altitudeweb.controllers.chat;
import com.alttd.altitudeweb.api.ChatInfoApi;
import com.alttd.altitudeweb.model.ChatMessageDto;
import com.alttd.altitudeweb.model.PartyNameDto;
import com.alttd.altitudeweb.model.PlayerNameDto;
import com.alttd.altitudeweb.services.chat.ChatInfoService;
@@ -9,6 +10,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
@Slf4j
@@ -43,4 +46,11 @@ public class ChatInfoController implements ChatInfoApi {
.orElse(ResponseEntity.notFound().build());
}
@Override
public ResponseEntity<List<ChatMessageDto>> getChatHistory(OffsetDateTime from, OffsetDateTime to) {
List<ChatMessageDto> chatMessageDtoList = chatInfoService.getHistory(from.toInstant(), to.toInstant()).join()
.stream().map(ChatMessageMapper::toDto).toList();
return ResponseEntity.ok(chatMessageDtoList);
}
}
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.experimental.UtilityClass;
import java.time.ZoneOffset;
import java.util.UUID;
@UtilityClass
@@ -74,4 +75,28 @@ public class ChatMessageMapper {
throw new IllegalStateException("Failed to serialize ChatMessage to JSON: " + chatMessage.getUuid(), e);
}
}
public static ChatMessageDto toDto(ChatMessage chatMessage) {
ChatMessageDto chatMessageDto = new ChatMessageDto();
chatMessageDto.setUuid(chatMessage.getUuid());
chatMessageDto.setTimestamp(chatMessage.getTimestamp().atOffset(ZoneOffset.UTC));
chatMessageDto.setServer(chatMessage.getServer());
chatMessageDto.setType(toDto(chatMessage.getType()));
chatMessageDto.setChannel(chatMessage.getChannel());
chatMessageDto.setReceiver(chatMessage.getReceiver());
chatMessageDto.setMessage(chatMessage.getMessageJson());
chatMessageDto.setBlocked(chatMessage.isNotBlocked());
return chatMessageDto;
}
public static ChatMessageDto.TypeEnum toDto(ChatMessageType chatMessageType) {
return switch (chatMessageType) {
case PUBLIC -> ChatMessageDto.TypeEnum.PUBLIC;
case GLOBAL -> ChatMessageDto.TypeEnum.GLOBAL;
case PARTY -> ChatMessageDto.TypeEnum.PARTY;
case GAC -> ChatMessageDto.TypeEnum.GAC;
case MSG -> ChatMessageDto.TypeEnum.MSG;
case CUSTOM -> ChatMessageDto.TypeEnum.CUSTOM;
};
}
}
@@ -1,6 +1,9 @@
package com.alttd.altitudeweb.services.chat;
import com.alttd.altitudeweb.controllers.chat.ChatMessage;
import com.alttd.altitudeweb.controllers.chat.ChatMessageMapper;
import com.alttd.altitudeweb.database.Databases;
import com.alttd.altitudeweb.database.chat.ChatLogMapper;
import com.alttd.altitudeweb.database.chat.NicknameMapper;
import com.alttd.altitudeweb.database.chat.PartyMapper;
import com.alttd.altitudeweb.database.luckperms.UUIDUsernameMapper;
@@ -10,8 +13,11 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@Slf4j
@Service
@@ -41,4 +47,24 @@ public class ChatInfoService {
.runQueryWithResult(sqlSession -> sqlSession.getMapper(PartyMapper.class).getPartyName(id));
}
public CompletableFuture<List<ChatMessage>> getHistory(Instant from, Instant to) {
CompletableFuture<List<ChatMessage>> completableFuture = new CompletableFuture<>();
Connection.getConnection(Databases.CHAT)
.runQuery(sqlSession -> {
log.debug("Loading chat history from {} to {}", from, to);
try {
List<ChatMessage> list = sqlSession.getMapper(ChatLogMapper.class)
.getChatLogHistory(from.toEpochMilli(), to.toEpochMilli())
.stream()
.map(ChatMessageMapper::fromDao)
.toList();
completableFuture.complete(list);
} catch (Exception e) {
log.error("Failed to load history count", e);
}
});
return completableFuture;
}
}
@@ -16,6 +16,15 @@ public interface ChatLogMapper {
""")
List<ChatLogDao> getChatLogs(@Param("since") long since);
@Select("""
SELECT uuid, time_stamp, server, type, channel, receiver, mini_message, blocked
FROM chat_log
WHERE mini_message IS NOT NULL
AND time_stamp >= #{since}
AND time_stamp <= #{to}
""")
List<ChatLogDao> getChatLogHistory(@Param("since") long since, @Param("to") long to);
@Select("""
SELECT party_id FROM chat_users
WHERE uuid = #{uuid}