Add API endpoints for search result counts by name and UUID
Introduced new API paths and backend logic to retrieve total punishment counts based on user search queries using names or UUIDs. Updated the frontend to utilize these endpoints and display the total search results dynamically.
This commit is contained in:
parent
ee66bdda83
commit
ecee377f01
|
|
@ -111,6 +111,48 @@ public class HistoryApiController implements HistoryApi {
|
||||||
return mapHistoryCount(historyCountCompletableFuture.join());
|
return mapHistoryCount(historyCountCompletableFuture.join());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Integer> getTotalResultsForUserSearch(String userType, String type, String user) {
|
||||||
|
UserType userTypeEnum = UserType.getUserType(userType);
|
||||||
|
HistoryType historyTypeEnum = HistoryType.getHistoryType(type);
|
||||||
|
CompletableFuture<Integer> searchResultCountCompletableFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
|
Connection.getConnection(Databases.LITE_BANS)
|
||||||
|
.runQuery(sqlSession -> {
|
||||||
|
log.debug("Loading name search result count");
|
||||||
|
try {
|
||||||
|
Integer punishmentCount = sqlSession.getMapper(HistoryCountMapper.class)
|
||||||
|
.getNamePunishmentCount(historyTypeEnum, userTypeEnum, user);
|
||||||
|
searchResultCountCompletableFuture.complete(punishmentCount);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to load history count", e);
|
||||||
|
searchResultCountCompletableFuture.completeExceptionally(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ResponseEntity.ok().body(searchResultCountCompletableFuture.join());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Integer> getTotalResultsForUuidSearch(String userType, String type, String uuid) {
|
||||||
|
UserType userTypeEnum = UserType.getUserType(userType);
|
||||||
|
HistoryType historyTypeEnum = HistoryType.getHistoryType(type);
|
||||||
|
CompletableFuture<Integer> searchResultCountCompletableFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
|
Connection.getConnection(Databases.LITE_BANS)
|
||||||
|
.runQuery(sqlSession -> {
|
||||||
|
log.debug("Loading uuid search result count");
|
||||||
|
try {
|
||||||
|
Integer punishmentCount = sqlSession.getMapper(HistoryCountMapper.class)
|
||||||
|
.getUuidPunishmentCount(historyTypeEnum, userTypeEnum, UUID.fromString(uuid));
|
||||||
|
searchResultCountCompletableFuture.complete(punishmentCount);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to load history count", e);
|
||||||
|
searchResultCountCompletableFuture.completeExceptionally(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ResponseEntity.ok().body(searchResultCountCompletableFuture.join());
|
||||||
|
}
|
||||||
|
|
||||||
private ResponseEntity<HistoryCountDto> mapHistoryCount(HistoryCount historyCount) {
|
private ResponseEntity<HistoryCountDto> mapHistoryCount(HistoryCount historyCount) {
|
||||||
HistoryCountDto historyCountDto = new HistoryCountDto();
|
HistoryCountDto historyCountDto = new HistoryCountDto();
|
||||||
historyCountDto.setBans(historyCount.getBans());
|
historyCountDto.setBans(historyCount.getBans());
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
package com.alttd.altitudeweb.database.litebans;
|
package com.alttd.altitudeweb.database.litebans;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public interface HistoryCountMapper {
|
public interface HistoryCountMapper {
|
||||||
/**
|
/**
|
||||||
* Gets the total count of punishments from all LiteBans tables.
|
* Gets the total count of punishments from all LiteBans tables.
|
||||||
|
|
@ -17,4 +22,76 @@ public interface HistoryCountMapper {
|
||||||
"""
|
"""
|
||||||
})
|
})
|
||||||
HistoryCount getPunishmentCounts();
|
HistoryCount getPunishmentCounts();
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM (SELECT punishment.uuid, user_lookup.name AS punished_name
|
||||||
|
FROM all_punishments AS punishment
|
||||||
|
JOIN user_lookup ON user_lookup.uuid = punishment.uuid
|
||||||
|
WHERE user_lookup.name LIKE #{partialName}
|
||||||
|
AND type IN (${typeList})) AS punishment
|
||||||
|
""")
|
||||||
|
Integer getPlayerNamePunishmentCount(@Param("typeList") String typeList,
|
||||||
|
@Param("partialName") String partialName);
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
SELECT COUNT(*) AS punishment_count
|
||||||
|
FROM (SELECT uuid, banned_by_name
|
||||||
|
FROM all_punishments
|
||||||
|
WHERE banned_by_name LIKE #{partialName}
|
||||||
|
AND type IN (${typeList})) AS punishment
|
||||||
|
""")
|
||||||
|
Integer getStaffNamePunishmentCount(@Param("typeList") String typeList,
|
||||||
|
@Param("partialName") String partialName);
|
||||||
|
|
||||||
|
default Integer getNamePunishmentCount(HistoryType historyTypeEnum, UserType userTypeEnum, String partialName) {
|
||||||
|
final String searchName = partialName.toLowerCase().replace("_", "\\_") + "%";
|
||||||
|
String[] historyType = getHistoryType(historyTypeEnum);
|
||||||
|
String historyTypeSqlList = Arrays.stream(historyType)
|
||||||
|
.map(type -> "'" + type + "'")
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
return switch (userTypeEnum) {
|
||||||
|
case PLAYER -> getPlayerNamePunishmentCount(historyTypeSqlList, searchName);
|
||||||
|
case STAFF -> getStaffNamePunishmentCount(historyTypeSqlList, searchName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
SELECT COUNT(*) AS punishment_count
|
||||||
|
FROM all_punishments
|
||||||
|
WHERE uuid = #{uuid}
|
||||||
|
AND type IN (${typeList})
|
||||||
|
""")
|
||||||
|
Integer getPlayerUuidPunishmentCount(@Param("typeList") String typeList,
|
||||||
|
@Param("uuid") String uuid);
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
SELECT COUNT(*) AS punishment_count
|
||||||
|
FROM all_punishments
|
||||||
|
WHERE banned_by_uuid = #{uuid}
|
||||||
|
AND type IN (${typeList})
|
||||||
|
""")
|
||||||
|
Integer getStaffUuidPunishmentCount(@Param("typeList") String typeList,
|
||||||
|
@Param("uuid") String uuid);
|
||||||
|
|
||||||
|
default Integer getUuidPunishmentCount(HistoryType historyTypeEnum, UserType userTypeEnum, UUID uuid) {
|
||||||
|
String[] historyType = getHistoryType(historyTypeEnum);
|
||||||
|
String historyTypeSqlList = Arrays.stream(historyType)
|
||||||
|
.map(type -> "'" + type + "'")
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
return switch (userTypeEnum) {
|
||||||
|
case PLAYER -> getPlayerUuidPunishmentCount(historyTypeSqlList, uuid.toString());
|
||||||
|
case STAFF -> getStaffUuidPunishmentCount(historyTypeSqlList, uuid.toString());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getHistoryType(HistoryType historyTypeEnum) {
|
||||||
|
return switch (historyTypeEnum) {
|
||||||
|
case ALL -> new String[]{"ban", "mute", "warn"};
|
||||||
|
case BAN -> new String[]{"ban"};
|
||||||
|
case MUTE -> new String[]{"mute"};
|
||||||
|
case KICK -> new String[]{"kick"};
|
||||||
|
case WARN -> new String[]{"warn"};
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import {HistoryComponent} from './history/history.component';
|
||||||
import {HistoryCount, HistoryService} from '../../api';
|
import {HistoryCount, HistoryService} from '../../api';
|
||||||
import {NgClass, NgForOf, NgIf} from '@angular/common';
|
import {NgClass, NgForOf, NgIf} from '@angular/common';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {catchError, map, Observable} from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-bans',
|
selector: 'app-bans',
|
||||||
|
|
@ -20,18 +21,14 @@ import {FormsModule} from '@angular/forms';
|
||||||
})
|
})
|
||||||
export class BansComponent implements OnInit {
|
export class BansComponent implements OnInit {
|
||||||
|
|
||||||
private PAGE_SIZE: number = 10;
|
|
||||||
|
|
||||||
public getCurrentButtonId(options: 'all' | 'ban' | 'mute' | 'kick' | 'warn') {
|
|
||||||
if (options == this.punishmentType) {
|
|
||||||
return 'currentButton'
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(public historyApi: HistoryService) {
|
constructor(public historyApi: HistoryService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PAGE_SIZE: number = 10;
|
||||||
|
private uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
||||||
|
private actualPage: number = 0;
|
||||||
|
private totalSearchResults: number = -1;
|
||||||
|
|
||||||
public active: string = '';
|
public active: string = '';
|
||||||
public userType: 'player' | 'staff' = "player";
|
public userType: 'player' | 'staff' = "player";
|
||||||
public punishmentType: 'all' | 'ban' | 'mute' | 'kick' | 'warn' = "all";
|
public punishmentType: 'all' | 'ban' | 'mute' | 'kick' | 'warn' = "all";
|
||||||
|
|
@ -47,7 +44,6 @@ export class BansComponent implements OnInit {
|
||||||
kicks: 0,
|
kicks: 0,
|
||||||
warnings: 0
|
warnings: 0
|
||||||
}
|
}
|
||||||
private actualPage: number = 0;
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.historyApi.getUserNames(this.userType, this.punishmentType).subscribe(names => {
|
this.historyApi.getUserNames(this.userType, this.punishmentType).subscribe(names => {
|
||||||
|
|
@ -71,6 +67,13 @@ export class BansComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCurrentButtonId(options: 'all' | 'ban' | 'mute' | 'kick' | 'warn') {
|
||||||
|
if (options == this.punishmentType) {
|
||||||
|
return 'currentButton'
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public filterNames() {
|
public filterNames() {
|
||||||
if (!this.searchTerm) {
|
if (!this.searchTerm) {
|
||||||
this.filteredNames = [];
|
this.filteredNames = [];
|
||||||
|
|
@ -91,6 +94,26 @@ export class BansComponent implements OnInit {
|
||||||
this.pushState()
|
this.pushState()
|
||||||
this.finalSearchTerm = this.searchTerm;
|
this.finalSearchTerm = this.searchTerm;
|
||||||
this.page = 0;
|
this.page = 0;
|
||||||
|
if (this.finalSearchTerm.length === 0) {
|
||||||
|
this.totalSearchResults = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let totalSearchResultsObservable: Observable<number>;
|
||||||
|
if (this.uuidRegex.test(this.finalSearchTerm)) {
|
||||||
|
totalSearchResultsObservable = this.historyApi.getTotalResultsForUuidSearch(this.userType, this.punishmentType, this.finalSearchTerm);
|
||||||
|
} else {
|
||||||
|
totalSearchResultsObservable = this.historyApi.getTotalResultsForUserSearch(this.userType, this.punishmentType, this.finalSearchTerm);
|
||||||
|
}
|
||||||
|
totalSearchResultsObservable.pipe(
|
||||||
|
map(totalSearchResults => {
|
||||||
|
this.totalSearchResults = totalSearchResults;
|
||||||
|
}),
|
||||||
|
catchError(err => {
|
||||||
|
console.error(err);
|
||||||
|
return [];
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public changeHistoryType(type: 'player' | 'staff') {
|
public changeHistoryType(type: 'player' | 'staff') {
|
||||||
|
|
@ -142,17 +165,20 @@ export class BansComponent implements OnInit {
|
||||||
|
|
||||||
public getMaxPage() {
|
public getMaxPage() {
|
||||||
const all = this.historyCount.bans + this.historyCount.mutes + this.historyCount.warnings;
|
const all = this.historyCount.bans + this.historyCount.mutes + this.historyCount.warnings;
|
||||||
|
if (this.finalSearchTerm.length !== 0) {
|
||||||
|
return Math.floor(this.totalSearchResults / this.PAGE_SIZE);
|
||||||
|
}
|
||||||
switch (this.punishmentType) {
|
switch (this.punishmentType) {
|
||||||
case 'all':
|
case 'all':
|
||||||
return Math.floor(all / this.PAGE_SIZE) - 1;
|
return Math.floor(all / this.PAGE_SIZE);
|
||||||
case 'ban':
|
case 'ban':
|
||||||
return Math.floor(this.historyCount.bans / this.PAGE_SIZE) - 1;
|
return Math.floor(this.historyCount.bans / this.PAGE_SIZE);
|
||||||
case 'mute':
|
case 'mute':
|
||||||
return Math.floor(this.historyCount.mutes / this.PAGE_SIZE) - 1;
|
return Math.floor(this.historyCount.mutes / this.PAGE_SIZE);
|
||||||
case 'kick':
|
case 'kick':
|
||||||
return Math.floor(this.historyCount.kicks / this.PAGE_SIZE) - 1;
|
return Math.floor(this.historyCount.kicks / this.PAGE_SIZE);
|
||||||
case 'warn':
|
case 'warn':
|
||||||
return Math.floor(this.historyCount.warnings / this.PAGE_SIZE) - 1;
|
return Math.floor(this.historyCount.warnings / this.PAGE_SIZE);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ export class HistoryComponent implements OnInit, OnChanges {
|
||||||
if (this.uuidRegex.test(this.searchTerm)) {
|
if (this.uuidRegex.test(this.searchTerm)) {
|
||||||
historyObservable = this.historyApi.getHistoryForUuid(this.userType, this.punishmentType, this.searchTerm, this.page);
|
historyObservable = this.historyApi.getHistoryForUuid(this.userType, this.punishmentType, this.searchTerm, this.page);
|
||||||
} else {
|
} else {
|
||||||
historyObservable = this.historyApi.getHistoryForUsers(this.userType, this.punishmentType, this.searchTerm, this.page)
|
historyObservable = this.historyApi.getHistoryForUsers(this.userType, this.punishmentType, this.searchTerm, this.page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyObservable.pipe(
|
historyObservable.pipe(
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ paths:
|
||||||
$ref: './schemas/bans/bans.yml#/getHistoryForAll'
|
$ref: './schemas/bans/bans.yml#/getHistoryForAll'
|
||||||
/history/{userType}/uuid/{type}/{uuid}/{page}:
|
/history/{userType}/uuid/{type}/{uuid}/{page}:
|
||||||
$ref: './schemas/bans/bans.yml#/getHistoryForUuid'
|
$ref: './schemas/bans/bans.yml#/getHistoryForUuid'
|
||||||
|
/history/{userType}/search-results/uuid/{type}/{uuid}:
|
||||||
|
$ref: './schemas/bans/bans.yml#/getTotalResultsForUuidSearch'
|
||||||
|
/history/{userType}/search-results/user/{type}/{user}:
|
||||||
|
$ref: './schemas/bans/bans.yml#/getTotalResultsForUserSearch'
|
||||||
/history/total:
|
/history/total:
|
||||||
$ref: './schemas/bans/bans.yml#/getTotalPunishments'
|
$ref: './schemas/bans/bans.yml#/getTotalPunishments'
|
||||||
/appeal/update-mail:
|
/appeal/update-mail:
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,54 @@ getTotalPunishments:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '../generic/errors.yml#/components/schemas/ApiError'
|
$ref: '../generic/errors.yml#/components/schemas/ApiError'
|
||||||
|
getTotalResultsForUserSearch:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- history
|
||||||
|
summary: Gets total results for search query
|
||||||
|
description: Retrieves the total count of punishments for the search query
|
||||||
|
operationId: getTotalResultsForUserSearch
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/UserType'
|
||||||
|
- $ref: '#/components/parameters/HistoryType'
|
||||||
|
- $ref: '#/components/parameters/User'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SearchResults'
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '../generic/errors.yml#/components/schemas/ApiError'
|
||||||
|
getTotalResultsForUuidSearch:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- history
|
||||||
|
summary: Gets total results for search query
|
||||||
|
description: Retrieves the total count of punishments for the search query
|
||||||
|
operationId: getTotalResultsForUuidSearch
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/UserType'
|
||||||
|
- $ref: '#/components/parameters/HistoryType'
|
||||||
|
- $ref: '#/components/parameters/Uuid'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SearchResults'
|
||||||
|
default:
|
||||||
|
description: Unexpected error
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '../generic/errors.yml#/components/schemas/ApiError'
|
||||||
components:
|
components:
|
||||||
parameters:
|
parameters:
|
||||||
HistoryType:
|
HistoryType:
|
||||||
|
|
@ -164,6 +212,9 @@ components:
|
||||||
type: integer
|
type: integer
|
||||||
description: The page that should be retrieved
|
description: The page that should be retrieved
|
||||||
schemas:
|
schemas:
|
||||||
|
SearchResults:
|
||||||
|
type: integer
|
||||||
|
description: A number representing the total count of results for the search query
|
||||||
PunishmentHistory:
|
PunishmentHistory:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user