Skip to content

Commit

Permalink
chat, deaths, connections window APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
rfresh2 committed Jan 16, 2025
1 parent ba0e6da commit 86aafc3
Show file tree
Hide file tree
Showing 7 changed files with 404 additions and 1 deletion.
63 changes: 63 additions & 0 deletions src/main/java/vc/controller/ChatsController.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import vc.util.PlayerLookup;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
Expand All @@ -41,6 +42,7 @@ public record Chat(OffsetDateTime time, String chat) {}
public record WordCount(int count) {}
public record PlayerChat(String playerName, UUID uuid, OffsetDateTime time, String chat) {}
public record ChatSearchResponse(List<PlayerChat> chats, int total, int pageCount) {}
public record ChatWindowResponse(List<PlayerChat> chats) {}

@GetMapping("/chats")
@RateLimiter(name = "main")
Expand Down Expand Up @@ -113,6 +115,67 @@ public ResponseEntity<ChatsResponse> chats(
}
}

@GetMapping("/chats/window")
@RateLimiter(name = "main")
@Cacheable("chatsWindow")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
All 2b2t chats during a window of time, starting from startDate (required) until endDate or pageSize is met
startDate and endDate must be ISO 8601 formatted strings, in this format: yyyy-MM-dd'T'HH:mm:ss.SSSXXX
Example: "2022-10-31T01:30:00.000".
""",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ChatWindowResponse.class)
)
}
),
@ApiResponse(
responseCode = "204",
description = "No chats found in this window.",
content = @Content
),
@ApiResponse(
responseCode = "400",
description = "Bad request. startDate must be provided",
content = @Content
)
})
public ResponseEntity<ChatWindowResponse> chatWindow(
@RequestParam(value = "startDate", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,
@RequestParam(value = "endDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate,
@RequestParam(value = "pageSize", required = false) Integer pageSize
) {
if (pageSize != null && pageSize > 100) {
return ResponseEntity.badRequest().build();
}
final int size = pageSize == null ? 25 : pageSize;
var baseQuery = dsl.select(CHATS.PLAYER_NAME, CHATS.PLAYER_UUID, CHATS.TIME, CHATS.CHAT)
.from(CHATS)
.where(CHATS.TIME.greaterOrEqual(startDate.atOffset(ZoneOffset.UTC)));
if (endDate != null) {
if (endDate.equals(startDate) || endDate.isBefore(startDate)) {
return ResponseEntity.badRequest().build();
}
baseQuery = baseQuery.and(CHATS.TIME.lessOrEqual(endDate.atOffset(ZoneOffset.UTC)));
}
var chats = baseQuery
.orderBy(CHATS.TIME.asc())
.limit(size)
.fetch()
.into(PlayerChat.class);
if (chats.isEmpty()) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.ok(new ChatWindowResponse(chats));
}
}

@GetMapping("/chats/word-count")
@RateLimiter(name = "main")
@Cacheable("chats-word-count")
Expand Down
63 changes: 63 additions & 0 deletions src/main/java/vc/controller/ConnectionsController.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import vc.util.PlayerLookup;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
Expand All @@ -39,6 +40,8 @@ public ConnectionsController(final DSLContext dsl, final PlayerLookup playerLook

public record ConnectionsResponse(List<Connection> connections, int total, int pageCount) { }
public record Connection(OffsetDateTime time, Connectiontype connection) {}
public record PlayerConnection(OffsetDateTime time, Connectiontype connection, String playerName, UUID uuid) {}
public record ConnectionsWindowResponse(List<PlayerConnection> connections) {}

@GetMapping("/connections")
@RateLimiter(name = "main")
Expand Down Expand Up @@ -112,4 +115,64 @@ public ResponseEntity<ConnectionsResponse> connections(
return ResponseEntity.ok(new ConnectionsResponse(connections, rowCount.intValue(), (int) Math.ceil(rowCount / (double) size)));
}
}

@GetMapping("/connections/window")
@RateLimiter(name = "main")
@Cacheable("connectionsWindow")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
All 2b2t connections during a window of time, starting from startDate (required) until endDate or pageSize is met
startDate and endDate must be ISO 8601 formatted strings, in this format: yyyy-MM-dd'T'HH:mm:ss.SSSXXX
Example: "2022-10-31T01:30:00.000".
""",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ConnectionsWindowResponse.class)
)
}
),
@ApiResponse(
responseCode = "204",
description = "No connections found in this window.",
content = @Content
),
@ApiResponse(
responseCode = "400",
description = "Bad request. startDate must be provided",
content = @Content
)
})
public ResponseEntity<ConnectionsWindowResponse> connectionsWindow(
@RequestParam(value = "startDate", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,
@RequestParam(value = "endDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate,
@RequestParam(value = "pageSize", required = false) Integer pageSize
) {
if (pageSize != null && pageSize > 100) {
return ResponseEntity.badRequest().build();
}
final int size = pageSize == null ? 25 : pageSize;
var baseQuery = dsl.selectFrom(CONNECTIONS)
.where(CONNECTIONS.TIME.greaterOrEqual(startDate.atOffset(ZoneOffset.UTC)));
if (endDate != null) {
if (endDate.equals(startDate) || endDate.isBefore(startDate)) {
return ResponseEntity.badRequest().build();
}
baseQuery = baseQuery.and(CONNECTIONS.TIME.lessOrEqual(endDate.atOffset(ZoneOffset.UTC)));
}
List<PlayerConnection> connections = baseQuery
.orderBy(CONNECTIONS.TIME.asc())
.limit(size)
.fetch()
.into(PlayerConnection.class);
if (connections.isEmpty()) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.ok(new ConnectionsWindowResponse(connections));
}
}
}
63 changes: 63 additions & 0 deletions src/main/java/vc/controller/DeathsController.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import vc.util.PlayerLookup;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
Expand Down Expand Up @@ -50,6 +51,7 @@ public record DeathsResponse(List<Death> deaths, int total, int pageCount) {}
public record KillsResponse(List<Death> kills, int total, int pageCount) {}
public record PlayerDeathOrKillCountResponse(List<PlayerDeathOrKillCount> players) {}
public record PlayerDeathOrKillCount(String playerName, UUID uuid, int count) {}
public record DeathsWindowResponse(List<Death> deaths) {}

