Added played_on_game_server achievement logic #268_achievements

This commit is contained in:
2023-07-15 14:42:01 +02:00
parent 3fb951a748
commit 189128f0d3
21 changed files with 188 additions and 27 deletions

View File

@@ -94,7 +94,10 @@
},
"modules": {
"achievements": {
"got_new_achievement": "{} hat die Errungenschaft {} freigeschaltet :D"
"got_new_achievement": "{} hat die Errungenschaft {} freigeschaltet :D",
"commands": {
"check": "Alles klar, ich schaue eben nach... nom nom"
}
},
"auto_role": {
"add": {

View File

@@ -22,7 +22,7 @@ class AchievementsMigration(MigrationABC):
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(255) NOT NULL,
`Attribute` VARCHAR(255) NOT NULL,
`Operator` VARCHAR(2) NOT NULL,
`Operator` VARCHAR(255) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
@@ -43,7 +43,7 @@ class AchievementsMigration(MigrationABC):
`ServerId` BIGINT,
`Name` VARCHAR(255) NOT NULL,
`Attribute` VARCHAR(255) NOT NULL,
`Operator` VARCHAR(2) NOT NULL,
`Operator` VARCHAR(255) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
`Deleted` BOOL DEFAULT FALSE,
`DateFrom` DATETIME(6) NOT NULL,

View File

@@ -2,6 +2,7 @@ from datetime import datetime
from typing import Optional
from cpl_core.database import TableABC
from cpl_core.dependency_injection import ServiceProviderABC
from bot_data.model.server import Server
@@ -22,8 +23,8 @@ class Achievement(TableABC):
self._name = name
self._attribute = attribute
if operator not in ["==", "!=", "<=", ">=", "<", ">"]:
raise ValueError("operator must be ==,!=,<=,>=,< or >")
if self._is_operator_valid(operator):
raise ValueError("Operator invalid")
self._operator = operator
self._value = value
@@ -33,6 +34,13 @@ class Achievement(TableABC):
self._created_at = created_at if created_at is not None else self._created_at
self._modified_at = modified_at if modified_at is not None else self._modified_at
@ServiceProviderABC.inject
def _is_operator_valid(self, operator, service: ServiceProviderABC) -> bool:
from modules.achievements.achievement_service import AchievementService
achievements: AchievementService = service.get_service(AchievementService)
return operator not in achievements.get_operators()
@property
def id(self) -> int:
return self._id

View File

@@ -26,6 +26,7 @@ from bot_graphql.mutations.auto_role_rule_mutation import AutoRoleRuleMutation
from bot_graphql.mutations.level_mutation import LevelMutation
from bot_graphql.mutations.user_joined_game_server_mutation import UserJoinedGameServerMutation
from bot_graphql.mutations.user_mutation import UserMutation
from bot_graphql.queries.achievement_attribute_query import AchievementAttributeQuery
from bot_graphql.queries.achievement_query import AchievementQuery
from bot_graphql.queries.auto_role_history_query import AutoRoleHistoryQuery
from bot_graphql.queries.auto_role_query import AutoRoleQuery
@@ -33,6 +34,7 @@ from bot_graphql.queries.auto_role_rule_history_query import AutoRoleRuleHistory
from bot_graphql.queries.auto_role_rule_query import AutoRoleRuleQuery
from bot_graphql.queries.client_history_query import ClientHistoryQuery
from bot_graphql.queries.client_query import ClientQuery
from bot_graphql.queries.game_server_query import GameServerQuery
from bot_graphql.queries.known_user_history_query import KnownUserHistoryQuery
from bot_graphql.queries.known_user_query import KnownUserQuery
from bot_graphql.queries.level_history_query import LevelHistoryQuery
@@ -65,6 +67,8 @@ class GraphQLModule(ModuleABC):
services.add_singleton(Mutation)
# queries
services.add_transient(QueryABC, AchievementAttributeQuery)
services.add_transient(QueryABC, AchievementQuery)
services.add_transient(QueryABC, AutoRoleHistoryQuery)
services.add_transient(QueryABC, AutoRoleQuery)
services.add_transient(QueryABC, AutoRoleRuleHistoryQuery)
@@ -77,9 +81,9 @@ class GraphQLModule(ModuleABC):
services.add_transient(QueryABC, LevelQuery)
services.add_transient(QueryABC, ServerHistoryQuery)
services.add_transient(QueryABC, ServerQuery)
services.add_transient(QueryABC, GameServerQuery)
services.add_transient(QueryABC, UserHistoryQuery)
services.add_transient(QueryABC, UserQuery)
services.add_transient(QueryABC, AchievementQuery)
services.add_transient(QueryABC, UserJoinedServerHistoryQuery)
services.add_transient(QueryABC, UserJoinedServerQuery)
services.add_transient(QueryABC, UserJoinedVoiceChannelHistoryQuery)

View File

@@ -1,6 +1,9 @@
type AchievementAttribute {
name: String
type: String
createdAt: String
modifiedAt: String
}
type Achievement implements TableWithHistoryQuery {

View File

@@ -17,6 +17,9 @@ type Query {
serverCount: Int
servers(filter: ServerFilter, page: Page, sort: Sort): [Server]
gameServerCount: Int
gameServers: [GameServer]
userJoinedServerCount: Int
userJoinedServers(filter: UserJoinedServerFilter, page: Page, sort: Sort): [UserJoinedServer]
@@ -31,8 +34,8 @@ type Query {
achievementCount: Int
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]
AchievementAttributes: [AchievementAttribute]
AchievementOperators: [String]
achievementAttributes: [AchievementAttribute]
achievementOperators: [String]
guilds(filter: GuildFilter): [Guild]
}

View File

@@ -1,3 +1,12 @@
type GameServer {
id: ID
name: String
server: Server
createdAt: String
modifiedAt: String
}
type Server implements TableWithHistoryQuery {
id: ID
discordId: String
@@ -13,6 +22,9 @@ type Server implements TableWithHistoryQuery {
levelCount: Int
levels(filter: LevelFilter, page: Page, sort: Sort): [Level]
gameServerCount: Int
gameServers: [GameServer]
userCount: Int
users(filter: UserFilter, page: Page, sort: Sort): [User]

View File

@@ -1,7 +1,7 @@
from bot_graphql.abc.data_query_abc import DataQueryABC
class AchievementQuery(DataQueryABC):
class AchievementAttributeQuery(DataQueryABC):
def __init__(
self,
):

View File

@@ -0,0 +1,10 @@
from bot_graphql.abc.data_query_abc import DataQueryABC
class GameServerQuery(DataQueryABC):
def __init__(self):
DataQueryABC.__init__(self, "GameServer")
self.set_field("id", lambda x, *_: x.id)
self.set_field("name", lambda x, *_: x.name)
self.set_field("server", lambda x, *_: x.server)

View File

@@ -4,6 +4,7 @@ from cpl_discord.service import DiscordBotServiceABC
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
from bot_data.abc.level_repository_abc import LevelRepositoryABC
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
from bot_data.abc.user_joined_voice_channel_repository_abc import UserJoinedVoiceChannelRepositoryABC
@@ -26,6 +27,7 @@ class ServerQuery(DataQueryWithHistoryABC):
auto_roles: AutoRoleRepositoryABC,
clients: ClientRepositoryABC,
levels: LevelRepositoryABC,
game_servers: GameServerRepositoryABC,
users: UserRepositoryABC,
ujs: UserJoinedServerRepositoryABC,
ujvs: UserJoinedVoiceChannelRepositoryABC,
@@ -56,6 +58,7 @@ class ServerQuery(DataQueryWithHistoryABC):
)
self.add_collection("level", lambda server, *_: self._levels.get_levels_by_server_id(server.id), LevelFilter)
self.add_collection("user", lambda server, *_: self._users.get_users_by_server_id(server.id), UserFilter)
self.add_collection("gameServer", lambda server, *_: game_servers.get_game_servers_by_server_id(server.id))
self.add_collection(
"achievement", lambda server, *_: achievements.get_achievements_by_server_id(server.id), AchievementFilter
)

View File

@@ -3,6 +3,7 @@ from cpl_discord.service import DiscordBotServiceABC
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from bot_data.abc.level_repository_abc import LevelRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
@@ -33,6 +34,7 @@ class Query(QueryABC):
known_users: KnownUserRepositoryABC,
levels: LevelRepositoryABC,
servers: ServerRepositoryABC,
game_servers: GameServerRepositoryABC,
user_joined_servers: UserJoinedServerRepositoryABC,
user_joined_voice_channels: UserJoinedVoiceChannelRepositoryABC,
user_joined_game_server: UserJoinedGameServerRepositoryABC,
@@ -50,6 +52,7 @@ class Query(QueryABC):
self.add_collection("knownUser", lambda *_: known_users.get_users())
self.add_collection("level", lambda *_: levels.get_levels(), LevelFilter)
self.add_collection("server", lambda *_: servers.get_servers(), ServerFilter)
self.add_collection("gameServer", lambda *_: game_servers.get_game_servers())
self.add_collection(
"userJoinedServer", lambda *_: user_joined_servers.get_user_joined_servers(), UserJoinedServerFilter
)
@@ -67,8 +70,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, *_: ["==", "!=", "<=", ">=", "<", ">"])
self.set_field("achievementAttributes", lambda x, *_: achievement_service.get_attributes())
self.set_field("achievementOperators", lambda x, *_: achievement_service.get_operators())
def _resolve_guilds(self, *_, filter=None):
if filter is None or "id" not in filter:

View File

@@ -3,6 +3,7 @@ from typing import List
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from bot_data.abc.level_repository_abc import LevelRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
@@ -21,6 +22,7 @@ class AchievementAttributeResolver:
known_users: KnownUserRepositoryABC,
levels: LevelRepositoryABC,
servers: ServerRepositoryABC,
game_servers: GameServerRepositoryABC,
user_joined_servers: UserJoinedServerRepositoryABC,
user_joined_voice_channels: UserJoinedVoiceChannelRepositoryABC,
user_joined_game_server: UserJoinedGameServerRepositoryABC,
@@ -32,6 +34,7 @@ class AchievementAttributeResolver:
self._known_users = known_users
self._levels = levels
self._servers = servers
self._game_servers = game_servers
self._user_joined_servers = user_joined_servers
self._user_joined_voice_channels = user_joined_voice_channels
self._user_joined_game_server = user_joined_game_server
@@ -40,4 +43,4 @@ class AchievementAttributeResolver:
def get_played_on_game_server(self, user: User) -> List[str]:
joins = self._user_joined_game_server.get_user_joined_game_servers_by_user_id(user.id)
return joins.select(lambda x: x.name)
return joins.select(lambda x: x.game_server.name)

View File

@@ -68,7 +68,7 @@ class AchievementService:
def get_attributes(self) -> List[AchievementAttribute]:
return self._attributes
def _match(self, value: str, operator: str, expected_value: str) -> bool:
def _match(self, value: any, operator: str, expected_value: str) -> bool:
return self._operators[operator](value, expected_value)
def has_user_achievement_already(self, user: User, achievement: Achievement) -> bool:
@@ -77,7 +77,7 @@ class AchievementService:
def has_user_achievement(self, user: User, achievement: Achievement) -> bool:
attribute: AchievementAttribute = self._attributes.where(lambda x: x.name == achievement.attribute).single()
return self._match(str(attribute.resolve(user)), achievement.operator, achievement.value)
return self._match(attribute.resolve(user), achievement.operator, achievement.value)
async def validate_achievements_for_user(self, user: User):
achievements = self._achievements.get_achievements_by_server_id(user.server.id)

View File

@@ -6,7 +6,9 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from modules.achievements.achievement_attribute_resolver import AchievementAttributeResolver
from modules.achievements.achievement_service import AchievementService
from modules.achievements.commands.achievements_group import AchievementGroup
from modules.achievements.events.achievement_on_message_event import AchievementOnMessageEvent
@@ -18,5 +20,9 @@ class AchievementsModule(ModuleABC):
pass
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_transient(AchievementAttributeResolver)
services.add_transient(AchievementService)
self._dc.add_command(AchievementGroup)
self._dc.add_event(DiscordEventTypesEnum.on_message.value, AchievementOnMessageEvent)

View File

@@ -0,0 +1 @@
# imports

View File

@@ -0,0 +1,57 @@
import discord
from cpl_discord.command import DiscordCommandABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord.ext import commands
from discord.ext.commands import Context
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.helper.command_checks import CommandChecks
from bot_core.logging.command_logger import CommandLogger
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from modules.achievements.achievement_service import AchievementService
class AchievementGroup(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
message_service: MessageServiceABC,
bot: DiscordBotServiceABC,
servers: ServerRepositoryABC,
users: UserRepositoryABC,
achievement_service: AchievementService,
translate: TranslatePipe,
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._message_service = message_service
self._bot = bot
self._servers = servers
self._users = users
self._achievement_service = achievement_service
self._t = translate
@commands.hybrid_group()
@commands.guild_only()
async def achievement(self, ctx: Context):
pass
@achievement.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator()
async def check(self, ctx: Context, member: discord.Member):
self._logger.debug(__name__, f"Received command achievement check {ctx}")
server = self._servers.get_server_by_discord_id(member.guild.id)
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id)
await self._message_service.send_ctx_msg(
ctx,
self._t.transform("modules.achievements.commands.check"),
)
await self._achievement_service.validate_achievements_for_user(user)
self._logger.trace(__name__, f"Finished command achievement check")