Added logic to make achievement config more generic #268_achievements
This commit is contained in:
parent
51928dcb4d
commit
0ec67d41e2
@ -1,3 +1,8 @@
|
|||||||
|
type AchievementAttribute {
|
||||||
|
name: String
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
|
||||||
type Achievement implements TableWithHistoryQuery {
|
type Achievement implements TableWithHistoryQuery {
|
||||||
id: ID
|
id: ID
|
||||||
name: String
|
name: String
|
||||||
|
@ -31,6 +31,8 @@ type Query {
|
|||||||
|
|
||||||
achievementCount: Int
|
achievementCount: Int
|
||||||
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
|
||||||
|
AchievementAttributes: [AchievementAttribute]
|
||||||
|
AchievementOperators: [String]
|
||||||
|
|
||||||
guilds(filter: GuildFilter): [Guild]
|
guilds(filter: GuildFilter): [Guild]
|
||||||
}
|
}
|
@ -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)
|
@ -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_game_server_filter import UserJoinedGameServerFilter
|
||||||
from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
from bot_graphql.filter.user_joined_server_filter import UserJoinedServerFilter
|
||||||
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
from bot_graphql.filter.user_joined_voice_channel_filter import UserJoinedVoiceChannelFilter
|
||||||
|
from modules.achievements.achievement_service import AchievementService
|
||||||
|
|
||||||
|
|
||||||
class Query(QueryABC):
|
class Query(QueryABC):
|
||||||
@ -37,6 +38,7 @@ class Query(QueryABC):
|
|||||||
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
user_joined_game_server: UserJoinedGameServerRepositoryABC,
|
||||||
users: UserRepositoryABC,
|
users: UserRepositoryABC,
|
||||||
achievements: AchievementRepositoryABC,
|
achievements: AchievementRepositoryABC,
|
||||||
|
achievement_service: AchievementService,
|
||||||
):
|
):
|
||||||
QueryABC.__init__(self, "Query")
|
QueryABC.__init__(self, "Query")
|
||||||
|
|
||||||
@ -65,6 +67,8 @@ class Query(QueryABC):
|
|||||||
self.add_collection("achievement", lambda *_: achievements.get_achievements(), AchievementFilter)
|
self.add_collection("achievement", lambda *_: achievements.get_achievements(), AchievementFilter)
|
||||||
|
|
||||||
self.set_field("guilds", self._resolve_guilds)
|
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):
|
def _resolve_guilds(self, *_, filter=None):
|
||||||
if filter is None or "id" not in filter:
|
if filter is None or "id" not in filter:
|
||||||
|
@ -2,6 +2,7 @@ from cpl_core.configuration import ConfigurationABC
|
|||||||
from cpl_core.database.context import DatabaseContextABC
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
from cpl_core.logging import LoggerABC
|
from cpl_core.logging import LoggerABC
|
||||||
from cpl_discord.service import DiscordBotServiceABC
|
from cpl_discord.service import DiscordBotServiceABC
|
||||||
|
from cpl_query.extension import List
|
||||||
from cpl_translation import TranslatePipe
|
from cpl_translation import TranslatePipe
|
||||||
|
|
||||||
from bot_core.configuration.server_settings import ServerSettings
|
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.achievement import Achievement
|
||||||
from bot_data.model.user import User
|
from bot_data.model.user import User
|
||||||
from bot_data.model.user_got_achievement import UserGotAchievement
|
from bot_data.model.user_got_achievement import UserGotAchievement
|
||||||
|
from modules.achievements.model.achievement_attribute import AchievementAttribute
|
||||||
|
|
||||||
|
|
||||||
class AchievementService:
|
class AchievementService:
|
||||||
@ -31,6 +33,17 @@ class AchievementService:
|
|||||||
self._message_service = message_service
|
self._message_service = message_service
|
||||||
self._t = t
|
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:
|
def _match(self, value: str, operator: str, expected_value: str) -> bool:
|
||||||
match operator:
|
match operator:
|
||||||
case "==":
|
case "==":
|
||||||
|
1
kdb-bot/src/modules/achievements/model/__init__.py
Normal file
1
kdb-bot/src/modules/achievements/model/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# imports
|
@ -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)
|
@ -1,10 +1,15 @@
|
|||||||
import { DataWithHistory } from "./data.model";
|
import { DataWithHistory } from "./data.model";
|
||||||
import { Server, ServerFilter } from "./server.model";
|
import { Server, ServerFilter } from "./server.model";
|
||||||
|
|
||||||
|
export interface AchievementAttribute {
|
||||||
|
name?: string;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Achievement extends DataWithHistory {
|
export interface Achievement extends DataWithHistory {
|
||||||
id?: number;
|
id?: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
attribute?: string;
|
attribute?: string | AchievementAttribute;
|
||||||
operator?: string;
|
operator?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
server?: Server;
|
server?: Server;
|
||||||
|
@ -90,6 +90,16 @@ export class Queries {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
static achievementTypeQuery = `
|
||||||
|
query AchievementType {
|
||||||
|
AchievementOperators
|
||||||
|
AchievementAttributes {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
static achievementQuery = `
|
static achievementQuery = `
|
||||||
query AchievementList($serverId: ID, $filter: AchievementFilter, $page: Page, $sort: Sort) {
|
query AchievementList($serverId: ID, $filter: AchievementFilter, $page: Page, $sort: Sort) {
|
||||||
servers(filter: {id: $serverId}) {
|
servers(filter: {id: $serverId}) {
|
||||||
|
@ -3,7 +3,7 @@ import { User } from "../data/user.model";
|
|||||||
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
import { AutoRole, AutoRoleRule } from "../data/auto_role.model";
|
||||||
import { Guild } from "../data/discord.model";
|
import { Guild } from "../data/discord.model";
|
||||||
import { Level } from "../data/level.model";
|
import { Level } from "../data/level.model";
|
||||||
import { Achievement } from "../data/achievement.model";
|
import { Achievement, AchievementAttribute } from "../data/achievement.model";
|
||||||
|
|
||||||
export interface Query {
|
export interface Query {
|
||||||
serverCount: number;
|
serverCount: number;
|
||||||
@ -24,6 +24,11 @@ export interface LevelListQuery {
|
|||||||
levels: Level[];
|
levels: Level[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AchievementTypeQuery {
|
||||||
|
AchievementAttributes: AchievementAttribute[];
|
||||||
|
AchievementOperators: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface AchievementListQuery {
|
export interface AchievementListQuery {
|
||||||
achievementCount: number;
|
achievementCount: number;
|
||||||
achievements: Achievement[];
|
achievements: Achievement[];
|
||||||
|
@ -132,7 +132,8 @@
|
|||||||
<td>
|
<td>
|
||||||
<p-cellEditor>
|
<p-cellEditor>
|
||||||
<ng-template pTemplate="input">
|
<ng-template pTemplate="input">
|
||||||
<p-dropdown [options]="attributes" [(ngModel)]="achievement.attribute" placeholder="{{'view.server.achievements.headers.attribute' | translate}}"></p-dropdown>
|
<p-dropdown [options]="attributes" [(ngModel)]="achievement.attribute"
|
||||||
|
placeholder="{{'view.server.achievements.headers.attribute' | translate}}"></p-dropdown>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="output">
|
<ng-template pTemplate="output">
|
||||||
{{achievement.attribute}}
|
{{achievement.attribute}}
|
||||||
@ -152,9 +153,18 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<p-cellEditor>
|
<p-cellEditor *ngIf="getAchievementAttributeByName(achievement.attribute).type === 'number'">
|
||||||
<ng-template pTemplate="input">
|
<ng-template pTemplate="input">
|
||||||
<input class="table-edit-input" pInputText min="0" type="text" [(ngModel)]="achievement.value">
|
<input class="table-edit-input" pInputText min="0" type="number" [(ngModel)]="achievement.value">
|
||||||
|
</ng-template>
|
||||||
|
<ng-template pTemplate="output">
|
||||||
|
{{achievement.value}}
|
||||||
|
</ng-template>
|
||||||
|
</p-cellEditor>
|
||||||
|
|
||||||
|
<p-cellEditor *ngIf="getAchievementAttributeByName(achievement.attribute).type === 'Level'">
|
||||||
|
<ng-template pTemplate="input">
|
||||||
|
<p-dropdown [options]="levels" [(ngModel)]="achievement.value" placeholder="{{'view.server.members.headers.level' | translate}}"></p-dropdown>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="output">
|
<ng-template pTemplate="output">
|
||||||
{{achievement.value}}
|
{{achievement.value}}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
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 { FormBuilder, FormControl, FormGroup } from "@angular/forms";
|
||||||
import { Page } from "../../../../../../models/graphql/filter/page.model";
|
import { Page } from "../../../../../../models/graphql/filter/page.model";
|
||||||
import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.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 { DataService } from "../../../../../../services/data/data.service";
|
||||||
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
||||||
import { ActivatedRoute } from "@angular/router";
|
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 { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
||||||
import { LazyLoadEvent } from "primeng/api";
|
import { LazyLoadEvent, MenuItem } from "primeng/api";
|
||||||
import { Table } from "primeng/table";
|
import { Table } from "primeng/table";
|
||||||
import { User } from "../../../../../../models/data/user.model";
|
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";
|
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -60,8 +60,10 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
private server: Server = {};
|
private server: Server = {};
|
||||||
public user: UserDTO | null = null;
|
public user: UserDTO | null = null;
|
||||||
|
|
||||||
public operators = ["==", "!=", "<=", ">=", "<", ">"];
|
public operators: string[] = [];
|
||||||
public attributes = ["xp", "message_count", "reaction_count", "ontime", "level"]
|
public attributes: MenuItem[] = [];
|
||||||
|
private achievementsAttributes: AchievementAttribute[] = [];
|
||||||
|
levels!: MenuItem[];
|
||||||
|
|
||||||
query: string = Queries.achievementWithHistoryQuery;
|
query: string = Queries.achievementWithHistoryQuery;
|
||||||
|
|
||||||
@ -78,10 +80,10 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
|
this.loading = true;
|
||||||
this.setFilterForm();
|
this.setFilterForm();
|
||||||
this.data.getServerFromRoute(this.route).then(async server => {
|
this.data.getServerFromRoute(this.route).then(async server => {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.loadNextPage();
|
|
||||||
let authUser = await this.authService.getLoggedInUser();
|
let authUser = await this.authService.getLoggedInUser();
|
||||||
this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null;
|
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();
|
this.unsubscriber.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadNextPage(): void {
|
|
||||||
this.loading = true;
|
private loadLevels() {
|
||||||
|
this.data.query<LevelListQuery>(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<AchievementListQuery>(Queries.achievementQuery, {
|
this.data.query<AchievementListQuery>(Queries.achievementQuery, {
|
||||||
serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort
|
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<AchievementTypeQuery>(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 {
|
public setFilterForm(): void {
|
||||||
this.filterForm = this.fb.group({
|
this.filterForm = this.fb.group({
|
||||||
id: new FormControl<number | null>(null),
|
id: new FormControl<number | null>(null),
|
||||||
@ -184,7 +213,7 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
name: newAchievement.name,
|
name: newAchievement.name,
|
||||||
attribute: newAchievement.attribute,
|
attribute: newAchievement.attribute,
|
||||||
operator: newAchievement.operator,
|
operator: newAchievement.operator,
|
||||||
value: newAchievement.value,
|
value: newAchievement.value + "",
|
||||||
serverId: this.server.id
|
serverId: this.server.id
|
||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
@ -207,7 +236,7 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
name: newAchievement.name,
|
name: newAchievement.name,
|
||||||
attribute: newAchievement.attribute,
|
attribute: newAchievement.attribute,
|
||||||
operator: newAchievement.operator,
|
operator: newAchievement.operator,
|
||||||
value: newAchievement.value
|
value: newAchievement.value + ""
|
||||||
}
|
}
|
||||||
).pipe(catchError(err => {
|
).pipe(catchError(err => {
|
||||||
this.spinner.hideSpinner();
|
this.spinner.hideSpinner();
|
||||||
@ -268,4 +297,9 @@ export class AchievementComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.isEditingNew = true;
|
this.isEditingNew = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAchievementAttributeByName(name: string): AchievementAttribute {
|
||||||
|
const [found] = this.achievementsAttributes.filter(x => x.name === name);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user