Add endpoints and schema for history retrieval by UUID

Introduced a new API endpoint to fetch all punishment history for a specified UUID. Updated existing schemas, controllers, and mappers to support this functionality. Adjusted login endpoints to improve request handling and streamlined frontend form setup for appeals.
This commit is contained in:
Teriuihi 2025-05-03 04:37:47 +02:00
parent 8c7ec0a237
commit cf758bfe60
8 changed files with 117 additions and 84 deletions

View File

@ -153,6 +153,24 @@ public class HistoryApiController implements HistoryApi {
return ResponseEntity.ok().body(searchResultCountCompletableFuture.join()); return ResponseEntity.ok().body(searchResultCountCompletableFuture.join());
} }
@Override
public ResponseEntity<PunishmentHistoryListDto> getAllHistoryForUUID(String uuid) {
PunishmentHistoryListDto punishmentHistoryList = new PunishmentHistoryListDto();
CompletableFuture<List<HistoryRecord>> historyRecordsCompletableFuture = new CompletableFuture<>();
Connection.getConnection(Databases.LITE_BANS).runQuery(sqlSession -> {
log.debug("Loading all history for uuid {}", uuid);
try {
List<HistoryRecord> punishments = sqlSession.getMapper(UUIDHistoryMapper.class)
.getAllHistoryForUUID(UUID.fromString(uuid));
historyRecordsCompletableFuture.complete(punishments);
} catch (Exception e) {
log.error("Failed to load all history for uuid {}", uuid, e);
historyRecordsCompletableFuture.completeExceptionally(e);
}
});
return mapPunishmentHistory(punishmentHistoryList, historyRecordsCompletableFuture);
}
@Override @Override
public ResponseEntity<PunishmentHistoryDto> getHistoryById(String type, Integer id) { public ResponseEntity<PunishmentHistoryDto> getHistoryById(String type, Integer id) {
HistoryType historyTypeEnum = HistoryType.getHistoryType(type); HistoryType historyTypeEnum = HistoryType.getHistoryType(type);

View File

@ -2,9 +2,6 @@ package com.alttd.altitudeweb.controllers.login;
import com.alttd.altitudeweb.api.LoginApi; import com.alttd.altitudeweb.api.LoginApi;
import com.alttd.altitudeweb.controllers.limits.RateLimit; import com.alttd.altitudeweb.controllers.limits.RateLimit;
import com.alttd.altitudeweb.model.AddLoginDto;
import com.alttd.altitudeweb.model.LoginDataDto;
import com.alttd.altitudeweb.model.LoginResultDto;
import org.springframework.http.HttpStatusCode; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -17,13 +14,13 @@ public class LoginController implements LoginApi {
@RateLimit(limit = 100, timeValue = 1, timeUnit = TimeUnit.MINUTES, key = "addLogin") @RateLimit(limit = 100, timeValue = 1, timeUnit = TimeUnit.MINUTES, key = "addLogin")
@Override @Override
public ResponseEntity<Void> addLogin(AddLoginDto addLoginDto) { public ResponseEntity<String> requestLogin(String uuid) throws Exception {
throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Adding login is not yet supported"); throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Adding login is not yet supported");
} }
@RateLimit(limit = 5, timeValue = 1, timeUnit = TimeUnit.MINUTES, key = "login") @RateLimit(limit = 5, timeValue = 1, timeUnit = TimeUnit.MINUTES, key = "login")
@Override @Override
public ResponseEntity<LoginResultDto> login(LoginDataDto loginDataDto) { public ResponseEntity<String> login(String code) {
throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Logging in is not yet supported"); throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Logging in is not yet supported");
} }
} }

View File