@GetMapping("/deaths")
@RateLimiter(name = "main")
Expand Down Expand Up @@ -125,6 +127,67 @@ public ResponseEntity<DeathsResponse> deaths(
}
}

@GetMapping("/deaths/window")
@RateLimiter(name = "main")
@Cacheable("deathsWindow")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = """
All 2b2t deaths during a window of time, starting from startDate (required) until endDate or pageSize is met
startDate and endDate must be ISO 8601 formatted strings, in this format: yyyy-MM-dd'T'HH:mm:ss.SSSXXX
Example: "2022-10-31T01:30:00.000".
""",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = DeathsWindowResponse.class)
)
}
),
@ApiResponse(
responseCode = "204",
description = "No deaths found in this window.",
content = @Content
),
@ApiResponse(
responseCode = "400",
description = "Bad request. startDate must be provided",
content = @Content
)
})
public ResponseEntity<DeathsWindowResponse> deathsWindow(
@RequestParam(value = "startDate", required = true) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,
@RequestParam(value = "endDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate,
@RequestParam(value = "pageSize", required = false) Integer pageSize
) {
if (pageSize != null && pageSize > 100) {
return ResponseEntity.badRequest().build();
}
final int size = pageSize == null ? 25 : pageSize;
var baseQuery = dsl
.selectFrom(DEATHS)
.where(DEATHS.TIME.greaterOrEqual(startDate.atOffset(ZoneOffset.UTC)));
if (endDate != null) {
if (endDate.equals(startDate) || endDate.isBefore(startDate)) {
return ResponseEntity.badRequest().build();
}
baseQuery = baseQuery.and(DEATHS.TIME.lessOrEqual(endDate.atOffset(ZoneOffset.UTC)));
}
List<Death> deathsList = baseQuery
.orderBy(DEATHS.TIME.asc())
.limit(size)
.fetch()
.into(Death.class);
if (deathsList.isEmpty()) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.ok(new DeathsWindowResponse(deathsList));
}
}

@GetMapping("/kills")
@RateLimiter(name = "main")
@Cacheable("kills")
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/vc/controller/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package vc.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<String> handleMissingParams(MissingServletRequestParameterException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getParameterName() + " is required");
}
}
Loading

0 comments on commit 86aafc3

Please sign in to comment.