From cd5b3b6523f11c6e55659e915ab35b3c7b47920a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Jul 2023 12:52:54 +0200 Subject: [PATCH] Added logic to make achievement config more generic #268_achievements --- kdb-bot/src/bot_graphql/model/achievement.gql | 5 ++ kdb-bot/src/bot_graphql/model/query.gql | 2 + .../queries/achievement_attribute_query.py | 11 ++++ kdb-bot/src/bot_graphql/query.py | 4 ++ .../achievements/achievement_service.py | 13 ++++ .../modules/achievements/model/__init__.py | 1 + .../model/achievement_attribute.py | 20 +++++++ .../src/app/models/data/achievement.model.ts | 7 ++- .../src/app/models/graphql/queries.model.ts | 10 ++++ kdb-web/src/app/models/graphql/query.model.ts | 7 ++- .../achievement/achievement.component.html | 16 ++++- .../achievement/achievement.component.ts | 60 +++++++++++++++---- 12 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 kdb-bot/src/bot_graphql/queries/achievement_attribute_query.py create mode 100644 kdb-bot/src/modules/achievements/model/__init__.py create mode 100644 kdb-bot/src/modules/achievements/model/achievement_attribute.py diff --git a/kdb-bot/src/bot_graphql/model/achievement.gql b/kdb-bot/src/bot_graphql/model/achievement.gql index 3a5f1328..ef124653 100644 --- a/kdb-bot/src/bot_graphql/model/achievement.gql +++ b/kdb-bot/src/bot_graphql/model/achievement.gql @@ -1,3 +1,8 @@ +type AchievementAttribute { + name: String + type: String +} + type Achievement implements TableWithHistoryQuery { id: ID name: String diff --git a/kdb-bot/src/bot_graphql/model/query.gql b/kdb-bot/src/bot_graphql/model/query.gql index 17d8634c..9f96dc61 100644 --- a/kdb-bot/src/bot_graphql/model/query.gql +++ b/kdb-bot/src/bot_graphql/model/query.gql @@ -31,6 +31,8 @@ type Query { achievementCount: Int achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement] + AchievementAttributes: [AchievementAttribute] + AchievementOperators: [String] guilds(filter: GuildFilter): [Guild] } \ No newline at end of file diff --git a/kdb-bot/src/bot_graphql/queries/achievement_attribute_query.py b/kdb-bot/src/bot_graphql/queries/achievement_attribute_query.py new file mode 100644 index 00000000..2884c32b --- /dev/null +++ b/kdb-bot/src/bot_graphql/queries/achievement_attribute_query.py @@ -0,0 +1,11 @@ +from bot_graphql.abc.data_query_abc import DataQueryABC + + +class AchievementQuery(DataQueryABC): + def __init__( + self, + ): + DataQueryABC.__init__(self, "AchievementAttribute") + + self.set_field("name", lambda x, *_: x.name) + self.set_field("type", lambda x, *_: x.type) diff --git a/kdb-bot/src/bot_graphql/query.py b/kdb-bot/src/bot_graphql/query.py index 976b1950..8f3562ea 100644 --- a/kdb-bot/src/bot_graphql/query.py +++ b/kdb-bot/src/bot_graphql/query.py @@ -21,6 +21,7 @@ from bot_graphql.filter.user_filter import UserFilter from bot_graphql.filter.user_joined_game_server_filter import UserJoinedGameServerFilter from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter +from modules.achievements.achievement_service import AchievementService class Query(QueryABC): @@ -37,6 +38,7 @@ class Query(QueryABC): user_joined_game_server: UserJoinedGameServerRepositoryABC, users: UserRepositoryABC, achievements: AchievementRepositoryABC, + achievement_service: AchievementService, ): QueryABC.__init__(self, "Query") @@ -65,6 +67,8 @@ class Query(QueryABC): self.add_collection("achievement", lambda *_: achievements.get_achievements(), AchievementFilter) self.set_field("guilds", self._resolve_guilds) + self.set_field("AchievementAttributes", lambda x, *_: achievement_service.get_attributes()) + self.set_field("AchievementOperators", lambda x, *_: ["==", "!=", "<=", ">=", "<", ">"]) def _resolve_guilds(self, *_, filter=None): if filter is None or "id" not in filter: diff --git a/kdb-bot/src/modules/achievements/achievement_service.py b/kdb-bot/src/modules/achievements/achievement_service.py index 73e5ffe2..f767ef87 100644 --- a/kdb-bot/src/modules/achievements/achievement_service.py +++ b/kdb-bot/src/modules/achievements/achievement_service.py @@ -2,6 +2,7 @@ from cpl_core.configuration import ConfigurationABC from cpl_core.database.context import DatabaseContextABC from cpl_core.logging import LoggerABC from cpl_discord.service import DiscordBotServiceABC +from cpl_query.extension import List from cpl_translation import TranslatePipe from bot_core.configuration.server_settings import ServerSettings @@ -10,6 +11,7 @@ from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC from bot_data.model.achievement import Achievement from bot_data.model.user import User from bot_data.model.user_got_achievement import UserGotAchievement +from modules.achievements.model.achievement_attribute import AchievementAttribute class AchievementService: @@ -31,6 +33,17 @@ class AchievementService: self._message_service = message_service self._t = t + def get_attributes(self) -> List[AchievementAttribute]: + attributes = List(AchievementAttribute) + + attributes.add(AchievementAttribute("xp", lambda user: user.xp, "number")) + attributes.add(AchievementAttribute("message_count", lambda user: user.message_count, "number")) + attributes.add(AchievementAttribute("reaction_count", lambda user: user.reaction_count, "number")) + attributes.add(AchievementAttribute("ontime", lambda user: user.ontime, "number")) + attributes.add(AchievementAttribute("level", lambda user: user.level, "Level")) + + return attributes + def _match(self, value: str, operator: str, expected_value: str) -> bool: match operator: case "==": diff --git a/kdb-bot/src/modules/achievements/model/__init__.py b/kdb-bot/src/modules/achievements/model/__init__.py new file mode 100644 index 00000000..425ab6c1 --- /dev/null +++ b/kdb-bot/src/modules/achievements/model/__init__.py @@ -0,0 +1 @@ +# imports diff --git a/kdb-bot/src/modules/achievements/model/achievement_attribute.py b/kdb-bot/src/modules/achievements/model/achievement_attribute.py new file mode 100644 index 00000000..c90d4722 --- /dev/null +++ b/kdb-bot/src/modules/achievements/model/achievement_attribute.py @@ -0,0 +1,20 @@ +from typing import Callable + + +class AchievementAttribute: + # frontend type = TypeScript types + def __init__(self, name: str, resolver: Callable, frontend_type: str): + self._name = name + self._resolver = resolver + self._frontend_type = frontend_type + + @property + def name(self) -> str: + return self._name + + @property + def type(self) -> str: + return self._frontend_type + + def resolve(self, *args, **kwargs): + return self._resolver(*args, **kwargs) diff --git a/kdb-web/src/app/models/data/achievement.model.ts b/kdb-web/src/app/models/data/achievement.model.ts index 0b1af096..23037847 100644 --- a/kdb-web/src/app/models/data/achievement.model.ts +++ b/kdb-web/src/app/models/data/achievement.model.ts @@ -1,10 +1,15 @@ import { DataWithHistory } from "./data.model"; import { Server, ServerFilter } from "./server.model"; +export interface AchievementAttribute { + name?: string; + type?: string; +} + export interface Achievement extends DataWithHistory { id?: number; name?: string; - attribute?: string; + attribute?: string | AchievementAttribute; operator?: string; value?: string; server?: Server; diff --git a/kdb-web/src/app/models/graphql/queries.model.ts b/kdb-web/src/app/models/graphql/queries.model.ts index df3cf125..dafb897e 100644 --- a/kdb-web/src/app/models/graphql/queries.model.ts +++ b/kdb-web/src/app/models/graphql/queries.model.ts @@ -90,6 +90,16 @@ export class Queries { } `; + static achievementTypeQuery = ` + query AchievementType { + AchievementOperators + AchievementAttributes { + name + type + } + } + `; + static achievementQuery = ` query AchievementList($serverId: ID, $filter: AchievementFilter, $page: Page, $sort: Sort) { servers(filter: {id: $serverId}) { diff --git a/kdb-web/src/app/models/graphql/query.model.ts b/kdb-web/src/app/models/graphql/query.model.ts index 60e1964d..fe7ba7f9 100644 --- a/kdb-web/src/app/models/graphql/query.model.ts +++ b/kdb-web/src/app/models/graphql/query.model.ts @@ -3,7 +3,7 @@ import { User } from "../data/user.model"; import { AutoRole, AutoRoleRule } from "../data/auto_role.model"; import { Guild } from "../data/discord.model"; import { Level } from "../data/level.model"; -import { Achievement } from "../data/achievement.model"; +import { Achievement, AchievementAttribute } from "../data/achievement.model"; export interface Query { serverCount: number; @@ -24,6 +24,11 @@ export interface LevelListQuery { levels: Level[]; } +export interface AchievementTypeQuery { + AchievementAttributes: AchievementAttribute[]; + AchievementOperators: string[]; +} + export interface AchievementListQuery { achievementCount: number; achievements: Achievement[]; diff --git a/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html b/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html index 2c080fd2..94b7e14a 100644 --- a/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html +++ b/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.html @@ -132,7 +132,8 @@ - + {{achievement.attribute}} @@ -152,9 +153,18 @@ - + - + + + + {{achievement.value}} + + + + + + {{achievement.value}} diff --git a/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts b/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts index 2836c8b7..3237048e 100644 --- a/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts +++ b/kdb-web/src/app/modules/view/server/achievements/components/achievement/achievement.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; -import { Achievement, AchievementFilter } from "../../../../../../models/data/achievement.model"; +import { Achievement, AchievementAttribute, AchievementFilter } from "../../../../../../models/data/achievement.model"; import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; import { Page } from "../../../../../../models/graphql/filter/page.model"; import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model"; @@ -15,12 +15,12 @@ import { TranslateService } from "@ngx-translate/core"; import { DataService } from "../../../../../../services/data/data.service"; import { SidebarService } from "../../../../../../services/sidebar/sidebar.service"; import { ActivatedRoute } from "@angular/router"; -import { AchievementListQuery, Query } from "../../../../../../models/graphql/query.model"; +import { AchievementListQuery, AchievementTypeQuery, LevelListQuery, Query } from "../../../../../../models/graphql/query.model"; import { catchError, debounceTime, takeUntil } from "rxjs/operators"; -import { LazyLoadEvent } from "primeng/api"; +import { LazyLoadEvent, MenuItem } from "primeng/api"; import { Table } from "primeng/table"; import { User } from "../../../../../../models/data/user.model"; -import { AchievementMutationResult, UpdateUserMutationResult } from "../../../../../../models/graphql/result.model"; +import { AchievementMutationResult } from "../../../../../../models/graphql/result.model"; import { Mutations } from "../../../../../../models/graphql/mutations.model"; @Component({ @@ -60,8 +60,10 @@ export class AchievementComponent implements OnInit, OnDestroy { private server: Server = {}; public user: UserDTO | null = null; - public operators = ["==", "!=", "<=", ">=", "<", ">"]; - public attributes = ["xp", "message_count", "reaction_count", "ontime", "level"] + public operators: string[] = []; + public attributes: MenuItem[] = []; + private achievementsAttributes: AchievementAttribute[] = []; + levels!: MenuItem[]; query: string = Queries.achievementWithHistoryQuery; @@ -78,10 +80,10 @@ export class AchievementComponent implements OnInit, OnDestroy { } public ngOnInit(): void { + this.loading = true; this.setFilterForm(); this.data.getServerFromRoute(this.route).then(async server => { this.server = server; - this.loadNextPage(); let authUser = await this.authService.getLoggedInUser(); this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null; }); @@ -92,8 +94,22 @@ export class AchievementComponent implements OnInit, OnDestroy { this.unsubscriber.complete(); } - public loadNextPage(): void { - this.loading = true; + + private loadLevels() { + this.data.query(Queries.levelQuery, { + serverId: this.server.id + }, + (data: Query) => { + return data.servers[0]; + } + ).subscribe(data => { + this.levels = data.levels.map(level => { + return { label: level.name, value: level.name }; + }); + }); + } + + private loadNextData() { this.data.query(Queries.achievementQuery, { serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort }, @@ -108,6 +124,19 @@ export class AchievementComponent implements OnInit, OnDestroy { }); } + public loadNextPage(): void { + this.data.query(Queries.achievementTypeQuery + ).subscribe(data => { + this.operators = data.AchievementOperators; + this.achievementsAttributes = data.AchievementAttributes; + this.attributes = data.AchievementAttributes.map(attribute => { + return { label: attribute.name, value: attribute.name }; + }); + this.loadLevels(); + this.loadNextData(); + }); + } + public setFilterForm(): void { this.filterForm = this.fb.group({ id: new FormControl(null), @@ -182,9 +211,9 @@ export class AchievementComponent implements OnInit, OnDestroy { this.spinner.showSpinner(); this.data.mutation(Mutations.createAchievement, { name: newAchievement.name, - attribute: newAchievement.attribute, - operator: newAchievement.operator, - value: newAchievement.value, + attribute: newAchievement.attribute, + operator: newAchievement.operator, + value: newAchievement.value + "", serverId: this.server.id } ).pipe(catchError(err => { @@ -207,7 +236,7 @@ export class AchievementComponent implements OnInit, OnDestroy { name: newAchievement.name, attribute: newAchievement.attribute, operator: newAchievement.operator, - value: newAchievement.value + value: newAchievement.value + "" } ).pipe(catchError(err => { this.spinner.hideSpinner(); @@ -268,4 +297,9 @@ export class AchievementComponent implements OnInit, OnDestroy { this.isEditingNew = true; } + + public getAchievementAttributeByName(name: string): AchievementAttribute { + const [found] = this.achievementsAttributes.filter(x => x.name === name); + return found; + } }