@ -80,6 +80,10 @@ public interface UUIDHistoryMapper {
}; };
} }
default List<HistoryRecord> getAllHistoryForUUID(@NotNull UUID uuid) {
return getRecentAllHistory(uuid.toString(), "uuid", 100, 0);
}
private List<HistoryRecord> getRecent(@NotNull String tableName, @NotNull UserType userType, private List<HistoryRecord> getRecent(@NotNull String tableName, @NotNull UserType userType,
@NotNull UUID uuid, int page) { @NotNull UUID uuid, int page) {
int offset = page * PAGE_SIZE; int offset = page * PAGE_SIZE;

View File

@ -1,7 +1,7 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {FormsComponent} from '../forms.component'; import {FormsComponent} from '../forms.component';
import {FormBuilder, FormGroup, Validators} from '@angular/forms'; import {FormControl, FormGroup, Validators} from '@angular/forms';
import {AppealsService} from '../../../api'; import {AppealsService, MinecraftAppeal} from '../../../api';
@Component({ @Component({
selector: 'app-appeal', selector: 'app-appeal',
@ -13,22 +13,18 @@ import {AppealsService} from '../../../api';
}) })
export class AppealComponent implements OnInit { export class AppealComponent implements OnInit {
public form: FormGroup | undefined; public form: FormGroup<Appeal>;
constructor(private fb: FormBuilder, private appealApi: AppealsService) { constructor(private appealApi: AppealsService) {
this.form = new FormGroup({
username: new FormControl('', {nonNullable: true, validators: [Validators.required]}),
punishmentId: new FormControl('', {nonNullable: true, validators: [Validators.required]}),
email: new FormControl('', {nonNullable: true, validators: [Validators.required, Validators.email]}),
appeal: new FormControl('', {nonNullable: true, validators: [Validators.required, Validators.minLength(10)]})
});
} }
ngOnInit() { ngOnInit() {
this.initForm()
}
private initForm() {
this.form = this.fb.group({
name: ['', [Validators.required]],
punishmentId: ['', [Validators.required]],
email: ['', [Validators.required, Validators.email]],
message: ['', [Validators.required, Validators.minLength(10)]]
});
} }
public onSubmit() { public onSubmit() {
@ -37,8 +33,7 @@ export class AppealComponent implements OnInit {
return return
} }
if (this.form.valid) { if (this.form.valid) {
console.log('Form submitted:', this.form.value); this.sendForm()
// Process form submission here
} else { } else {
// Mark all fields as touched to trigger validation display // Mark all fields as touched to trigger validation display
Object.keys(this.form.controls).forEach(field => { Object.keys(this.form.controls).forEach(field => {
@ -52,12 +47,23 @@ export class AppealComponent implements OnInit {
} }
} }
private sendForm(validForm: FormGroup) { private sendForm() {
// const appeal: MinecraftAppeal = { const rawValue = this.form.getRawValue();
// const appeal: MinecraftAppeal = {
// } appeal: rawValue.appeal,
// this.appealApi.submitMinecraftAppeal() email: rawValue.email,
punishmentId: parseInt(rawValue.punishmentId),
username: rawValue.username,
uuid: ''//TODO
}
this.appealApi.submitMinecraftAppeal(appeal).subscribe()
} }
}
interface Appeal {
username: FormControl<string>;
punishmentId: FormControl<string>;
email: FormControl<string>;
appeal: FormControl<string>;
} }

View File

@ -28,6 +28,8 @@ paths:
$ref: './schemas/bans/bans.yml#/getTotalResultsForUserSearch' $ref: './schemas/bans/bans.yml#/getTotalResultsForUserSearch'
/history/single/{type}/{id}: /history/single/{type}/{id}:
$ref: './schemas/bans/bans.yml#/getHistoryById' $ref: './schemas/bans/bans.yml#/getHistoryById'
/history/all/{uuid}:
$ref: './schemas/bans/bans.yml#/getAllHistoryForUUID'
/history/total: /history/total:
$ref: './schemas/bans/bans.yml#/getTotalPunishments' $ref: './schemas/bans/bans.yml#/getTotalPunishments'
/appeal/update-mail: /appeal/update-mail:
@ -36,7 +38,7 @@ paths:
$ref: './schemas/forms/appeal/appeal.yml#/MinecraftAppeal' $ref: './schemas/forms/appeal/appeal.yml#/MinecraftAppeal'
/appeal/discord-appeal: /appeal/discord-appeal:
$ref: './schemas/forms/appeal/appeal.yml#/DiscordAppeal' $ref: './schemas/forms/appeal/appeal.yml#/DiscordAppeal'
/login/addUserLogin: /login/requestNewUserLogin/{uuid}:
$ref: './schemas/login/login.yml#/AddUserLogin' $ref: './schemas/login/login.yml#/RequestNewUserLogin'
/login/userLogin: /login/userLogin:
$ref: './schemas/login/login.yml#/UserLogin' $ref: './schemas/login/login.yml#/UserLogin'

View File

@ -89,7 +89,7 @@ getHistoryForUuid:
parameters: parameters:
- $ref: '#/components/parameters/UserType' - $ref: '#/components/parameters/UserType'
- $ref: '#/components/parameters/HistoryType' - $ref: '#/components/parameters/HistoryType'
- $ref: '#/components/parameters/Uuid' - $ref: '../generic/parameters.yml#/components/parameters/Uuid'
- $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Page'
responses: responses:
'200': '200':
@ -158,7 +158,7 @@ getTotalResultsForUuidSearch:
parameters: parameters:
- $ref: '#/components/parameters/UserType' - $ref: '#/components/parameters/UserType'
- $ref: '#/components/parameters/HistoryType' - $ref: '#/components/parameters/HistoryType'
- $ref: '#/components/parameters/Uuid' - $ref: '../generic/parameters.yml#/components/parameters/Uuid'
responses: responses:
'200': '200':
description: Successful operation description: Successful operation
@ -195,6 +195,22 @@ getHistoryById:
application/json: application/json:
schema: schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError' $ref: '../generic/errors.yml#/components/schemas/ApiError'
getAllHistoryForUUID:
get:
tags:
- history
summary: Gets all history for specified UUID
description: Retrieves all history for specified UUID
operationId: getAllHistoryForUUID
parameters:
- $ref: '../generic/parameters.yml#/components/parameters/Uuid'
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/PunishmentHistoryList'
components: components:
parameters: parameters:
HistoryType: HistoryType:
@ -212,13 +228,6 @@ components:
schema: schema:
type: string type: string
description: The (partial) username to search for description: The (partial) username to search for
Uuid:
name: uuid
in: path
required: true
schema:
type: string
description: The uuid of the desired user
UserType: UserType:
name: userType name: userType
in: path in: path

View File

@ -0,0 +1,9 @@
components:
parameters:
Uuid:
name: uuid
in: path
required: true
schema:
type: string
description: The uuid of the desired user

View File

@ -1,51 +1,55 @@
UserLogin: UserLogin:
post: get:
tags: tags:
- login - login
summary: Log in to the site summary: Log in to the site
description: Log in to the site through a code from the server description: Log in to the site through a code from the server
operationId: login operationId: login
requestBody: parameters:
required: true - $ref: '#/components/parameters/Code'
content:
application/json:
schema:
$ref: '#/components/schemas/LoginData'
responses: responses:
'200': '200':
description: Logged in description: Logged in
content: content:
application/json: application/text:
schema: schema:
$ref: '#/components/schemas/LoginResult' type: string
description: A JWT token for this user
'401': '401':
description: Login failed - Invalid credentials description: Login failed - Invalid credentials
content: content:
application/json: application/text:
schema: schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError' $ref: '../generic/errors.yml#/components/schemas/ApiError'
default: default:
description: Unexpected error description: Unexpected error
content: content:
application/json: application/text:
schema: schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError' $ref: '../generic/errors.yml#/components/schemas/ApiError'
AddUserLogin: RequestNewUserLogin:
post: get:
tags: tags:
- login - login
summary: Add a login summary: Request a login
description: Add a code, user combination that can be used to log in description: Request a code, that can be used to log in
operationId: addLogin operationId: requestLogin
requestBody: parameters:
required: true - $ref: '../generic/parameters.yml#/components/parameters/Uuid'
content:
application/json:
schema:
$ref: '#/components/schemas/AddLogin'
responses: responses:
'200': '200':
description: Success description: Success
content:
application/text:
schema:
type: string
description: code to log in with
'401':
description: Login failed - Invalid secret
content:
application/json:
schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError'
default: default:
description: Unexpected error description: Unexpected error
content: content:
@ -53,6 +57,14 @@ AddUserLogin:
schema: schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError' $ref: '../generic/errors.yml#/components/schemas/ApiError'
components: components:
parameters:
Code:
name: code
in: path
required: true
schema:
type: string
description: The code to log in with
schemas: schemas:
LoginData: LoginData:
type: object type: object
@ -62,35 +74,11 @@ components:
loginCode: loginCode:
type: string type: string
description: The code to log in description: The code to log in
LoginResult:
type: object
required:
- uuid
- userName
- auth
properties:
uuid:
type: string
format: uuid
description: UUID of logged in user
userName:
type: string
description: Name of the logged in user
auth:
type: string
description: Token to use along side requests
AddLogin: AddLogin:
type: object type: object
required: required:
- loginCode
- uuid - uuid
properties: properties:
auth:
type: string
description: Token to verify the sender is allowed to add logins
loginCode:
type: string
description: The code that can be logged in with
uuid: uuid:
type: string type: string
format: uuid format: uuid