Removed statistic module #190

This commit is contained in:
Nick Jungmann 2023-02-17 00:02:26 +01:00
parent e2ef4f3bde
commit 55e9fc6eb5
15 changed files with 26 additions and 659 deletions

View File

@ -19,7 +19,7 @@
"cpl-core==2022.12.1.post3", "cpl-core==2022.12.1.post3",
"cpl-translation==2022.12.1", "cpl-translation==2022.12.1",
"cpl-query==2022.12.2.post1", "cpl-query==2022.12.2.post1",
"Flask==2.2.2", "Flask==2.2.3",
"Flask-Classful==0.14.2", "Flask-Classful==0.14.2",
"Flask-Cors==3.0.10", "Flask-Cors==3.0.10",
"PyJWT==2.6.0", "PyJWT==2.6.0",
@ -41,15 +41,15 @@
"BuildSettings": { "BuildSettings": {
"ProjectType": "console", "ProjectType": "console",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "..\\..\\dist",
"Main": "bot.main", "Main": "bot.main",
"EntryPoint": "bot", "EntryPoint": "bot",
"IncludePackageData": false, "IncludePackageData": false,
"Included": [], "Included": [],
"Excluded": [ "Excluded": [
"*/__pycache__", "*\\__pycache__",
"*/logs", "*\\logs",
"*/tests" "*\\tests"
], ],
"PackageData": {}, "PackageData": {},
"ProjectReferences": [ "ProjectReferences": [

@ -1 +1 @@
Subproject commit ac7046820f3410f55e779797126d9410c6bcdc9f Subproject commit e8c7334eee0dcc25d11343fae0adb106aca079f1

View File

@ -11,7 +11,6 @@ from modules.boot_log.boot_log_module import BootLogModule
from modules.database.database_module import DatabaseModule from modules.database.database_module import DatabaseModule
from modules.level.level_module import LevelModule from modules.level.level_module import LevelModule
from modules.permission.permission_module import PermissionModule from modules.permission.permission_module import PermissionModule
from modules.stats.stats_module import StatsModule
from modules.technician.technician_module import TechnicianModule from modules.technician.technician_module import TechnicianModule
@ -31,7 +30,6 @@ class ModuleList:
BaseModule, BaseModule,
LevelModule, LevelModule,
ApiModule, ApiModule,
StatsModule,
TechnicianModule, TechnicianModule,
# has to be last! # has to be last!
BootLogModule, BootLogModule,

View File

@ -4,7 +4,7 @@ from bot_data.db_context import DBContext
class StatsMigration(MigrationABC): class StatsMigration(MigrationABC):
name = "0.3_StatsMigration" name = "1.0_RemoveStatsMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext): def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self) MigrationABC.__init__(self)
@ -18,20 +18,26 @@ class StatsMigration(MigrationABC):
self._cursor.execute( self._cursor.execute(
str( str(
f""" f"""
CREATE TABLE IF NOT EXISTS `Statistics` ( DROP TABLE IF EXISTS `Statistics`;
`Id` BIGINT NOT NULL AUTO_INCREMENT, """
`Name` VARCHAR(255) NOT NULL,
`Description` VARCHAR(255) NOT NULL,
`Code` LONGTEXT NOT NULL,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`Id`),
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
);
"""
) )
) )
def downgrade(self): def downgrade(self):
self._cursor.execute("DROP TABLE `Statistics`;") self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `Statistics` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(255) NOT NULL,
`Description` VARCHAR(255) NOT NULL,
`Code` LONGTEXT NOT NULL,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`Id`),
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
);
"""
)
)

View File

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = "modules.stats"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "0.3.1"
from collections import namedtuple
# imports:
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = "modules.stats.command"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "0.3.1"
from collections import namedtuple
# imports
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -1,232 +0,0 @@
from typing import List as TList
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.command import DiscordCommandABC
from cpl_translation import TranslatePipe
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import Context
from bot_core.abc.client_utils_abc import ClientUtilsABC
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.statistic_repository_abc import StatisticRepositoryABC
from modules.permission.abc.permission_service_abc import PermissionServiceABC
from modules.stats.service.statistic_service import StatisticService
from modules.stats.ui.add_statistic_form import AddStatisticForm
class StatsGroup(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
message_service: MessageServiceABC,
client_utils: ClientUtilsABC,
translate: TranslatePipe,
permission_service: PermissionServiceABC,
statistic: StatisticService,
servers: ServerRepositoryABC,
stats: StatisticRepositoryABC,
db: DatabaseContextABC,
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._client_utils = client_utils
self._message_service = message_service
self._t = translate
self._permissions = permission_service
self._statistic = statistic
self._servers = servers
self._stats = stats
self._db = db
@commands.hybrid_group()
@commands.guild_only()
async def stats(self, ctx: Context):
pass
@stats.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator()
async def list(self, ctx: Context, wait: int = None):
self._logger.debug(__name__, f"Received command stats list {ctx}")
if ctx.guild is None:
return
embed = discord.Embed(
title=self._t.transform("modules.auto_role.list.title"),
description=self._t.transform("modules.auto_role.list.description"),
color=int("ef9d0d", 16),
)
server = self._servers.get_server_by_discord_id(ctx.guild.id)
stats = self._stats.get_statistics_by_server_id(server.server_id)
if stats.count() == 0:
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.stats.list.nothing_found"))
return
statistics = ""
descriptions = ""
for statistic in stats:
statistics += f"\n{statistic.name}"
descriptions += f"\n{statistic.description}"
embed.add_field(
name=self._t.transform("modules.stats.list.statistic"),
value=statistics,
inline=True,
)
embed.add_field(
name=self._t.transform("modules.stats.list.description"),
value=descriptions,
inline=True,
)
await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait)
self._logger.trace(__name__, f"Finished command stats list")
@stats.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator()
async def view(self, ctx: Context, name: str, wait: int = None):
self._logger.debug(__name__, f"Received command stats view {ctx}:{name}")
if ctx.guild is None:
return
try:
server = self._servers.get_server_by_discord_id(ctx.guild.id)
stats = self._stats.get_statistics_by_server_id(server.server_id)
statistic = stats.where(lambda s: s.name == name).single()
result = await self._statistic.execute(statistic.code, server)
embed = discord.Embed(
title=statistic.name,
description=statistic.description,
color=int("ef9d0d", 16),
)
for i in range(result.header.count()):
header = result.header[i]
value = ""
for row in result.values:
value += f"\n{row[i]}"
embed.add_field(name=header, value=value, inline=True)
await self._message_service.send_ctx_msg(ctx, embed, wait_before_delete=wait)
except Exception as e:
self._logger.error(__name__, f"Cannot view statistic {name}", e)
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.stats.view.failed"))
self._logger.trace(__name__, f"Finished stats view command")
@view.autocomplete("name")
async def view_autocomplete(
self, interaction: discord.Interaction, current: str
) -> TList[app_commands.Choice[str]]:
server = self._servers.get_server_by_discord_id(interaction.guild.id)
stats = self._stats.get_statistics_by_server_id(server.server_id)
return [
app_commands.Choice(name=f"{statistic.name}: {statistic.description}", value=statistic.name)
for statistic in stats
]
@stats.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_technician()
async def add(self, ctx: Context, name: str):
self._logger.debug(__name__, f"Received command stats add {ctx}: {name}")
if ctx.guild is None:
return
server = self._servers.get_server_by_discord_id(ctx.guild.id)
form = AddStatisticForm(
server,
self._stats,
self._db,
name,
self._message_service,
self._logger,
self._t,
)
self._logger.trace(__name__, f"Finished stats add command")
self._logger.trace(__name__, f"Started stats command form")
await ctx.interaction.response.send_modal(form)
@stats.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_technician()
async def edit(self, ctx: Context, name: str):
self._logger.debug(__name__, f"Received command stats edit {ctx}: {name}")
try:
server = self._servers.get_server_by_discord_id(ctx.guild.id)
stats = self._stats.get_statistics_by_server_id(server.server_id)
statistic = stats.where(lambda s: s.name == name).single()
form = AddStatisticForm(
server,
self._stats,
self._db,
name,
self._message_service,
self._logger,
self._t,
code=statistic.code,
description=statistic.description,
)
self._logger.trace(__name__, f"Finished stats edit command")
self._logger.trace(__name__, f"Started stats command form")
await ctx.interaction.response.send_modal(form)
except Exception as e:
self._logger.error(__name__, f"Cannot edit statistic {name}", e)
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.stats.edit.failed"))
@edit.autocomplete("name")
async def edit_autocomplete(
self, interaction: discord.Interaction, current: str
) -> TList[app_commands.Choice[str]]:
server = self._servers.get_server_by_discord_id(interaction.guild.id)
stats = self._stats.get_statistics_by_server_id(server.server_id)
return [
app_commands.Choice(name=f"{statistic.name}: {statistic.description}", value=statistic.name)
for statistic in stats
]
@stats.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_technician()
async def remove(self, ctx: Context, name: str):
self._logger.debug(__name__, f"Received command stats remove {ctx}: {name}")
try:
server = self._servers.get_server_by_discord_id(ctx.guild.id)
statistic = self._stats.get_statistic_by_name(name, server.server_id)
self._stats.delete_statistic(statistic)
self._db.save_changes()
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.stats.remove.success"))
self._logger.trace(__name__, f"Finished stats remove command")
except Exception as e:
self._logger.error(__name__, f"Cannot remove statistic {name}", e)
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.stats.remove.failed"))
@remove.autocomplete("name")
async def edit_autocomplete(
self, interaction: discord.Interaction, current: str
) -> TList[app_commands.Choice[str]]:
server = self._servers.get_server_by_discord_id(interaction.guild.id)
stats = self._stats.get_statistics_by_server_id(server.server_id)
return [
app_commands.Choice(name=f"{statistic.name}: {statistic.description}", value=statistic.name)
for statistic in stats
]

View File

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = "modules.stats.model"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "0.3.1"
from collections import namedtuple
# imports
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -1,23 +0,0 @@
from cpl_query.extension import List
class StatisticResult:
def __init__(self):
self._header = List(str)
self._values = List(List)
@property
def header(self) -> List[str]:
return self._header
@header.setter
def header(self, value: List[str]):
self._header = value
@property
def values(self) -> List[List]:
return self._values
@values.setter
def values(self, value: List[List]):
self._values = value

View File

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = "modules.stats.service"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "0.3.1"
from collections import namedtuple
# imports
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -1,87 +0,0 @@
from abc import abstractmethod
from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from discord import Guild
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
from bot_data.abc.client_repository_abc import ClientRepositoryABC
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
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
from bot_data.abc.user_joined_voice_channel_repository_abc import (
UserJoinedVoiceChannelRepositoryABC,
)
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.auto_role import AutoRole
from bot_data.model.client import Client
from bot_data.model.known_user import KnownUser
from bot_data.model.level import Level
from bot_data.model.server import Server
from bot_data.model.user import User
from bot_data.model.user_joined_server import UserJoinedServer
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from modules.stats.model.statistic_result import StatisticResult
class StatisticService:
def __init__(
self,
auto_roles: AutoRoleRepositoryABC,
clients: ClientRepositoryABC,
known_users: KnownUserRepositoryABC,
levels: LevelRepositoryABC,
servers: ServerRepositoryABC,
user_joined_servers: UserJoinedServerRepositoryABC,
user_joined_voice_channel: UserJoinedVoiceChannelRepositoryABC,
users: UserRepositoryABC,
bot: DiscordBotServiceABC,
):
self._auto_roles = auto_roles
self._clients = clients
self._known_users = known_users
self._levels = levels
self._servers = servers
self._user_joined_servers = user_joined_servers
self._user_joined_voice_channel = user_joined_voice_channel
self._users = users
self._bot = bot
async def execute(self, code: str, server: Server) -> StatisticResult:
guild = self._bot.guilds.where(lambda g: g.id == server.discord_server_id).single()
return await self.get_data(
code,
self._auto_roles.get_auto_roles().where(lambda x: x.server.server_id == server.server_id),
self._clients.get_clients().where(lambda x: x.server.server_id == server.server_id),
self._known_users.get_users(),
self._levels.get_levels().where(lambda x: x.server.server_id == server.server_id),
self._servers.get_servers().where(lambda x: x.server_id == server.server_id),
self._user_joined_servers.get_user_joined_servers().where(
lambda x: x.user.server.server_id == server.server_id
),
self._user_joined_voice_channel.get_user_joined_voice_channels().where(
lambda x: x.user.server.server_id == server.server_id
),
self._users.get_users().where(lambda x: x.server.server_id == server.server_id),
guild,
)
@staticmethod
async def get_data(
code: str,
auto_roles: List[AutoRole],
clients: List[Client],
known_users: List[KnownUser],
levels: List[Level],
servers: List[Server],
user_joined_servers: List[UserJoinedServer],
user_joined_voice_channel: List[UserJoinedVoiceChannel],
users: List[User],
guild: Guild,
) -> StatisticResult:
result = StatisticResult()
exec(code)
return result

View File

@ -1,44 +0,0 @@
{
"ProjectSettings": {
"Name": "stats",
"Version": {
"Major": "0",
"Minor": "3",
"Micro": "1"
},
"Author": "",
"AuthorEmail": "",
"Description": "",
"LongDescription": "",
"URL": "",
"CopyrightDate": "",
"CopyrightName": "",
"LicenseName": "",
"LicenseDescription": "",
"Dependencies": [
"cpl-core==2022.12.0"
],
"DevDependencies": [
"cpl-cli==2022.12.0"
],
"PythonVersion": ">=3.10.4",
"PythonPath": {},
"Classifiers": []
},
"BuildSettings": {
"ProjectType": "library",
"SourcePath": "",
"OutputPath": "../../dist",
"Main": "stats.main",
"EntryPoint": "stats",
"IncludePackageData": false,
"Included": [],
"Excluded": [
"*/__pycache__",
"*/logs",
"*/tests"
],
"PackageData": {},
"ProjectReferences": []
}
}

View File

@ -1,23 +0,0 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC
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.stats.command.stats_group import StatsGroup
from modules.stats.service.statistic_service import StatisticService
class StatsModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.stats_module)
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
pass
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_transient(StatisticService)
# commands
self._dc.add_command(StatsGroup)
# events

View File

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
"""
bot Keksdose bot
~~~~~~~~~~~~~~~~~~~
Discord bot for the Keksdose discord Server
:copyright: (c) 2022 - 2023 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = "modules.stats.ui"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2022 - 2023 sh-edraft.de"
__version__ = "0.3.1"
from collections import namedtuple
# imports
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="0", minor="3", micro="1")

View File

@ -1,98 +0,0 @@
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_query.extension import List
from cpl_translation import TranslatePipe
from discord import ui, TextStyle
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.logging.command_logger import CommandLogger
from bot_data.abc.statistic_repository_abc import StatisticRepositoryABC
from bot_data.model.server import Server
from bot_data.model.statistic import Statistic
class AddStatisticForm(ui.Modal):
description = ui.TextInput(label="Beschreibung", required=True)
code = ui.TextInput(label="Code", required=True, style=TextStyle.long)
def __init__(
self,
server: Server,
stats: StatisticRepositoryABC,
db: DatabaseContextABC,
name: str,
message_service: MessageServiceABC,
logger: CommandLogger,
t: TranslatePipe,
code: str = None,
description: str = None,
):
ui.Modal.__init__(self, title=name)
self._server = server
self._stats = stats
self._db = db
self._name = name
self._message_service = message_service
self._logger = logger
self._t = t
if code is not None:
self.code.default = code
if description is not None:
self.description.default = description
async def on_submit(self, interaction: discord.Interaction):
statistic = (
self._stats.get_statistics_by_server_id(self._server.server_id)
.where(lambda s: s.name == self._name)
.single_or_default()
)
if interaction.guild is None:
if statistic is None:
await self._message_service.send_interaction_msg(
interaction, self._t.transform("modules.stats.add.failed")
)
else:
await self._message_service.send_interaction_msg(
interaction, self._t.transform("modules.stats.edit.failed")
)
return
try:
if statistic is None:
self._stats.add_statistic(
Statistic(
self._name,
self.description.value,
self.code.value,
self._server,
)
)
self._db.save_changes()
await self._message_service.send_interaction_msg(
interaction, self._t.transform("modules.stats.add.success")
)
return
statistic.description = self.description.value
statistic.code = self.code.value
self._stats.update_statistic(statistic)
self._db.save_changes()
await self._message_service.send_interaction_msg(
interaction, self._t.transform("modules.stats.edit.success")
)
except Exception as e:
self._logger.error(__name__, f"Save statistic {self._name} failed", e)
if statistic is None:
await self._message_service.send_interaction_msg(
interaction, self._t.transform("modules.stats.add.failed")
)
else:
await self._message_service.send_interaction_msg(
interaction, self._t.transform("modules.stats.edit.failed")
)
self._logger.trace(__name__, f"Finished stats command form")