Cleaning up advanced search

This commit is contained in:
nise.moe 2024-02-24 18:59:55 +01:00
parent f182284f60
commit 79557b170a
3 changed files with 93 additions and 83 deletions

View File

@ -5,19 +5,10 @@ import com.nisemoe.generated.tables.references.SCORES
import com.nisemoe.generated.tables.references.USERS import com.nisemoe.generated.tables.references.USERS
import com.nisemoe.nise.Format import com.nisemoe.nise.Format
import com.nisemoe.nise.service.AuthService import com.nisemoe.nise.service.AuthService
import org.jooq.Condition import org.jooq.*
import org.jooq.DSLContext
import org.jooq.Field
import org.jooq.OrderField
import org.jooq.Record
import org.jooq.Result
import org.jooq.impl.DSL import org.jooq.impl.DSL
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RestController
import kotlin.math.roundToInt import kotlin.math.roundToInt
@RestController @RestController
@ -144,6 +135,18 @@ class SearchController(
val type: String val type: String
) )
data class InternalSchemaField(
val name: String,
val shortName: String,
val category: Category,
val type: Type,
val active: Boolean,
val description: String,
val isPrivileged: Boolean = false,
val databaseField: Field<*>? = null
)
data class SchemaField( data class SchemaField(
val name: String, val name: String,
val shortName: String, val shortName: String,
@ -169,68 +172,89 @@ class SearchController(
@GetMapping("search") @GetMapping("search")
fun getSearchSchema(): ResponseEntity<SearchSchema> { fun getSearchSchema(): ResponseEntity<SearchSchema> {
val fields = listOf( val internalFields = listOf(
// User fields // User fields
SchemaField("user_id", "ID", Category.user, Type.number, false, "unique identifier for a user"), InternalSchemaField("user_id", "ID", Category.user, Type.number, false, "unique identifier for a user"),
SchemaField("user_username", "Username", Category.user, Type.string, true, "user's name"), InternalSchemaField("user_username", "Username", Category.user, Type.string, true, "user's name"),
SchemaField("user_join_date", "Join Date", Category.user, Type.string, false, "when the user joined"), InternalSchemaField("user_join_date", "Join Date", Category.user, Type.string, false, "when the user joined"),
SchemaField("user_country", "Country", Category.user, Type.flag, true, "user's country flag"), InternalSchemaField("user_country", "Country", Category.user, Type.flag, true, "user's country flag"),
SchemaField("user_country_rank", "Country Rank", Category.user, Type.number, false, "ranking within user's country"), InternalSchemaField("user_country_rank", "Country Rank", Category.user, Type.number, false, "ranking within user's country"),
SchemaField("user_rank", "Rank", Category.user, Type.number, false, "global ranking"), InternalSchemaField("user_rank", "Rank", Category.user, Type.number, false, "global ranking"),
SchemaField("user_pp_raw", "User PP", Category.user, Type.number, false, "performance points"), InternalSchemaField("user_pp_raw", "User PP", Category.user, Type.number, false, "performance points"),
SchemaField("user_accuracy", "User Accuracy", Category.user, Type.number, false, "hit accuracy percentage"), InternalSchemaField("user_accuracy", "User Accuracy", Category.user, Type.number, false, "hit accuracy percentage"),
SchemaField("user_playcount", "Playcount", Category.user, Type.number, false, "total plays"), InternalSchemaField("user_playcount", "Playcount", Category.user, Type.number, false, "total plays"),
SchemaField("user_total_score", "Total Score", Category.user, Type.number, false, "cumulative score"), InternalSchemaField("user_total_score", "Total Score", Category.user, Type.number, false, "cumulative score"),
SchemaField("user_ranked_score", "Ranked Score", Category.user, Type.number, false, "score from ranked maps"), InternalSchemaField("user_ranked_score", "Ranked Score", Category.user, Type.number, false, "score from ranked maps"),
SchemaField("user_seconds_played", "Play Time", Category.user, Type.number, false, "total play time in seconds"), InternalSchemaField("user_seconds_played", "Play Time", Category.user, Type.number, false, "total play time in seconds"),
SchemaField("user_count_300", "300s", Category.user, Type.number, false, "number of 300 hits"), InternalSchemaField("user_count_300", "300s", Category.user, Type.number, false, "number of 300 hits"),
SchemaField("user_count_100", "100s", Category.user, Type.number, false, "number of 100 hits"), InternalSchemaField("user_count_100", "100s", Category.user, Type.number, false, "number of 100 hits"),
SchemaField("user_count_50", "50s", Category.user, Type.number, false, "number of 50 hits"), InternalSchemaField("user_count_50", "50s", Category.user, Type.number, false, "number of 50 hits"),
SchemaField("user_count_miss", "Misses", Category.user, Type.number, false, "missed hits"), InternalSchemaField("user_count_miss", "Misses", Category.user, Type.number, false, "missed hits"),
// Score fields // Score fields
SchemaField("id", "ID", Category.score, Type.number, false, "unique identifier for a score"), InternalSchemaField("id", "ID", Category.score, Type.number, false, "unique identifier for a score"),
SchemaField("beatmap_id", "Beatmap ID", Category.score, Type.number, false, "identifies the beatmap"), InternalSchemaField("beatmap_id", "Beatmap ID", Category.score, Type.number, false, "identifies the beatmap"),
SchemaField("count_300", "300s", Category.score, Type.number, false, "number of 300 hits in score"), InternalSchemaField("count_300", "300s", Category.score, Type.number, false, "number of 300 hits in score"),
SchemaField("count_100", "100s", Category.score, Type.number, false, "number of 100 hits in score"), InternalSchemaField("count_100", "100s", Category.score, Type.number, false, "number of 100 hits in score"),
SchemaField("count_50", "50s", Category.score, Type.number, false, "number of 50 hits in score"), InternalSchemaField("count_50", "50s", Category.score, Type.number, false, "number of 50 hits in score"),
SchemaField("count_miss", "Misses", Category.score, Type.number, false, "missed hits in score"), InternalSchemaField("count_miss", "Misses", Category.score, Type.number, false, "missed hits in score"),
SchemaField("date", "Date", Category.score, Type.string, true, "when score was achieved"), InternalSchemaField("date", "Date", Category.score, Type.string, true, "when score was achieved"),
SchemaField("max_combo", "Max Combo", Category.score, Type.number, false, "highest combo in score"), InternalSchemaField("max_combo", "Max Combo", Category.score, Type.number, false, "highest combo in score"),
SchemaField("mods", "Mods", Category.score, Type.number, false, "game modifiers used"), InternalSchemaField("mods", "Mods", Category.score, Type.number, false, "game modifiers used"),
SchemaField("perfect", "Perfect", Category.score, Type.boolean, false, "if score is a full combo"), InternalSchemaField("perfect", "Perfect", Category.score, Type.boolean, false, "if score is a full combo"),
SchemaField("pp", "Score PP", Category.score, Type.number, true, "performance points for score"), InternalSchemaField("pp", "Score PP", Category.score, Type.number, true, "performance points for score"),
SchemaField("rank", "Rank", Category.score, Type.grade, false, "score grade"), InternalSchemaField("rank", "Rank", Category.score, Type.grade, false, "score grade"),
SchemaField("replay_id", "Replay ID", Category.score, Type.number, false, "identifier for replay"), InternalSchemaField("replay_id", "Replay ID", Category.score, Type.number, false, "identifier for replay"),
SchemaField("score", "Score", Category.score, Type.number, false, "score value"), InternalSchemaField("score", "Score", Category.score, Type.number, false, "score value"),
SchemaField("ur", "UR", Category.score, Type.number, false, "unstable rate"), InternalSchemaField("ur", "UR", Category.score, Type.number, false, "unstable rate"),
SchemaField("frametime", "Frame Time", Category.score, Type.number, false, "average frame time during play"), InternalSchemaField("frametime", "Frame Time", Category.score, Type.number, false, "average frame time during play"),
SchemaField("edge_hits", "Edge Hits", Category.score, Type.number, false, "hits at the edge of hit window"), InternalSchemaField("edge_hits", "Edge Hits", Category.score, Type.number, false, "hits at the edge of hit window"),
SchemaField("snaps", "Snaps", Category.score, Type.number, false, "rapid cursor movements"), InternalSchemaField("snaps", "Snaps", Category.score, Type.number, false, "rapid cursor movements"),
SchemaField("adjusted_ur", "Adj. UR", Category.score, Type.number, true, "adjusted unstable rate"), InternalSchemaField("adjusted_ur", "Adj. UR", Category.score, Type.number, true, "adjusted unstable rate"),
SchemaField("mean_error", "Mean Error", Category.score, Type.number, false, "average timing error"), InternalSchemaField("mean_error", "Mean Error", Category.score, Type.number, false, "average timing error"),
SchemaField("error_variance", "Error Var.", Category.score, Type.number, false, "variability of error in scores"), InternalSchemaField("error_variance", "Error Var.", Category.score, Type.number, false, "variability of error in scores"),
SchemaField("error_standard_deviation", "Error SD", Category.score, Type.number, false, "standard deviation of error"), InternalSchemaField("error_standard_deviation", "Error SD", Category.score, Type.number, false, "standard deviation of error"),
SchemaField("minimum_error", "Min Error", Category.score, Type.number, false, "smallest error recorded"), InternalSchemaField("minimum_error", "Min Error", Category.score, Type.number, false, "smallest error recorded"),
SchemaField("maximum_error", "Max Error", Category.score, Type.number, false, "largest error recorded"), InternalSchemaField("maximum_error", "Max Error", Category.score, Type.number, false, "largest error recorded"),
SchemaField("error_range", "Error Range", Category.score, Type.number, false, "range between min and max error"), InternalSchemaField("error_range", "Error Range", Category.score, Type.number, false, "range between min and max error"),
SchemaField("error_coefficient_of_variation", "Error CV", Category.score, Type.number, false, "relative variability of error"), InternalSchemaField("error_coefficient_of_variation", "Error CV", Category.score, Type.number, false, "relative variability of error"),
SchemaField("error_kurtosis", "Kurtosis", Category.score, Type.number, false, "peakedness of error distribution"), InternalSchemaField("error_kurtosis", "Kurtosis", Category.score, Type.number, false, "peakedness of error distribution"),
SchemaField("error_skewness", "Skewness", Category.score, Type.number, false, "asymmetry of error distribution"), InternalSchemaField("error_skewness", "Skewness", Category.score, Type.number, false, "asymmetry of error distribution"),
SchemaField("keypresses_median_adjusted", "KP Median Adj.", Category.score, Type.number, false, "median of adjusted keypresses"), InternalSchemaField("keypresses_median_adjusted", "KP Median Adj.", Category.score, Type.number, false, "median of adjusted keypresses", isPrivileged = true),
SchemaField("keypresses_standard_deviation_adjusted", "KP std. Adj.", Category.score, Type.number, false, "std. dev of adjusted keypresses"), InternalSchemaField("keypresses_standard_deviation_adjusted", "KP std. Adj.", Category.score, Type.number, false, "std. dev of adjusted keypresses", isPrivileged = true),
SchemaField("sliderend_release_median_adjusted", "Sliderend Median Adj.", Category.score, Type.number, false, "median of adjusted sliderend releases"), InternalSchemaField("sliderend_release_median_adjusted", "Sliderend Median Adj.", Category.score, Type.number, false, "median of adjusted sliderend releases", isPrivileged = true),
SchemaField("sliderend_release_standard_deviation_adjusted", "Sliderend std. Adj.", Category.score, Type.number, false, "std. dev of adjusted sliderend releases"), InternalSchemaField("sliderend_release_standard_deviation_adjusted", "Sliderend std. Adj.", Category.score, Type.number, false, "std. dev of adjusted sliderend releases", isPrivileged = true),
// Beatmap fields // Beatmap fields
SchemaField("beatmap_artist", "Artist", Category.beatmap, Type.string, false, "artist of the beatmap"), InternalSchemaField("beatmap_artist", "Artist", Category.beatmap, Type.string, false, "artist of the beatmap"),
SchemaField("beatmap_beatmapset_id", "Set ID", Category.beatmap, Type.number, false, "id of the beatmap set"), InternalSchemaField("beatmap_beatmapset_id", "Set ID", Category.beatmap, Type.number, false, "id of the beatmap set"),
SchemaField("beatmap_creator", "Creator", Category.beatmap, Type.string, false, "creator of the beatmap"), InternalSchemaField("beatmap_creator", "Creator", Category.beatmap, Type.string, false, "creator of the beatmap"),
SchemaField("beatmap_source", "Source", Category.beatmap, Type.string, false, "source of the beatmap music"), InternalSchemaField("beatmap_source", "Source", Category.beatmap, Type.string, false, "source of the beatmap music"),
SchemaField("beatmap_star_rating", "Stars", Category.beatmap, Type.number, false, "(★) difficulty rating of the beatmap"), InternalSchemaField("beatmap_star_rating", "Stars", Category.beatmap, Type.number, false, "(★) difficulty rating of the beatmap"),
SchemaField("beatmap_title", "Title", Category.beatmap, Type.string, false, "title of the beatmap"), InternalSchemaField("beatmap_title", "Title", Category.beatmap, Type.string, false, "title of the beatmap"),
SchemaField("beatmap_version", "Version", Category.beatmap, Type.string, false, "version or difficulty name of the beatmap") InternalSchemaField("beatmap_version", "Version", Category.beatmap, Type.string, false, "version or difficulty name of the beatmap")
) )
// Map to SchemaField
val isUserAdmin = authService.isAdmin()
val fields = internalFields
.filter {
return@filter !(it.isPrivileged && !isUserAdmin)
}
.map {
SchemaField(
name = it.name,
shortName = it.shortName,
category = it.category,
type = it.type,
active = it.active,
description = it.description
)
}
// Filter privileged fields
val schema = SearchSchema(fields) val schema = SearchSchema(fields)
return ResponseEntity.ok(schema) return ResponseEntity.ok(schema)
} }

View File

@ -112,12 +112,7 @@ export class SearchComponent implements OnInit {
queries: Query[] | null = null; queries: Query[] | null = null;
ngOnInit(): void { ngOnInit(): void {
this.httpClient.get<SchemaResponse>(`${environment.apiUrl}/search`,).subscribe({
this.localCacheService.fetchData<SchemaResponse>(
"search-schema",
`${environment.apiUrl}/search`,
60
).subscribe({
next: (response) => { next: (response) => {
this.fields = response.fields; this.fields = response.fields;
this.loadPreviousFromLocalStorage(); this.loadPreviousFromLocalStorage();

View File

@ -15,7 +15,6 @@ export class UserService {
currentUser: UserInfo | null = null; currentUser: UserInfo | null = null;
loginCallback: () => void = () => {}; loginCallback: () => void = () => {};
logoutCallback: () => void = () => {};
constructor(private httpClient: HttpClient) { constructor(private httpClient: HttpClient) {
this.currentUser = this.loadCurrentUserFromLocalStorage(); this.currentUser = this.loadCurrentUserFromLocalStorage();
@ -23,14 +22,6 @@ export class UserService {
.catch(reason => console.debug(reason)); .catch(reason => console.debug(reason));
} }
public doLogout(): void {
this.currentUser = null;
this.clearCurrentUserFromLocalStorage();
this.updateUser().then(
() => this.logoutCallback()
)
}
isUserLoggedIn(): boolean { isUserLoggedIn(): boolean {
return this.currentUser !== null; return this.currentUser !== null;
} }
@ -74,7 +65,7 @@ export class UserService {
} }
clearCurrentUserFromLocalStorage() { clearCurrentUserFromLocalStorage() {
localStorage.setItem('currentUser', ''); localStorage.removeItem('currentUser');
document.cookie = 'SESSION=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; document.cookie = 'SESSION=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
} }