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());
}
@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
public ResponseEntity<PunishmentHistoryDto> getHistoryById(String type, Integer id) {
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.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.ResponseEntity;
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")
@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");
}
@RateLimit(limit = 5, timeValue = 1, timeUnit = TimeUnit.MINUTES, key = "login")
@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");
}
}

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,
@NotNull UUID uuid, int page) {
int offset = page * PAGE_SIZE;

View File

@ -1,7 +1,7 @@
import {Component, OnInit} from '@angular/core';
import {FormsComponent} from '../forms.component';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {AppealsService} from '../../../api';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {AppealsService, MinecraftAppeal} from '../../../api';
@Component({
selector: 'app-appeal',
@ -13,22 +13,18 @@ import {AppealsService} from '../../../api';
})
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() {
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() {
@ -37,8 +33,7 @@ export class AppealComponent implements OnInit {
return
}
if (this.form.valid) {
console.log('Form submitted:', this.form.value);
// Process form submission here
this.sendForm()
} else {
// Mark all fields as touched to trigger validation display
Object.keys(this.form.controls).forEach(field => {
@ -52,12 +47,23 @@ export class AppealComponent implements OnInit {
}
}
private sendForm(validForm: FormGroup) {
// const appeal: MinecraftAppeal = {
//
// }
// this.appealApi.submitMinecraftAppeal()
private sendForm() {
const rawValue = this.form.getRawValue();
const appeal: MinecraftAppeal = {
appeal: rawValue.appeal,
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'
/history/single/{type}/{id}:
$ref: './schemas/bans/bans.yml#/getHistoryById'
/history/all/{uuid}:
$ref: './schemas/bans/bans.yml#/getAllHistoryForUUID'
/history/total:
$ref: './schemas/bans/bans.yml#/getTotalPunishments'
/appeal/update-mail:
@ -36,7 +38,7 @@ paths:
$ref: './schemas/forms/appeal/appeal.yml#/MinecraftAppeal'
/appeal/discord-appeal:
$ref: './schemas/forms/appeal/appeal.yml#/DiscordAppeal'
/login/addUserLogin:
$ref: './schemas/login/login.yml#/AddUserLogin'
/login/requestNewUserLogin/{uuid}:
$ref: './schemas/login/login.yml#/RequestNewUserLogin'
/login/userLogin:
$ref: './schemas/login/login.yml#/UserLogin'

View File

@ -89,7 +89,7 @@ getHistoryForUuid:
parameters:
- $ref: '#/components/parameters/UserType'
- $ref: '#/components/parameters/HistoryType'
- $ref: '#/components/parameters/Uuid'
- $ref: '../generic/parameters.yml#/components/parameters/Uuid'
- $ref: '#/components/parameters/Page'
responses:
'200':
@ -158,7 +158,7 @@ getTotalResultsForUuidSearch:
parameters:
- $ref: '#/components/parameters/UserType'
- $ref: '#/components/parameters/HistoryType'
- $ref: '#/components/parameters/Uuid'
- $ref: '../generic/parameters.yml#/components/parameters/Uuid'
responses:
'200':
description: Successful operation
@ -195,6 +195,22 @@ getHistoryById:
application/json:
schema:
$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:
parameters:
HistoryType:
@ -212,13 +228,6 @@ components:
schema:
type: string
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:
name: userType
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:
post:
get:
tags:
- login
summary: Log in to the site
description: Log in to the site through a code from the server
operationId: login
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginData'
parameters:
- $ref: '#/components/parameters/Code'
responses:
'200':
description: Logged in
content:
application/json:
application/text:
schema:
$ref: '#/components/schemas/LoginResult'
type: string
description: A JWT token for this user
'401':
description: Login failed - Invalid credentials
content:
application/json:
application/text:
schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError'
default:
description: Unexpected error
content:
application/json:
application/text:
schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError'
AddUserLogin:
post:
RequestNewUserLogin:
get:
tags:
- login
summary: Add a login
description: Add a code, user combination that can be used to log in
operationId: addLogin
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddLogin'
summary: Request a login
description: Request a code, that can be used to log in
operationId: requestLogin
parameters:
- $ref: '../generic/parameters.yml#/components/parameters/Uuid'
responses:
'200':
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:
description: Unexpected error
content:
@ -53,6 +57,14 @@ AddUserLogin:
schema:
$ref: '../generic/errors.yml#/components/schemas/ApiError'
components:
parameters:
Code:
name: code
in: path
required: true
schema:
type: string
description: The code to log in with
schemas:
LoginData:
type: object
@ -62,35 +74,11 @@ components:
loginCode:
type: string
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:
type: object
required:
- loginCode
- uuid
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:
type: string
format: uuid