diff --git a/kdb-bot/src/bot/bot.json b/kdb-bot/src/bot/bot.json index 9245699a..4f702589 100644 --- a/kdb-bot/src/bot/bot.json +++ b/kdb-bot/src/bot/bot.json @@ -29,8 +29,7 @@ "eventlet==0.33.2", "requests-oauthlib==1.3.1", "icmplib==3.0.3", - "ariadne==0.17.0", - "ariadne-graphql-modules==0.7.0" + "ariadne==0.17.0" ], "DevDependencies": [ "cpl-cli==2022.12.0" diff --git a/kdb-bot/src/bot_api/controller/grahpql_controller.py b/kdb-bot/src/bot_api/controller/grahpql_controller.py index 9d51d363..9c102ccc 100644 --- a/kdb-bot/src/bot_api/controller/grahpql_controller.py +++ b/kdb-bot/src/bot_api/controller/grahpql_controller.py @@ -3,6 +3,7 @@ from ariadne.constants import PLAYGROUND_HTML from cpl_core.configuration import ConfigurationABC from cpl_core.environment import ApplicationEnvironmentABC from flask import request, jsonify +from graphql import MiddlewareManager from bot_api.logging.api_logger import ApiLogger from bot_api.route.route import Route diff --git a/kdb-bot/src/bot_graphql/abc/data_query_abc.py b/kdb-bot/src/bot_graphql/abc/data_query_abc.py new file mode 100644 index 00000000..59af3956 --- /dev/null +++ b/kdb-bot/src/bot_graphql/abc/data_query_abc.py @@ -0,0 +1,20 @@ +from cpl_core.database import TableABC + +from bot_graphql.abc.query_abc import QueryABC + + +class DataQueryABC(QueryABC): + + def __init__(self, name: str): + QueryABC.__init__(self, name) + + self.set_field('created_at', self.resolve_created_at) + self.set_field('modified_at', self.resolve_modified_at) + + @staticmethod + def resolve_created_at(entry: TableABC, *_): + return entry.created_at + + @staticmethod + def resolve_modified_at(entry: TableABC, *_): + return entry.modified_at diff --git a/kdb-bot/src/bot_graphql/abc/filter_abc.py b/kdb-bot/src/bot_graphql/abc/filter_abc.py new file mode 100644 index 00000000..827f45b3 --- /dev/null +++ b/kdb-bot/src/bot_graphql/abc/filter_abc.py @@ -0,0 +1,57 @@ +import functools +from abc import ABC +from inspect import signature, Parameter + + +class FilterABC(ABC): + + def __init__(self): + ABC.__init__(self) + + self._page_index = 0 + self._page_size = 10 + self._sort_direction = '' + self._sort_column = '' + + @property + def page_index(self) -> int: + return self._page_index + + @property + def page_size(self) -> int: + return self._page_size + + @property + def sort_direction(self) -> str: + return self._sort_direction + + @property + def sort_column(self) -> str: + return self._sort_column + + @staticmethod + def get_filter(f, values: dict): + sig = signature(f) + for param in sig.parameters.items(): + parameter = param[1] + if parameter.name == 'self' or parameter.annotation == Parameter.empty: + continue + + if issubclass(parameter.annotation, FilterABC): + filter = parameter.annotation() + filter.from_dict(values) + return filter + + @classmethod + def resolve_filter_annotation(cls, f=None): + if f is None: + return functools.partial(cls.filter) + + @functools.wraps(f) + def decorator(*args, **kwargs): + if 'filter' in kwargs: + kwargs['filter'] = cls.get_filter(f, kwargs['filter']) + + return f(*args, **kwargs) + + return decorator diff --git a/kdb-bot/src/bot_graphql/filter/server_filter.py b/kdb-bot/src/bot_graphql/filter/server_filter.py index 3238500e..26fcb8ea 100644 --- a/kdb-bot/src/bot_graphql/filter/server_filter.py +++ b/kdb-bot/src/bot_graphql/filter/server_filter.py @@ -1,2 +1,43 @@ -class ServerFilter: - pass +from cpl_core.dependency_injection import ServiceProviderABC +from cpl_discord.container import Guild +from cpl_discord.service import DiscordBotServiceABC +from cpl_query.extension import List + +from bot_data.model.server import Server +from bot_graphql.abc.filter_abc import FilterABC + + +class ServerFilter(FilterABC): + + def __init__(self): + FilterABC.__init__(self) + + self._id = None + self._discord_id = None + self._name = None + + def from_dict(self, values: dict): + if 'id' in values: + self._id = values['id'] + + @ServiceProviderABC.inject + def filter(self, query: List[Server], bot: DiscordBotServiceABC) -> List[Server]: + result = List(Server) + + if self._id is not None: + query = query.where(lambda x: x.server_id == self._id) + + if self._discord_id is not None: + query = query.where(lambda x: x.discord_server_id == self._discord_id) + + if self._name is not None: + def where_guild(x: Guild): + guild = bot.get_guild(x.discord_server_id) + return guild is not None and (self._name.lower() == guild.name.lower() or self._name.lower() in guild.name.lower()) + + query = query.where(where_guild) + + skip = self.page_size * self.page_index + result = query.skip(skip).take(self.page_size) + + return result diff --git a/kdb-bot/src/bot_graphql/model.gql b/kdb-bot/src/bot_graphql/model.gql index dba3d2af..94182271 100644 --- a/kdb-bot/src/bot_graphql/model.gql +++ b/kdb-bot/src/bot_graphql/model.gql @@ -1,17 +1,38 @@ type Query { - servers: [Server] + servers(filter: ServerFilter): [Server] + server_count: Int known_users: [User] } -type Server { +interface TableQuery { + created_at: String + modified_at: String +} + +input ServerFilter { + id: Int + discord_id: String + name: String + + page_index: Int + page_size: Int + sort_direction: String + sort_column: String +} + +type Server implements TableQuery { id: ID discord_id: String + name: String clients: [Client] members: [User] level: [Level] + + created_at: String + modified_at: String } -type Client { +type Client implements TableQuery { id: ID discord_id: String sent_message_count: Int @@ -21,9 +42,12 @@ type Client { moved_users_count: Int server: Server + + created_at: String + modified_at: String } -type User { +type User implements TableQuery { id: ID discord_id: String name: String @@ -35,25 +59,34 @@ type User { joined_voice_channel: [UserJoinedVoiceChannel] server: Server + + created_at: String + modified_at: String } -type UserJoinedServer { +type UserJoinedServer implements TableQuery { id: ID user: User server: Server joined_on: String leaved_on: String + + created_at: String + modified_at: String } -type UserJoinedVoiceChannel { +type UserJoinedVoiceChannel implements TableQuery { id: ID channel_id: String user: User joined_on: String leaved_on: String + + created_at: String + modified_at: String } -type Level { +type Level implements TableQuery { id: ID name: String color: String @@ -61,4 +94,7 @@ type Level { permissions: String server: Server + + created_at: String + modified_at: String } \ No newline at end of file diff --git a/kdb-bot/src/bot_graphql/queries/server_query.py b/kdb-bot/src/bot_graphql/queries/server_query.py index 1b1aea4b..81a1a2ac 100644 --- a/kdb-bot/src/bot_graphql/queries/server_query.py +++ b/kdb-bot/src/bot_graphql/queries/server_query.py @@ -1,14 +1,22 @@ -from bot_graphql.abc.query_abc import QueryABC +from cpl_discord.service import DiscordBotServiceABC + from bot_data.model.server import Server +from bot_graphql.abc.data_query_abc import DataQueryABC -class ServerQuery(QueryABC): +class ServerQuery(DataQueryABC): - def __init__(self): - QueryABC.__init__(self, 'Server') + def __init__( + self, + bot: DiscordBotServiceABC + ): + DataQueryABC.__init__(self, 'Server') + + self._bot = bot self.set_field('id', self.resolve_id) self.set_field('discord_id', self.resolve_discord_id) + self.set_field('name', self.resolve_name) @staticmethod def resolve_id(server: Server, *_): @@ -17,3 +25,7 @@ class ServerQuery(QueryABC): @staticmethod def resolve_discord_id(server: Server, *_): return server.discord_server_id + + def resolve_name(self, server: Server, *_): + guild = self._bot.get_guild(server.discord_server_id) + return None if guild is None else guild.name diff --git a/kdb-bot/src/bot_graphql/query.py b/kdb-bot/src/bot_graphql/query.py index cacaf8ad..b080fa2a 100644 --- a/kdb-bot/src/bot_graphql/query.py +++ b/kdb-bot/src/bot_graphql/query.py @@ -1,7 +1,8 @@ from ariadne import QueryType -from bot_graphql.filter.server_filter import ServerFilter from bot_data.service.server_repository_service import ServerRepositoryService +from bot_graphql.abc.filter_abc import FilterABC +from bot_graphql.filter.server_filter import ServerFilter class Query(QueryType): @@ -14,6 +15,14 @@ class Query(QueryType): self._servers = servers self.set_field('servers', self.resolve_servers) + self.set_field('server_count', self.resolve_server_count) - def resolve_servers(self, filter: ServerFilter, *_): - return self._servers.get_servers() + @FilterABC.resolve_filter_annotation + def resolve_servers(self, *_, filter: ServerFilter = None): + if filter is not None: + return filter.filter(self._servers.get_servers()) + else: + return self._servers.get_servers() + + def resolve_server_count(self, *_): + return self._servers.get_servers().count()