Merge pull request 'A-0.3 - Basismodul' (#36) from 0.3 into Alpha

Reviewed-on: #36
Closed #9
This commit is contained in:
Sven Heidemann 2021-12-27 18:17:41 +01:00
commit 40419c9a0b
51 changed files with 2253 additions and 89 deletions

View File

@ -10,7 +10,8 @@
"boot-log": "src/modules/boot_log/boot-log.json",
"level-generator": "tools/level_generator/level-generator.json",
"ontime-calculator": "tools/ontime_calculator/ontime-calculator.json",
"database": "src/modules/database/database.json"
"database": "src/modules/database/database.json",
"base": "src/modules/base/base.json"
},
"Scripts": {
"build-start": "cd src/gismo_cli; echo 'gismo-cli:'; cpl build; cd ../gismo; echo 'gismo:'; cpl build; cd ../../dist/gismo/build/gismo; bash gismo",

View File

@ -15,11 +15,11 @@ __title__ = 'gismo'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -3,8 +3,10 @@ from cpl_core.configuration import ConfigurationABC
from cpl_core.console import Console
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.logging import LoggerABC
from gismo_core.abc.bot_service_abc import BotServiceABC
from gismo_core.service.bot_service import BotService
from gismo_data.service.migration_service import MigrationService
class Gismo(ApplicationABC):
@ -14,12 +16,14 @@ class Gismo(ApplicationABC):
self._bot: BotService = services.get_service(BotServiceABC)
self._logger: LoggerABC = services.get_service(LoggerABC)
self._migrations: MigrationService = services.get_service(MigrationService)
async def configure(self):
pass
async def main(self):
try:
self._migrations.migrate()
self._logger.trace(__name__, f'Try to start {BotService}')
await self._bot.start_async()
except Exception as e:

View File

@ -0,0 +1,36 @@
{
"TimeFormatSettings": {
"DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
},
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR",
"FileLogLevel": "WARN"
},
"Discord": {
"Token": ""
},
"Bot": {
"Prefix": "!g",
"Servers": [
{
"Id": "",
"LoginMessageChannelId": "",
"LoginMessage": "",
"MessageDeleteTimer": 0,
"WelcomeMessage": "",
"GoodbyeMessage": "",
"MaxVoiceStateHours": 0,
"XpPerMessage": 0,
"XpPerOntimeHour": 0,
"AFKChannelIds": [],
"AdminRoleIds": [],
"ModeratorRoleIds": []
}
]
}
}

View File

@ -5,11 +5,10 @@
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
},
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR",
"FileLogLevel": "WARN"
}
}
}

View File

@ -3,7 +3,7 @@
"Name": "gismo",
"Version": {
"Major": "0",
"Minor": "2",
"Minor": "3",
"Micro": "0"
},
"Author": "Sven Heidemann",
@ -48,7 +48,9 @@
"../gismo_core/gismo-core.json",
"../gismo_data/gismo-data.json",
"../modules_core/modules-core.json",
"../modules/boot_log/boot-log.json"
"../modules/boot_log/boot-log.json",
"../modules/base/base.json",
"../modules/database/database.json"
]
}
}

View File

@ -9,15 +9,32 @@ from cpl_core.dependency_injection import (ServiceCollectionABC,
ServiceProviderABC)
from cpl_core.environment import ApplicationEnvironment
from cpl_core.logging import LoggerABC
from gismo_core.abc.bot_service_abc import BotServiceABC
from gismo_core.abc.message_service_abc import MessageServiceABC
from gismo_core.service.bot_service import BotService
from gismo_core.service.message_service import MessageService
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from gismo_data.abc.migration_abc import MigrationABC
from gismo_data.abc.server_repository_abc import ServerRepositoryABC
from gismo_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
from gismo_data.abc.user_repository_abc import UserRepositoryABC
from gismo_data.db_context import DBContext
from gismo_data.service.server_repository_service import ServerRepositoryService
from gismo_data.migration.initial_migration import InitialMigration
from gismo_data.migration.migration_0_3 import Migration_0_3
from gismo_data.migration.migration_0_3_1 import Migration_0_3_1
from gismo_data.service.client_repository_service import (
ClientRepositoryABC, ClientRepositoryService)
from gismo_data.service.known_user_repository_service import \
KnownUserRepositoryService
from gismo_data.service.migration_service import MigrationService
from gismo_data.service.server_repository_service import \
ServerRepositoryService
from gismo_data.service.user_joined_server_repository_service import UserJoinedServerRepositoryService
from gismo_data.service.user_joined_voice_channel_service import UserJoinedVoiceChannelRepositoryService
from gismo_data.service.user_repository_service import UserRepositoryService
from modules.base.base import Base
from modules.boot_log.boot_log import BootLog
from modules.database.database import Database
from modules_core.abc.module_abc import ModuleABC
@ -51,15 +68,31 @@ class Startup(StartupABC):
services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings))
# modules
services.add_singleton(ModuleServiceABC, ModuleService)
services.add_singleton(BotServiceABC, BotService)
services.add_transient(MessageServiceABC, MessageService)
# services
services.add_transient(MigrationService)
# data services
services.add_transient(ServerRepositoryABC, ServerRepositoryService)
services.add_transient(UserRepositoryABC, UserRepositoryService)
services.add_transient(ClientRepositoryABC, ClientRepositoryService)
services.add_transient(KnownUserRepositoryABC, KnownUserRepositoryService)
services.add_transient(UserJoinedServerRepositoryABC, UserJoinedServerRepositoryService)
services.add_transient(UserJoinedVoiceChannelRepositoryABC, UserJoinedVoiceChannelRepositoryService)
# modules
services.add_transient(ModuleABC, Database)
services.add_transient(ModuleABC, Base)
services.add_transient(ModuleABC, BootLog)
# migrations
services.add_transient(MigrationABC, InitialMigration)
services.add_transient(MigrationABC, Migration_0_3)
services.add_transient(MigrationABC, Migration_0_3_1)
provider: ServiceProviderABC = services.build_service_provider()

View File

@ -15,11 +15,11 @@ __title__ = 'gismo_core'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -15,11 +15,11 @@ __title__ = 'gismo_core.abc'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -15,11 +15,11 @@ __title__ = 'gismo_core.configuration'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -13,6 +13,15 @@ class ServerSettings(ConfigurationModelABC):
self._message_delete_timer: int = 0
self._login_message_channel_id: int = 0
self._login_message: str = ''
self._welcome_message: str = ''
self._welcome_message_for_team: str = ''
self._goodbye_message: str = ''
self._max_voice_state_hours: int = 0
self._xp_per_message: int = 0
self._xp_per_ontime_hour: int = 0
self._afk_channel_ids: list[int] = []
self._admin_roles: list[int] = []
self._moderator_roles: list[int] = []
@property
def id(self) -> str:
@ -30,12 +39,62 @@ class ServerSettings(ConfigurationModelABC):
def login_message(self) -> str:
return self._login_message
@property
def welcome_message(self) -> str:
return self._welcome_message
@property
def welcome_message_for_team(self) -> str:
return self._welcome_message_for_team
@property
def goodbye_message(self) -> str:
return self._goodbye_message
@property
def max_voice_state_hours(self) -> int:
return self._max_voice_state_hours
@property
def xp_per_message(self) -> int:
return self._xp_per_message
@property
def xp_per_ontime_hour(self) -> int:
return self._xp_per_ontime_hour
@property
def afk_channel_ids(self) -> list[int]:
return self._afk_channel_ids
@property
def admin_roles(self) -> list[int]:
return self._admin_roles
@property
def moderator_roles(self) -> list[int]:
return self._moderator_roles
def from_dict(self, settings: dict):
try:
self._id = int(settings['Id'])
self._message_delete_timer = int(settings['MessageDeleteTimer'])
self._login_message_channel_id = int(settings['LoginMessageChannelId'])
self._login_message = settings['LoginMessage']
self._welcome_message = settings['WelcomeMessage']
self._welcome_message_for_team = settings['WelcomeMessageForTeam']
self._goodbye_message = settings['GoodbyeMessage']
self._max_voice_state_hours = int(settings['MaxVoiceStateHours'])
self._xp_per_message = int(settings['XpPerMessage'])
self._xp_per_ontime_hour = int(settings['XpPerOntimeHour'])
for id in settings['AFKChannelIds']:
self._afk_channel_ids.append(int(id))
for id in settings['AdminRoleIds']:
self._admin_roles.append(int(id))
for id in settings['ModeratorRoleIds']:
self._moderator_roles.append(int(id))
except Exception as e:
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in settings')
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')

View File

@ -15,11 +15,11 @@ __title__ = 'gismo_core.service'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -3,6 +3,7 @@ from typing import Union
import discord
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.database.context.database_context_abc import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_query.extension import List
from discord.ext.commands import Context
@ -10,14 +11,17 @@ from discord.ext.commands import Context
from gismo_core.abc.bot_service_abc import BotServiceABC
from gismo_core.abc.message_service_abc import MessageServiceABC
from gismo_core.configuration.server_settings import ServerSettings
from gismo_data.abc.client_repository_abc import ClientRepositoryABC
class MessageService(MessageServiceABC):
def __init__(self, config: ConfigurationABC, logger: LoggerABC, bot: BotServiceABC):
def __init__(self, config: ConfigurationABC, logger: LoggerABC, bot: BotServiceABC, clients: ClientRepositoryABC, db: DatabaseContextABC):
self._config = config
self._logger = logger
self._bot = bot
self._clients = clients
self._db = db
async def delete_messages(self, messages: List[discord.Message]):
self._logger.debug(__name__, f'Try to delete {messages.count()} messages')
@ -29,11 +33,14 @@ class MessageService(MessageServiceABC):
server_st: ServerSettings = self._config.get_configuration(f'DSERVER_{message.guild.id}')
await asyncio.sleep(server_st.message_delete_timer)
self._logger.debug(__name__, f'Try to delete message:\n\t{message}\n\t{message.content}')
guild_id = message.guild.id
try:
await message.delete()
except Exception as e:
self._logger.error(__name__, f'Deleting message failed', e)
else:
self._clients.apppend_deleted_message_count(self._bot.user.id, guild_id, 1)
self._db.save_changes()
self._logger.info(__name__, f'Deleted message {message}')
async def send_channel_message(self, channel: discord.TextChannel, message: str):
@ -45,6 +52,8 @@ class MessageService(MessageServiceABC):
self._logger.error(__name__, f'Send message to channel {channel.id} failed', e)
else:
self._logger.info(__name__, f'Sent message to channel {channel.id}')
self._clients.apppend_sent_message_count(self._bot.user.id, channel.guild.id, 1)
self._db.save_changes()
await self.delete_message(msg)
async def send_dm_message(self, message: str, receiver: Union[discord.User, discord.Member]):
@ -54,6 +63,8 @@ class MessageService(MessageServiceABC):
except Exception as e:
self._logger.error(__name__, f'Send message to user {receiver.id} failed', e)
else:
self._clients.apppend_sent_message_count(self._bot.user.id, receiver.guild.id, 1)
self._db.save_changes()
self._logger.info(__name__, f'Sent message to user {receiver.id}')
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.File]):
@ -73,4 +84,6 @@ class MessageService(MessageServiceABC):
self._logger.error(__name__, f'Send message to channel {ctx.channel.id} failed', e)
else:
self._logger.info(__name__, f'Sent message to channel {ctx.channel.id}')
self._clients.apppend_sent_message_count(self._bot.user.id, ctx.guild.id, 1)
self._db.save_changes()
await self.delete_message(msg)

View File

@ -1 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'gismo_data'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -1 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'gismo_data.abc'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,53 @@
from abc import ABC, abstractmethod
from typing import Optional
from cpl_query.extension import List
from gismo_data.model.client import Client
class ClientRepositoryABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def get_clients(self) -> List[Client]: pass
@abstractmethod
def get_client_by_id(self, id: int) -> Client: pass
@abstractmethod
def get_client_by_discord_id(self, discord_id: int) -> Client: pass
@abstractmethod
def find_client_by_discord_id(self, discord_id: int) -> Optional[Client]: pass
@abstractmethod
def find_client_by_server_id(self, server_id: int) -> Optional[Client]: pass
@abstractmethod
def find_client_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> Optional[Client]: pass
@abstractmethod
def add_client(self, client: Client): pass
@abstractmethod
def update_client(self, client: Client): pass
@abstractmethod
def delete_client(self, client: Client): pass
@abstractmethod
def apppend_sent_message_count(self, id: int, server_id: int, value: int): pass
@abstractmethod
def apppend_received_message_count(self, id: int, server_id: int, value: int): pass
@abstractmethod
def apppend_deleted_message_count(self, id: int, server_id: int, value: int): pass
@abstractmethod
def apppend_received_command_count(self, id: int, server_id: int, value: int): pass
@abstractmethod
def apppend_moved_users_count(self, id: int, server_id: int, value: int): pass

View File

@ -0,0 +1,30 @@
from abc import ABC, abstractmethod
from typing import Optional
from cpl_query.extension import List
from gismo_data.model.known_user import KnownUser
class KnownUserRepositoryABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def get_users(self) -> List[KnownUser]: pass
@abstractmethod
def get_user_by_id(self, id: int) -> KnownUser: pass
@abstractmethod
def get_user_by_discord_id(self, discord_id: int) -> KnownUser: pass
@abstractmethod
def find_user_by_discord_id(self, discord_id: int) -> Optional[KnownUser]: pass
@abstractmethod
def add_user(self, known_user: KnownUser): pass
@abstractmethod
def delete_user(self, known_user: KnownUser): pass

View File

@ -0,0 +1,13 @@
from abc import ABC, abstractmethod
class MigrationABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def upgrade(self): pass
@abstractmethod
def downgrade(self): pass

View File

@ -0,0 +1,35 @@
from abc import ABC, abstractmethod
from typing import Optional
from cpl_query.extension import List
from gismo_data.model.user_joined_server import UserJoinedServer
class UserJoinedServerRepositoryABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def get_user_joined_servers(self) -> List[UserJoinedServer]: pass
@abstractmethod
def get_user_joined_server_by_id(self, id: int) -> UserJoinedServer: pass
@abstractmethod
def get_user_joined_servers_by_user_id(self, user_id: int) -> list[UserJoinedServer]: pass
@abstractmethod
def get_active_user_joined_server_by_user_id(self, user_id: int) -> UserJoinedServer: pass
@abstractmethod
def find_active_user_joined_server_by_user_id(self, user_id: int) -> Optional[UserJoinedServer]: pass
@abstractmethod
def add_user_joined_server(self, user_joined_server: UserJoinedServer): pass
@abstractmethod
def update_user_joined_server(self, user_joined_server: UserJoinedServer): pass
@abstractmethod
def delete_user_joined_server(self, user_joined_server: UserJoinedServer): pass

View File

@ -0,0 +1,34 @@
from abc import ABC, abstractmethod
from typing import Optional
from cpl_query.extension import List
from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
class UserJoinedVoiceChannelRepositoryABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def get_user_joined_voice_channels(self) -> List[UserJoinedVoiceChannel]: pass
@abstractmethod
def get_user_joined_voice_channel_by_id(self, id: int) -> UserJoinedVoiceChannel: pass
@abstractmethod
def get_user_joined_voice_channels_by_user_id(self, user_id: int) -> list[UserJoinedVoiceChannel]: pass
@abstractmethod
def get_active_user_joined_voice_channel_by_user_id(self, user_id: int) -> UserJoinedVoiceChannel: pass
@abstractmethod
def find_active_user_joined_voice_channel_by_user_id(self, user_id: int) -> Optional[UserJoinedVoiceChannel]: pass
@abstractmethod
def add_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel): pass
@abstractmethod
def update_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel): pass
@abstractmethod
def delete_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel): pass

View File

@ -18,10 +18,13 @@ class UserRepositoryABC(ABC):
def get_user_by_id(self, id: int) -> User: pass
@abstractmethod
def get_user_by_discord_id(self, discord_id: int) -> User: pass
def get_users_by_discord_id(self, discord_id: int) -> List[User]: pass
@abstractmethod
def find_user_by_discord_id(self, discord_id: int) -> Optional[User]: pass
def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User: pass
@abstractmethod
def find_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> Optional[User]: pass
@abstractmethod
def add_user(self, user: User): pass

View File

@ -16,10 +16,6 @@ class DBContext(DatabaseContext):
try:
self._logger.debug(__name__, "Connecting to database")
self._db.connect(database_settings)
for table in self._tables:
self._logger.debug(__name__, f"Create table if not exists: {table}")
self._logger.trace(__name__, f'Send SQL command: {table.get_create_string()}')
self._db.cursor.execute(table.get_create_string())
self.save_changes()
self._logger.info(__name__, "Connected to database")

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'gismo_data.migration'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,57 @@
from cpl_core.logging import LoggerABC
from gismo_data.abc.migration_abc import MigrationABC
from gismo_data.db_context import DBContext
class InitialMigration(MigrationABC):
def __init__(self, logger: LoggerABC, db: DBContext):
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, 'Running upgrade')
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `MigrationHistory` (
`MigrationId` VARCHAR(255),
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`MigrationId`)
);
""")
)
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `Servers` (
`ServerId` BIGINT NOT NULL AUTO_INCREMENT,
`DiscordServerId` BIGINT NOT NULL,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`ServerId`)
);
""")
)
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `Users` (
`UserId` BIGINT NOT NULL AUTO_INCREMENT,
`DiscordId` BIGINT NOT NULL,
`XP` BIGINT NOT NULL DEFAULT 0,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
FOREIGN KEY (`ServerId`) REFERENCES Servers(`ServerId`),
PRIMARY KEY(`UserId`)
);
""")
)
def downgrade(self):
self._cursor.execute('DROP TABLE `Servers`;')
self._cursor.execute('DROP TABLE `Users`;')

View File

@ -0,0 +1,65 @@
from cpl_core.logging import LoggerABC
from gismo_data.abc.migration_abc import MigrationABC
from gismo_data.db_context import DBContext
class Migration_0_3(MigrationABC):
def __init__(self, logger: LoggerABC, db: DBContext):
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, 'Running upgrade')
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `Clients` (
`ClientId` BIGINT NOT NULL AUTO_INCREMENT,
`DiscordClientId` BIGINT NOT NULL,
`SentMessageCount` BIGINT NOT NULL DEFAULT 0,
`ReceivedMessageCount` BIGINT NOT NULL DEFAULT 0,
`DeletedMessageCount` BIGINT NOT NULL DEFAULT 0,
`ReceivedCommandsCount` BIGINT NOT NULL DEFAULT 0,
`MovedUsersCount` BIGINT NOT NULL DEFAULT 0,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
FOREIGN KEY (`ServerId`) REFERENCES Servers(`ServerId`),
PRIMARY KEY(`ClientId`)
);
""")
)
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `KnownUsers` (
`KnownUserId` BIGINT NOT NULL AUTO_INCREMENT,
`DiscordId` BIGINT NOT NULL,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`KnownUserId`)
);
""")
)
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `UserJoinedServers` (
`JoinId` BIGINT NOT NULL AUTO_INCREMENT,
`UserId` BIGINT NOT NULL,
`JoinedOn` DATETIME(6) NOT NULL,
`LeavedOn` DATETIME(6),
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
FOREIGN KEY (`UserId`) REFERENCES Users(`UserId`),
PRIMARY KEY(`JoinId`)
);
""")
)
def downgrade(self):
self._cursor.execute('DROP TABLE `Clients`;')
self._cursor.execute('DROP TABLE `KnownUsers`;')
self._cursor.execute('DROP TABLE `UserJoinedServers`;')

View File

@ -0,0 +1,35 @@
from cpl_core.logging import LoggerABC
from gismo_data.abc.migration_abc import MigrationABC
from gismo_data.db_context import DBContext
class Migration_0_3_1(MigrationABC):
def __init__(self, logger: LoggerABC, db: DBContext):
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, 'Running upgrade')
self._cursor.execute(
str(f"""
CREATE TABLE IF NOT EXISTS `UserJoinedVoiceChannel` (
`JoinId` BIGINT NOT NULL AUTO_INCREMENT,
`UserId` BIGINT NOT NULL,
`DiscordChannelId` BIGINT NOT NULL,
`JoinedOn` DATETIME(6) NOT NULL,
`LeavedOn` DATETIME(6),
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
FOREIGN KEY (`UserId`) REFERENCES Users(`UserId`),
PRIMARY KEY(`JoinId`)
);
""")
)
def downgrade(self):
self._logger.debug(__name__, 'Running downgrade')
self._cursor.execute('DROP TABLE `UserJoinedVoiceChannel`;')

View File

@ -1 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'gismo_data.model'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,170 @@
from datetime import datetime
from cpl_core.database import TableABC
from gismo_data.model.server import Server
class Client(TableABC):
def __init__(self,
dc_id: int,
smc: int,
rmc: int,
dmc: int,
rcc: int,
muc: int,
server: Server,
created_at: datetime = None,
modified_at: datetime = None,
id=0
):
self._client_id = id
self._discord_client_id = dc_id
self._sent_message_count = smc
self._received_message_count = rmc
self._deleted_message_count = dmc
self._received_command_count = rcc
self._moved_users_count = muc
self._server: Server = server
TableABC.__init__(self)
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
@property
def client_id(self) -> int:
return self._client_id
@property
def discord_id(self) -> int:
return self._discord_client_id
@property
def sent_message_count(self) -> int:
return self._sent_message_count
@sent_message_count.setter
def sent_message_count(self, value: int):
self._modified_at = datetime.now().isoformat()
self._sent_message_count = value
@property
def received_message_count(self) -> int:
return self._received_message_count
@received_message_count.setter
def received_message_count(self, value: int):
self._modified_at = datetime.now().isoformat()
self._received_message_count = value
@property
def deleted_message_count(self) -> int:
return self._deleted_message_count
@deleted_message_count.setter
def deleted_message_count(self, value: int):
self._modified_at = datetime.now().isoformat()
self._deleted_message_count = value
@property
def received_command_count(self) -> int:
return self._received_command_count
@received_command_count.setter
def received_command_count(self, value: int):
self._modified_at = datetime.now().isoformat()
self._received_command_count = value
@property
def moved_users_count(self) -> int:
return self._moved_users_count
@moved_users_count.setter
def moved_users_count(self, value: int):
self._modified_at = datetime.now().isoformat()
self._moved_users_count = value
@property
def server(self) -> Server:
return self._server
@staticmethod
def get_select_all_string() -> str:
return str(f"""
SELECT * FROM `Clients`;
""")
@staticmethod
def get_select_by_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `Clients`
WHERE `ClientId` = {id};
""")
@staticmethod
def get_select_by_discord_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `Clients`
WHERE `DiscordClientId` = {id};
""")
@staticmethod
def get_select_by_server_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `Clients`
WHERE `ServerId` = {id};
""")
@staticmethod
def get_select_by_discord_id_and_server_id_string(id: int, server_id: int) -> str:
return str(f"""
SELECT * FROM `Clients`
WHERE `DiscordClientId` = {id}
AND `ServerId` = {server_id};
""")
@property
def insert_string(self) -> str:
return str(f"""
INSERT INTO `Clients` (
`DiscordClientId`,
`SentMessageCount`,
`ReceivedMessageCount`,
`DeletedMessageCount`,
`ReceivedCommandsCount`,
`MovedUsersCount`,
`ServerId`,
`CreatedAt`,
`LastModifiedAt`
) VALUES (
{self._discord_client_id},
{self._sent_message_count},
{self._received_message_count},
{self._deleted_message_count},
{self._received_message_count},
{self._moved_users_count},
{self._server.server_id},
'{self._created_at}',
'{self._modified_at}'
);
""")
@property
def udpate_string(self) -> str:
return str(f"""
UPDATE `Clients`
SET `SentMessageCount` = {self._sent_message_count},
`ReceivedMessageCount` = {self._received_message_count},
`DeletedMessageCount` = {self._deleted_message_count},
`ReceivedCommandsCount` = {self._received_command_count},
`MovedUsersCount` = {self._moved_users_count},
`LastModifiedAt` = '{self._modified_at}'
WHERE `ClientId` = {self._client_id};
""")
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `Clients`
WHERE `ClientId` = {self._client_id};
""")

View File

@ -0,0 +1,67 @@
from datetime import datetime
from typing import Optional
from cpl_core.database import TableABC
from gismo_data.model.server import Server
class KnownUser(TableABC):
def __init__(self, dc_id: int, created_at: datetime = None, modified_at: datetime = None, id=0):
self._known_user_id = id
self._discord_id = dc_id
TableABC.__init__(self)
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
@property
def known_user_id(self) -> int:
return self._known_user_id
@property
def discord_id(self) -> int:
return self._discord_id
@staticmethod
def get_select_all_string() -> str:
return str(f"""
SELECT * FROM `KnownUsers`;
""")
@staticmethod
def get_select_by_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `KnownUsers`
WHERE `KnownUserId` = {id};
""")
@staticmethod
def get_select_by_discord_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `KnownUsers`
WHERE `DiscordId` = {id};
""")
@property
def insert_string(self) -> str:
return str(f"""
INSERT INTO `KnownUsers` (
`DiscordId`, `CreatedAt`, `LastModifiedAt`
) VALUES (
{self._discord_id},
'{self._created_at}',
'{self._modified_at}'
);
""")
@property
def udpate_string(self) -> str:
return ''
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `KnownUsers`
WHERE `Id` = {self._known_user_id};
""")

View File

@ -0,0 +1,47 @@
from cpl_core.database import TableABC
class MigrationHistory(TableABC):
def __init__(self, id: str):
self._id = id
TableABC.__init__(self)
@property
def migration_id(self) -> str:
return self._id
@staticmethod
def get_select_by_id_string(id: str) -> str:
return str(f"""
SELECT * FROM `MigrationHistory`
WHERE `MigrationId` = '{id}';
""")
@property
def insert_string(self) -> str:
return str(f"""
INSERT INTO `MigrationHistory` (
`MigrationId`, `CreatedAt`, `LastModifiedAt`
) VALUES (
'{self._id}',
'{self._created_at}',
'{self._modified_at}'
);
""")
@property
def udpate_string(self) -> str:
return str(f"""
UPDATE `MigrationHistory`
SET LastModifiedAt` = '{self._modified_at}'
WHERE `MigrationId` = '{self._id}';
""")
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `MigrationHistory`
WHERE `MigrationId` = '{self._id}';
""")

View File

@ -21,18 +21,6 @@ class Server(TableABC):
@property
def discord_server_id(self) -> int:
return self._discord_server_id
@staticmethod
def get_create_string() -> str:
return str(f"""
CREATE TABLE IF NOT EXISTS `Servers` (
`ServerId` BIGINT NOT NULL AUTO_INCREMENT,
`DiscordServerId` BIGINT NOT NULL,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`ServerId`)
);
""")
@staticmethod
def get_select_all_string() -> str:
@ -72,12 +60,12 @@ class Server(TableABC):
UPDATE `Servers`
SET `DiscordServerId` = {self._discord_server_id},
`LastModifiedAt` = '{self._modified_at}'
WHERE `Id` = {self._id};
WHERE `Id` = {self._server_id};
""")
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `Servers`
WHERE `Id` = {self._id};
WHERE `Id` = {self._server_id};
""")

View File

@ -38,21 +38,6 @@ class User(TableABC):
def server(self) -> Optional[Server]:
return self._server
@staticmethod
def get_create_string() -> str:
return str(f"""
CREATE TABLE IF NOT EXISTS `Users` (
`UserId` BIGINT NOT NULL AUTO_INCREMENT,
`DiscordId` BIGINT NOT NULL,
`XP` BIGINT NOT NULL DEFAULT 0,
`ServerId` BIGINT,
`CreatedAt` DATETIME(6),
`LastModifiedAt` DATETIME(6),
FOREIGN KEY (`ServerId`) REFERENCES Servers(`ServerId`),
PRIMARY KEY(`UserId`)
);
""")
@staticmethod
def get_select_all_string() -> str:
return str(f"""
@ -73,6 +58,14 @@ class User(TableABC):
WHERE `DiscordId` = {id};
""")
@staticmethod
def get_select_by_discord_id_and_server_id_string(dc_id: int, s_id: int) -> str:
return str(f"""
SELECT * FROM `Users`
WHERE `DiscordId` = {dc_id}
AND `ServerId` = {s_id};
""")
@property
def insert_string(self) -> str:
return str(f"""
@ -93,12 +86,12 @@ class User(TableABC):
UPDATE `Users`
SET `XP` = {self._xp},
`LastModifiedAt` = '{self._modified_at}'
WHERE `Id` = {self._id};
WHERE `UserId` = {self._user_id};
""")
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `Users`
WHERE `Id` = {self._id};
WHERE `UserId` = {self._user_id};
""")

View File

@ -0,0 +1,116 @@
from datetime import datetime
from typing import Optional
from cpl_core.database import TableABC
from gismo_data.model.user import User
from gismo_data.model.server import Server
class UserJoinedServer(TableABC):
def __init__(self, user: User, joined_on: datetime, leaved_on: datetime=None, created_at: datetime=None, modified_at: datetime=None, id=0):
self._join_id = id
self._user = user
self._joined_on = joined_on
self._leaved_on = leaved_on
TableABC.__init__(self)
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
@property
def join_id(self) -> int:
return self._join_id
@property
def user(self) -> User:
return self._user
@property
def joined_on(self) -> datetime:
return self._joined_on
@joined_on.setter
def joined_on(self, value: datetime):
self._modified_at = datetime.now()
self.joined_on = value
@property
def leaved_on(self) -> datetime:
return self._leaved_on
@leaved_on.setter
def leaved_on(self, value: datetime):
self._modified_at = datetime.now()
self._leaved_on = value
@staticmethod
def get_select_all_string() -> str:
return str(f"""
SELECT * FROM `UserJoinedServers`;
""")
@staticmethod
def get_select_by_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `UserJoinedServers`
WHERE `JoinId` = {id};
""")
@staticmethod
def get_select_by_user_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `UserJoinedServers`
WHERE `UserId` = {id};
""")
@staticmethod
def get_select_active_by_user_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `UserJoinedServers`
WHERE `UserId` = {id}
AND `LeavedOn` IS NULL;
""")
@property
def insert_string(self) -> str:
if self._leaved_on is not None:
return str(f"""
INSERT INTO `UserJoinedServers` (
`UserId`, `JoinedOn`, `LeavedOn`, `CreatedAt`, `LastModifiedAt`
) VALUES (
{self._user.user_id},
'{self._joined_on}',
'{self._leaved_on}',
'{self._created_at}',
'{self._modified_at}'
);
""")
else:
return str(f"""
INSERT INTO `UserJoinedServers` (
`UserId`, `JoinedOn`, `CreatedAt`, `LastModifiedAt`
) VALUES (
{self._user.user_id},
'{self._joined_on}',
'{self._created_at}',
'{self._modified_at}'
);
""")
@property
def udpate_string(self) -> str:
return str(f"""
UPDATE `UserJoinedServers`
SET `LeavedOn` = '{self._leaved_on}',
`LastModifiedAt` = '{self._modified_at}'
WHERE `UserId` = {self._user.user_id};
""")
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `UserJoinedServers`
WHERE `Id` = {self._join_id};
""")

View File

@ -0,0 +1,121 @@
from datetime import datetime
from cpl_core.database import TableABC
from gismo_data.model.user import User
class UserJoinedVoiceChannel(TableABC):
def __init__(self, user: User, dc_channel_id: int, joined_on: datetime, leaved_on: datetime = None, created_at: datetime = None, modified_at: datetime = None, id=0):
self._join_id = id
self._dc_channel_id = dc_channel_id
self._user = user
self._joined_on = joined_on
self._leaved_on = leaved_on
TableABC.__init__(self)
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
@property
def join_id(self) -> int:
return self._join_id
@property
def dc_channel_id(self) -> int:
return self._dc_channel_id
@property
def user(self) -> User:
return self._user
@property
def joined_on(self) -> datetime:
return self._joined_on
@joined_on.setter
def joined_on(self, value: datetime):
self._modified_at = datetime.now()
self.joined_on = value
@property
def leaved_on(self) -> datetime:
return self._leaved_on
@leaved_on.setter
def leaved_on(self, value: datetime):
self._modified_at = datetime.now()
self._leaved_on = value
@staticmethod
def get_select_all_string() -> str:
return str(f"""
SELECT * FROM `UserJoinedVoiceChannel`;
""")
@staticmethod
def get_select_by_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `UserJoinedVoiceChannel`
WHERE `JoinId` = {id};
""")
@staticmethod
def get_select_by_user_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `UserJoinedVoiceChannel`
WHERE `UserId` = {id};
""")
@staticmethod
def get_select_active_by_user_id_string(id: int) -> str:
return str(f"""
SELECT * FROM `UserJoinedVoiceChannel`
WHERE `UserId` = {id}
AND `LeavedOn` IS NULL;
""")
@property
def insert_string(self) -> str:
if self._leaved_on is not None:
return str(f"""
INSERT INTO `UserJoinedVoiceChannel` (
`UserId`, `DiscordChannelId`, `JoinedOn`, `LeavedOn`, `CreatedAt`, `LastModifiedAt`
) VALUES (
{self._user.user_id},
{self._dc_channel_id},
'{self._joined_on}',
'{self._leaved_on}',
'{self._created_at}',
'{self._modified_at}'
);
""")
else:
return str(f"""
INSERT INTO `UserJoinedVoiceChannel` (
`UserId`, `DiscordChannelId`, `JoinedOn`, `CreatedAt`, `LastModifiedAt`
) VALUES (
{self._user.user_id},
{self._dc_channel_id},
'{self._joined_on}',
'{self._created_at}',
'{self._modified_at}'
);
""")
@property
def udpate_string(self) -> str:
return str(f"""
UPDATE `UserJoinedVoiceChannel`
SET `LeavedOn` = '{self._leaved_on}',
`LastModifiedAt` = '{self._modified_at}'
WHERE `JoinId` = {self._join_id};
""")
@property
def delete_string(self) -> str:
return str(f"""
DELETE FROM `UserJoinedVoiceChannel`
WHERE `JoinId` = {self._join_id};
""")

View File

@ -1 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'gismo_data.service'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,173 @@
from typing import Optional
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_query.extension import List
from gismo_data.abc.client_repository_abc import ClientRepositoryABC
from gismo_data.abc.server_repository_abc import ServerRepositoryABC
from gismo_data.model.client import Client
class ClientRepositoryService(ClientRepositoryABC):
def __init__(self, logger: LoggerABC, db_context: DatabaseContextABC, servers: ServerRepositoryABC):
self._logger = logger
self._context = db_context
self._servers = servers
ClientRepositoryABC.__init__(self)
def get_clients(self) -> List[Client]:
clients = List(Client)
self._logger.trace(__name__, f'Send SQL command: {Client.get_select_all_string()}')
results = self._context.select(Client.get_select_all_string())
for result in results:
self._logger.trace(__name__, f'Get client with id {result[0]}')
clients.append(Client(
result[1],
result[2],
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[7]),
id=result[0]
))
return clients
def get_client_by_id(self, id: int) -> Client:
self._logger.trace(__name__, f'Send SQL command: {Client.get_select_by_id_string(id)}')
result = self._context.select(Client.get_select_by_id_string(id))
return Client(
result[1],
result[2],
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[7]),
id=result[0]
)
def get_client_by_discord_id(self, discord_id: int) -> Client:
self._logger.trace(__name__, f'Send SQL command: {Client.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(Client.get_select_by_discord_id_string(discord_id))[0]
return Client(
result[1],
result[2],
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[7]),
id=result[0]
)
def find_client_by_discord_id(self, discord_id: int) -> Optional[Client]:
self._logger.trace(__name__, f'Send SQL command: {Client.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(Client.get_select_by_discord_id_string(discord_id))
if result is None or len(result) == 0:
return None
result = result[0]
return Client(
result[1],
result[2],
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[7]),
id=result[0]
)
def find_client_by_server_id(self, discord_id: int) -> Optional[Client]:
self._logger.trace(__name__, f'Send SQL command: {Client.get_select_by_server_id_string(discord_id)}')
result = self._context.select(Client.get_select_by_server_id_string(discord_id))
if result is None or len(result) == 0:
return None
result = result[0]
return Client(
result[1],
result[2],
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[7]),
id=result[0]
)
def find_client_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> Optional[Client]:
self._logger.trace(__name__, f'Send SQL command: {Client.get_select_by_discord_id_and_server_id_string(discord_id, server_id)}')
result = self._context.select(Client.get_select_by_discord_id_and_server_id_string(discord_id, server_id))
if result is None or len(result) == 0:
return None
result = result[0]
return Client(
result[1],
result[2],
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[7]),
id=result[0]
)
def add_client(self, client: Client):
self._logger.trace(__name__, f'Send SQL command: {client.insert_string}')
self._context.cursor.execute(client.insert_string)
def update_client(self, client: Client):
self._logger.trace(__name__, f'Send SQL command: {client.udpate_string}')
self._context.cursor.execute(client.udpate_string)
def delete_client(self, client: Client):
self._logger.trace(__name__, f'Send SQL command: {client.delete_string}')
self._context.cursor.execute(client.delete_string)
def _get_client_and_server(self, id: int, server_id: int) -> Client:
server = self._servers.find_server_by_discord_id(server_id)
if server is None:
self._logger.warn(__name__, f'Cannot find server by id {server_id}')
raise Exception('Value not found')
client = self.find_client_by_discord_id_and_server_id(id, server.server_id)
if client is None:
self._logger.warn(__name__, f'Cannot find client by ids {id}@{server.server_id}')
raise Exception('Value not found')
return client
def apppend_sent_message_count(self, id: int, server_id: int, value: int):
client = self._get_client_and_server(id, server_id)
client.sent_message_count += value
self.update_client(client)
def apppend_received_message_count(self, id: int, server_id: int, value: int):
client = self._get_client_and_server(id, server_id)
client.received_message_count += value
self.update_client(client)
def apppend_deleted_message_count(self, id: int, server_id: int, value: int):
client = self._get_client_and_server(id, server_id)
client.deleted_message_count += value
self.update_client(client)
def apppend_received_command_count(self, id: int, server_id: int, value: int):
client = self._get_client_and_server(id, server_id)
client.received_command_count += value
self.update_client(client)
def apppend_moved_users_count(self, id: int, server_id: int, value: int):
client = self._get_client_and_server(id, server_id)
client.moved_users_count += value
self.update_client(client)

View File

@ -0,0 +1,77 @@
from typing import Optional
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_query.extension import List
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from gismo_data.abc.server_repository_abc import ServerRepositoryABC
from gismo_data.model.known_user import KnownUser
class KnownUserRepositoryService(KnownUserRepositoryABC):
def __init__(self, logger: LoggerABC, db_context: DatabaseContextABC, servers: ServerRepositoryABC):
self._logger = logger
self._context = db_context
self._servers = servers
KnownUserRepositoryABC.__init__(self)
def get_users(self) -> List[KnownUser]:
users = List(KnownUser)
self._logger.trace(__name__, f'Send SQL command: {KnownUser.get_select_all_string()}')
results = self._context.select(KnownUser.get_select_all_string())
for result in results:
self._logger.trace(__name__, f'Get known_user with id {result[0]}')
users.append(KnownUser(
result[1],
result[2],
self._servers.get_server_by_id(result[3]),
id=result[0]
))
return users
def get_user_by_id(self, id: int) -> KnownUser:
self._logger.trace(__name__, f'Send SQL command: {KnownUser.get_select_by_id_string(id)}')
result = self._context.select(KnownUser.get_select_by_id_string(id))
return KnownUser(
result[1],
result[2],
self._servers.get_server_by_id(result[3]),
id=result[0]
)
def get_user_by_discord_id(self, discord_id: int) -> KnownUser:
self._logger.trace(__name__, f'Send SQL command: {KnownUser.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(KnownUser.get_select_by_discord_id_string(discord_id))[0]
return KnownUser(
result[1],
result[2],
self._servers.get_server_by_id(result[3]),
id=result[0]
)
def find_user_by_discord_id(self, discord_id: int) -> Optional[KnownUser]:
self._logger.trace(__name__, f'Send SQL command: {KnownUser.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(KnownUser.get_select_by_discord_id_string(discord_id))
if result is None or len(result) == 0:
return None
result = result[0]
return KnownUser(
result[1],
result[2],
result[3],
id=result[0]
)
def add_user(self, known_user: KnownUser):
self._logger.trace(__name__, f'Send SQL command: {known_user.insert_string}')
self._context.cursor.execute(known_user.insert_string)
def delete_user(self, known_user: KnownUser):
self._logger.trace(__name__, f'Send SQL command: {known_user.delete_string}')
self._context.cursor.execute(known_user.delete_string)

View File

@ -0,0 +1,43 @@
from cpl_core.database.context import DatabaseContextABC
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.logging import LoggerABC
from gismo_data.abc.migration_abc import MigrationABC
from gismo_data.model.migration_history import MigrationHistory
class MigrationService:
def __init__(self, logger: LoggerABC, services: ServiceProviderABC, db: DatabaseContextABC):
self._logger = logger
self._services = services
self._db = db
self._cursor = db.cursor
self._migrations: list[MigrationABC] = MigrationABC.__subclasses__()
def migrate(self):
self._logger.info(__name__, f"Running Migrations")
for migration in self._migrations:
migration_id = migration.__name__
try:
# check if table exists
self._cursor.execute("SHOW TABLES LIKE 'MigrationHistory'")
result = self._cursor.fetchone()
if result:
# there is a table named "tableName"
self._logger.trace(__name__, f"Running SQL Command: {MigrationHistory.get_select_by_id_string(migration_id)}")
migration_from_db: MigrationHistory = self._db.select(MigrationHistory.get_select_by_id_string(migration_id))
self._logger.trace(__name__, migration_from_db)
if migration_from_db is not None and len(migration_from_db) > 0:
continue
self._logger.debug(__name__, f"Running Migration {migration}")
migration_as_service: MigrationABC = self._services.get_service(migration)
migration_as_service.upgrade()
self._cursor.execute(MigrationHistory(migration_id).insert_string)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get migration with id {migration}', e)

View File

@ -37,7 +37,7 @@ class ServerRepositoryService(ServerRepositoryABC):
def get_server_by_discord_id(self, discord_id: int) -> Server:
self._logger.trace(__name__, f'Send SQL command: {Server.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(Server.get_select_by_discord_id_string(discord_id))
result = self._context.select(Server.get_select_by_discord_id_string(discord_id))[0]
return Server(
result[1],
id=result[0]

View File

@ -0,0 +1,107 @@
from typing import Optional
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_query.extension import List
from gismo_data.abc.user_joined_server_repository_abc import \
UserJoinedServerRepositoryABC
from gismo_data.abc.user_repository_abc import UserRepositoryABC
from gismo_data.model.user import User
from gismo_data.model.user_joined_server import UserJoinedServer
class UserJoinedServerRepositoryService(UserJoinedServerRepositoryABC):
def __init__(self, logger: LoggerABC, db_context: DatabaseContextABC, users: UserRepositoryABC):
self._logger = logger
self._context = db_context
self._users = users
UserJoinedServerRepositoryABC.__init__(self)
def get_user_joined_servers(self) -> List[UserJoinedServer]:
joins = List(UserJoinedServer)
self._logger.trace(__name__, f'Send SQL command: {UserJoinedServer.get_select_all_string()}')
results = self._context.select(UserJoinedServer.get_select_all_string())
for result in results:
self._logger.trace(__name__, f'Get user-joined-server with id {result[0]}')
joins.append(UserJoinedServer(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
))
return joins
def get_user_joined_server_by_id(self, id: int) -> UserJoinedServer:
self._logger.trace(__name__, f'Send SQL command: {UserJoinedServer.get_select_by_id_string(id)}')
result = self._context.select(UserJoinedServer.get_select_by_id_string(id))[0]
return UserJoinedServer(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
)
def get_user_joined_servers_by_user_id(self, user_id: int) -> List[UserJoinedServer]:
joins = List(UserJoinedServer)
self._logger.trace(__name__, f'Send SQL command: {UserJoinedServer.get_select_by_user_id_string(user_id)}')
results = self._context.select(UserJoinedServer.get_select_by_user_id_string(user_id))
for result in results:
joins.append(UserJoinedServer(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
))
return joins
def get_active_user_joined_server_by_user_id(self, user_id: int) -> UserJoinedServer:
self._logger.trace(__name__, f'Send SQL command: {UserJoinedServer.get_select_by_user_id_string(user_id)}')
result = self._context.select(UserJoinedServer.get_select_active_by_user_id_string(user_id))[0]
return UserJoinedServer(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
)
def find_active_user_joined_server_by_user_id(self, user_id: int) -> Optional[UserJoinedServer]:
self._logger.trace(__name__, f'Send SQL command: {UserJoinedServer.get_select_by_user_id_string(user_id)}')
result = self._context.select(UserJoinedServer.get_select_active_by_user_id_string(user_id))
if result is None or len(result) == 0:
return None
result = result[0]
return UserJoinedServer(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
)
def add_user_joined_server(self, user_joined_server: UserJoinedServer):
self._logger.trace(__name__, f'Send SQL command: {user_joined_server.insert_string}')
self._context.cursor.execute(user_joined_server.insert_string)
def update_user_joined_server(self, user_joined_server: UserJoinedServer):
self._logger.trace(__name__, f'Send SQL command: {user_joined_server.udpate_string}')
self._context.cursor.execute(user_joined_server.udpate_string)
def delete_user_joined_server(self, user_joined_server: UserJoinedServer):
self._logger.trace(__name__, f'Send SQL command: {user_joined_server.delete_string}')
self._context.cursor.execute(user_joined_server.delete_string)

View File

@ -0,0 +1,107 @@
from typing import Optional
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_query.extension import List
from gismo_data.abc.user_repository_abc import UserRepositoryABC
from gismo_data.model.user import User
from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
class UserJoinedVoiceChannelRepositoryService(UserJoinedVoiceChannelRepositoryABC):
def __init__(self, logger: LoggerABC, db_context: DatabaseContextABC, users: UserRepositoryABC):
self._logger = logger
self._context = db_context
self._users = users
UserJoinedVoiceChannelRepositoryABC.__init__(self)
def get_user_joined_voice_channels(self) -> List[UserJoinedVoiceChannel]:
joins = List(UserJoinedVoiceChannel)
self._logger.trace(__name__, f'Send SQL command: {UserJoinedVoiceChannel.get_select_all_string()}')
results = self._context.select(UserJoinedVoiceChannel.get_select_all_string())
for result in results:
self._logger.trace(__name__, f'Get user-joined-voice-channel with id {result[0]}')
joins.append(UserJoinedVoiceChannel(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
))
return joins
def get_user_joined_voice_channel_by_id(self, id: int) -> UserJoinedVoiceChannel:
self._logger.trace(__name__, f'Send SQL command: {UserJoinedVoiceChannel.get_select_by_id_string(id)}')
result = self._context.select(UserJoinedVoiceChannel.get_select_by_id_string(id))[0]
return UserJoinedVoiceChannel(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
)
def get_user_joined_voice_channels_by_user_id(self, user_id: int) -> List[UserJoinedVoiceChannel]:
joins = List(UserJoinedVoiceChannel)
self._logger.trace(__name__, f'Send SQL command: {UserJoinedVoiceChannel.get_select_by_user_id_string(user_id)}')
results = self._context.select(UserJoinedVoiceChannel.get_select_by_user_id_string(user_id))
for result in results:
joins.append(UserJoinedVoiceChannel(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
))
return joins
def get_active_user_joined_voice_channel_by_user_id(self, user_id: int) -> UserJoinedVoiceChannel:
self._logger.trace(__name__, f'Send SQL command: {UserJoinedVoiceChannel.get_select_by_user_id_string(user_id)}')
result = self._context.select(UserJoinedVoiceChannel.get_select_active_by_user_id_string(user_id))[0]
return UserJoinedVoiceChannel(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
)
def find_active_user_joined_voice_channel_by_user_id(self, user_id: int) -> Optional[UserJoinedVoiceChannel]:
self._logger.trace(__name__, f'Send SQL command: {UserJoinedVoiceChannel.get_select_by_user_id_string(user_id)}')
result = self._context.select(UserJoinedVoiceChannel.get_select_active_by_user_id_string(user_id))
if result is None or len(result) == 0:
return None
result = result[0]
return UserJoinedVoiceChannel(
self._users.get_user_by_id(result[1]),
result[2],
result[3],
result[4],
result[5],
id=result[0]
)
def add_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel):
self._logger.trace(__name__, f'Send SQL command: {user_joined_voice_channel.insert_string}')
self._context.cursor.execute(user_joined_voice_channel.insert_string)
def update_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel):
self._logger.trace(__name__, f'Send SQL command: {user_joined_voice_channel.udpate_string}')
self._context.cursor.execute(user_joined_voice_channel.udpate_string)
def delete_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel):
self._logger.trace(__name__, f'Send SQL command: {user_joined_voice_channel.delete_string}')
self._context.cursor.execute(user_joined_voice_channel.delete_string)

View File

@ -35,7 +35,31 @@ class UserRepositoryService(UserRepositoryABC):
def get_user_by_id(self, id: int) -> User:
self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_id_string(id)}')
result = self._context.select(User.get_select_by_id_string(id))
result = self._context.select(User.get_select_by_id_string(id))[0]
return User(
result[1],
result[2],
self._servers.get_server_by_id(result[3]),
id=result[0]
)
def get_users_by_discord_id(self, discord_id: int) -> List[User]:
users = List(User)
self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_discord_id_string(discord_id)}')
results = self._context.select(User.get_select_by_discord_id_string(discord_id))
for result in results:
users.append(User(
result[1],
result[2],
self._servers.get_server_by_id(result[3]),
id=result[0]
))
def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User:
self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_discord_id_and_server_id_string(discord_id, server_id)}')
result = self._context.select(User.get_select_by_discord_id_and_server_id_string(discord_id, server_id))[0]
return User(
result[1],
result[2],
@ -43,19 +67,9 @@ class UserRepositoryService(UserRepositoryABC):
id=result[0]
)
def get_user_by_discord_id(self, discord_id: int) -> User:
self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(User.get_select_by_discord_id_string(discord_id))[0]
return User(
result[1],
result[2],
self._servers.get_server_by_id(result[3]),
id=result[0]
)
def find_user_by_discord_id(self, discord_id: int) -> Optional[User]:
self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_discord_id_string(discord_id)}')
result = self._context.select(User.get_select_by_discord_id_string(discord_id))
def find_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> Optional[User]:
self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_discord_id_and_server_id_string(discord_id, server_id)}')
result = self._context.select(User.get_select_by_discord_id_and_server_id_string(discord_id, server_id))
if result is None or len(result) == 0:
return None

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.base'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -0,0 +1,43 @@
{
"ProjectSettings": {
"Name": "modules/base",
"Version": {
"Major": "0",
"Minor": "0",
"Micro": "0"
},
"Author": "",
"AuthorEmail": "",
"Description": "",
"LongDescription": "",
"URL": "",
"CopyrightDate": "",
"CopyrightName": "",
"LicenseName": "",
"LicenseDescription": "",
"Dependencies": [
"sh_cpl-core>=2021.11.0.post1"
],
"PythonVersion": ">=3.9.2",
"PythonPath": {
"linux": ""
},
"Classifiers": []
},
"BuildSettings": {
"ProjectType": "library",
"SourcePath": "",
"OutputPath": "../../dist",
"Main": "modules/base.main",
"EntryPoint": "modules/base",
"IncludePackageData": false,
"Included": [],
"Excluded": [
"*/__pycache__",
"*/logs",
"*/tests"
],
"PackageData": {},
"ProjectReferences": []
}
}

262
src/modules/base/base.py Normal file
View File

@ -0,0 +1,262 @@
from datetime import datetime
from typing import Union
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging.logger_abc import LoggerABC
from gismo_core.abc.bot_service_abc import BotServiceABC
from gismo_core.abc.message_service_abc import MessageServiceABC
from gismo_core.configuration.server_settings import ServerSettings
from gismo_data.abc.client_repository_abc import ClientRepositoryABC
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from gismo_data.abc.server_repository_abc import ServerRepositoryABC
from gismo_data.abc.user_joined_server_repository_abc import \
UserJoinedServerRepositoryABC
from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
from gismo_data.abc.user_repository_abc import UserRepositoryABC
from gismo_data.model.known_user import KnownUser
from gismo_data.model.user import User
from gismo_data.model.user_joined_server import UserJoinedServer
from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from modules_core.abc.events.on_member_join_abc import OnMemberJoinABC
from modules_core.abc.events.on_member_remove_abc import OnMemberRemoveABC
from modules_core.abc.events.on_message_abc import OnMessageABC
from modules_core.abc.events.on_voice_state_update_abc import \
OnVoiceStateUpdateABC
from modules_core.abc.module_abc import ModuleABC
class Base(ModuleABC, OnMemberJoinABC, OnMemberRemoveABC, OnMessageABC, OnVoiceStateUpdateABC):
def __init__(
self,
config: ConfigurationABC,
logger: LoggerABC,
clients: ClientRepositoryABC,
servers: ServerRepositoryABC,
known_users: KnownUserRepositoryABC,
users: UserRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
bot: BotServiceABC,
db: DatabaseContextABC,
messenger: MessageServiceABC
):
self._config = config
self._logger = logger
self._clients = clients
self._servers = servers
self._known_users = known_users
self._users = users
self._user_joins = user_joins
self._user_joins_vc = user_joins_vc
self._bot = bot
self._db = db
self._messenger = messenger
ModuleABC.__init__(self)
self._priorities[OnMemberJoinABC] = 1
self._priorities[OnMemberRemoveABC] = 1
self._priorities[OnMessageABC] = 30
self._priorities[OnVoiceStateUpdateABC] = 10
self._logger.trace(__name__, f'Module {type(self)} loaded')
def _apppend_received_message_count(self, g_id: int):
try:
self._clients.apppend_received_message_count(self._bot.user.id, g_id, 1)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot edit client {self._bot.user.id}@{g_id}')
def _apppend_deleted_message_count(self, g_id: int):
try:
self._clients.apppend_received_message_count(self._bot.user.id, g_id, 1)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot edit client {self._bot.user.id}@{g_id}')
def _check_for_known_user(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Check if user is already known {member}')
try:
user = self._known_users.find_user_by_discord_id(member.id)
if user is not None:
return
self._logger.debug(__name__, f'Add user: {member.id}')
self._known_users.add_user(KnownUser(member.id))
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get user {member.id}', e)
async def _add_if_not_exists_user(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Check if user exists {member}')
settings: ServerSettings = self._config.get_configuration(f'DSERVER_{member.guild.id}')
await self._messenger.send_dm_message(settings.welcome_message.format(member.guild.name), member)
for roleId in settings.admin_roles:
g: discord.Guild = member.guild
role: discord.Role = g.get_role(roleId)
for admin in role.members:
await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), admin)
for roleId in settings.moderator_roles:
g: discord.Guild = member.guild
role: discord.Role = g.get_role(roleId)
for mod in role.members:
await self._messenger.send_dm_message(settings.welcome_message_for_team.format(member.name), mod)
try:
server = self._servers.get_server_by_discord_id(member.guild.id)
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
if user is not None:
self._user_joins.add_user_joined_server(UserJoinedServer(user, datetime.now()))
return
self._logger.debug(__name__, f'Add user: {member.id}')
self._users.add_user(User(member.id, 0, server))
self._db.save_changes()
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.server_id)
self._user_joins.add_user_joined_server(UserJoinedServer(user, datetime.now()))
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get user {member.id}', e)
async def _remove_user(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Remove user {member}')
settings: ServerSettings = self._config.get_configuration(f'DSERVER_{member.guild.id}')
await self._messenger.send_dm_message(settings.goodbye_message, member)
try:
server = self._servers.get_server_by_discord_id(member.guild.id)
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
if user is None:
self._logger.error(__name__, f'Cannot find user {member}')
return
join = self._user_joins.get_active_user_joined_server_by_user_id(user.user_id)
join.leaved_on = datetime.now()
self._user_joins.update_user_joined_server(join)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f'Cannot get user {member.id}', e)
def _update_voice_state(self, joined: bool, dc_user_id: int, dc_channel_id: int, srv_id: int):
user: User = None
try:
user = self._users.get_user_by_discord_id_and_server_id(dc_user_id, srv_id)
except Exception as e:
self._logger.error(__name__, f'Cannot get user {dc_user_id}', e)
return
if user is None:
self._logger.error(__name__, f'User not found {dc_user_id}')
return
try:
if joined:
join = UserJoinedVoiceChannel(user, dc_channel_id, datetime.now())
self._user_joins_vc.add_user_joined_voice_channel(join)
self._db.save_changes()
return
server_st: ServerSettings = self._config.get_configuration(f'DSERVER_{user.server.discord_server_id}')
join = self._user_joins_vc.get_active_user_joined_voice_channel_by_user_id(user.user_id)
join.leaved_on = datetime.now()
# ontime as hours
ontime = round((join.leaved_on - join.joined_on).total_seconds()/3600, 2)
old_xp = user.xp
user.xp += round(ontime * server_st.xp_per_ontime_hour)
self._user_joins_vc.update_user_joined_voice_channel(join)
self._users.update_user(user)
self._db.save_changes()
self._logger.debug(__name__, f'User {user} leaved_on {join.leaved_on}. Ontime: {ontime}h | xp: from {old_xp} to {user.xp}')
except Exception as e:
self._logger.error(__name__, f'Ontime validation failed', e)
def _handle_message_for_xp(self, message: discord.Message):
dc_user_id = message.author.id
try:
server = self._servers.get_server_by_discord_id(message.guild.id)
except Exception as e:
self._logger.error(__name__, f'Cannot get server {message.guild.id}', e)
return
user: User = None
try:
user = self._users.get_user_by_discord_id_and_server_id(dc_user_id, server.server_id)
except Exception as e:
self._logger.error(__name__, f'Cannot get user {dc_user_id}', e)
return
if user is None:
self._logger.error(__name__, f'User not found {dc_user_id}')
return
server_st: ServerSettings = self._config.get_configuration(f'DSERVER_{user.server.discord_server_id}')
old_xp = user.xp
user.xp += server_st._xp_per_message
self._users.update_user(user)
self._db.save_changes()
self._logger.debug(__name__, f'User {user} sent message. xp: from {old_xp} to {user.xp}')
async def on_member_join(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Module {type(self)} started')
self._check_for_known_user(member)
await self._add_if_not_exists_user(member)
async def on_member_remove(self, member: Union[discord.User, discord.Member]):
self._logger.debug(__name__, f'Module {type(self)} started')
await self._remove_user(member)
async def on_message(self, message: discord.Message):
self._logger.debug(__name__, f'Module {type(self)} started')
if message is None or message.guild is None:
return
self._apppend_received_message_count(message.guild.id)
if not message.author.bot:
self._handle_message_for_xp(message)
async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState):
self._logger.debug(__name__, f'Module {type(self)} started')
self._logger.trace(__name__, f'Detected on_voice_state_update {member.id} from {before} to {after}')
u: discord.User = member
server_st: ServerSettings = self._config.get_configuration(f'DSERVER_{member.guild.id}')
server = self._servers.get_server_by_discord_id(member.guild.id)
try:
# join
if before.channel is None and after.channel is not None and after.channel.id not in server_st.afk_channel_ids:
self._logger.trace(__name__, f'User {u.id} joined {after.channel}')
self._update_voice_state(True, member.id, after.channel.id, server.server_id)
# leave
elif before.channel is not None and after.channel is None and before.channel.id not in server_st.afk_channel_ids:
self._logger.trace(__name__, f'User {u.id} left {before.channel}')
self._update_voice_state(False, member.id, before.channel.id, server.server_id)
# channel to channel
elif before.channel is not None and after.channel is not None:
# joined
if before.channel.id in server_st.afk_channel_ids and after.channel.id not in server_st.afk_channel_ids:
self._logger.trace(__name__, f'User {u.id} joined {after.channel}')
self._update_voice_state(True, member.id, after.channel.id, server.server_id)
# left
elif after.channel.id in server_st.afk_channel_ids and before.channel.id not in server_st.afk_channel_ids:
self._logger.trace(__name__, f'User {u.id} left {before.channel}')
self._update_voice_state(False, member.id, before.channel.id, server.server_id)
else:
self._logger.trace(__name__, f'User {u.id} switched to {after.channel}')
except Exception as e:
self._logger.error(__name__, f'Cannot handle voice state for user {u.id}', e)

View File

@ -15,11 +15,11 @@ __title__ = 'modules.boot_log'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -1 +1,25 @@
# -*- coding: utf-8 -*-
"""
gismo sh-edraft Gismo
~~~~~~~~~~~~~~~~~~~
sh-edraft Dicord bot Gismo
:copyright: (c) 2021 - 2022 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = 'modules.database'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.3.0'
from collections import namedtuple
# imports:
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -1,6 +1,5 @@
import asyncio
from ctypes import Union
from datetime import datetime
import time
import discord
from cpl_core.configuration import ConfigurationABC
@ -8,11 +7,19 @@ from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from gismo_core.abc.bot_service_abc import BotServiceABC
from gismo_core.abc.message_service_abc import MessageServiceABC
from gismo_core.configuration.server_settings import ServerSettings
from gismo_data.abc.client_repository_abc import ClientRepositoryABC
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from gismo_data.abc.user_joined_server_repository_abc import \
UserJoinedServerRepositoryABC
from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
from gismo_data.abc.user_repository_abc import UserRepositoryABC
from gismo_data.model.client import Client
from gismo_data.model.known_user import KnownUser
from gismo_data.model.server import Server
from gismo_data.model.user import User
from gismo_data.model.user_joined_server import UserJoinedServer
from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from gismo_data.service.user_repository_service import ServerRepositoryABC
from modules_core.abc.events.on_ready_abc import OnReadyABC
from modules_core.abc.module_abc import ModuleABC
@ -27,7 +34,11 @@ class Database(ModuleABC, OnReadyABC):
bot: BotServiceABC,
db_context: DatabaseContextABC,
server_repo: ServerRepositoryABC,
user_repo: UserRepositoryABC
user_repo: UserRepositoryABC,
client_repo: ClientRepositoryABC,
known_users: KnownUserRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
user_joins_vc: UserJoinedVoiceChannelRepositoryABC
):
self._config = config
@ -36,7 +47,11 @@ class Database(ModuleABC, OnReadyABC):
self._db_context = db_context
self._servers = server_repo
self._users = user_repo
self._clients = client_repo
self._known_users = known_users
self._user_joins = user_joins
self._user_joins_vc = user_joins_vc
ModuleABC.__init__(self)
self._priorities[OnReadyABC] = 0
self._logger.trace(__name__, f'Module {type(self)} loaded')
@ -60,18 +75,49 @@ class Database(ModuleABC, OnReadyABC):
self._logger.error(__name__, 'Database init time calculation failed', e)
return
def _check_known_users(self):
self._logger.debug(__name__, f'Start checking KnownUsers table, {len(self._bot.users)}')
for u in self._bot.users:
u: discord.User = u
try:
if u.bot:
self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot')
continue
user = self._known_users.find_user_by_discord_id(u.id)
if user is not None:
continue
self._logger.warn(__name__, f'Unknown user: {u.id}')
self._logger.debug(__name__, f'Add user: {u.id}')
self._known_users.add_user(KnownUser(u.id))
self._db_context.save_changes()
user = self._known_users.find_user_by_discord_id(u.id)
if user is None:
self._logger.fatal(__name__, f'Cannot add user: {u.id}')
self._logger.debug(__name__, f'Added user: {u.id}')
except Exception as e:
self._logger.error(__name__, f'Cannot get user', e)
def _check_servers(self):
self._logger.debug(__name__, f'Start checking Servers table')
for g in self._bot.guilds:
g: discord.Guild = g
try:
server = self._servers.find_server_by_discord_id(g.id)
if server is not None:
return
continue
self._logger.warn(__name__, f'Server not found in database: {g.id}')
self._logger.debug(__name__, f'Add server: {g.id}')
self._servers.add_server(Server(g.id))
self._db_context.save_changes()
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f'Cannot add server: {g.id}')
self._logger.debug(__name__, f'Added server: {g.id}')
except Exception as e:
@ -80,8 +126,39 @@ class Database(ModuleABC, OnReadyABC):
results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f'Table Servers is empty!')
def _check_clients(self):
self._logger.debug(__name__, f'Start checking Clients table')
for g in self._bot.guilds:
g: discord.Guild = g
try:
server: Server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f'Server not found in database: {g.id}')
client = self._clients.find_client_by_server_id(server.server_id)
if client is not None:
continue
self._logger.warn(__name__, f'Client for server {g.id} not found in database: {self._bot.user.id}')
self._logger.debug(__name__, f'Add client: {self._bot.user.id}')
self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server))
self._db_context.save_changes()
client = self._clients.find_client_by_server_id(server.server_id)
if client is None:
self._logger.fatal(__name__, f'Cannot add client {self._bot.user.id} for server {g.id}')
self._logger.debug(__name__, f'Added client: {g.id}')
except Exception as e:
self._logger.error(__name__, f'Cannot get client', e)
results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f'Table Servers is empty!')
def _check_users(self):
self._logger.debug(__name__, f'Start checking Users table')
for g in self._bot.guilds:
g: discord.Guild = g
@ -89,13 +166,16 @@ class Database(ModuleABC, OnReadyABC):
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f'Server not found in database: {g.id}')
break
for u in g.members:
u: discord.Member = u
user = self._users.find_user_by_discord_id(u.id)
u: Union[discord.Member, discord.User] = u
if u.bot:
self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot')
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id)
if user is not None:
break
continue
self._logger.warn(__name__, f'User not found in database: {u.id}')
self._logger.debug(__name__, f'Add user: {u.id}')
@ -110,11 +190,129 @@ class Database(ModuleABC, OnReadyABC):
if results is None or len(results) == 0:
self._logger.error(__name__, f'Table Users is empty!')
def _check_user_joins(self):
self._logger.debug(__name__, f'Start checking UserJoinedServers table')
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f'Server not found in database: {guild.id}')
try:
for u in guild.members:
u: discord.User = u
if u.bot:
self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot')
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id)
if user is None:
self._logger.fatal(__name__, f'User not found in database: {u.id}')
join = self._user_joins.find_active_user_joined_server_by_user_id(user.user_id)
if join is not None:
continue
m: discord.Member = u
self._logger.warn(__name__, f'Active UserJoinedServer not found in database: {guild.id}:{u.id}@{m.joined_at}')
self._logger.debug(__name__, f'Add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}')
self._user_joins.add_user_joined_server(UserJoinedServer(user, m.joined_at, None))
self._db_context.save_changes()
self._logger.debug(__name__, f'Added UserJoinedServer: {u.id}')
except Exception as e:
self._logger.error(__name__, f'Cannot get UserJoinedServer', e)
results = self._users.get_users()
if results is None or len(results) == 0:
self._logger.error(__name__, f'Table Users is empty!')
joins = self._user_joins.get_user_joined_servers()
for join in joins:
join: UserJoinedServer = join
if join.user.server.discord_server_id != guild.id:
continue
if join.leaved_on is not None:
continue
dc_user = guild.get_member(join.user.discord_id)
if dc_user is None:
self._logger.warn(__name__, f'User {join.user.discord_id} already left the server.')
join.leaved_on = datetime.now()
self._user_joins.update_user_joined_server(join)
self._db_context.save_changes()
def _check_user_joins_vc(self):
self._logger.debug(__name__, f'Start checking UserJoinedVoiceChannel table')
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f'Server not found in database: {guild.id}')
try:
for u in guild.members:
u: discord.User = u
if u.bot:
self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot')
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id)
if user is None:
self._logger.fatal(__name__, f'User not found in database: {u.id}')
join = self._user_joins_vc.find_active_user_joined_voice_channel_by_user_id(user.user_id)
if join is None:
continue
m: discord.Member = u
self._logger.warn(__name__, f'Active UserJoinedVoiceChannel found in database: {guild.id}:{u.id}@{m.joined_at}')
join.leaved_on = datetime.now()
server_st: ServerSettings = self._config.get_configuration(f'DSERVER_{guild.id}')
if ((join.leaved_on - join.joined_on).total_seconds()/60/60) > server_st.max_voice_state_hours:
join.leaved_on = join.joined_on + datetime.timedelta(hours=server_st.max_voice_state_hours)
self._user_joins_vc.update_user_joined_voice_channel(join)
# todo: maybe add XP
self._db_context.save_changes()
for u in guild.members:
if u.bot:
self._logger.trace(__name__, f'User {u.id} is ignored, because its a bot')
continue
m: discord.Member = u
if m.voice is None:
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.server_id)
if user is None:
self._logger.fatal(__name__, f'User not found in database: {u.id}')
join = UserJoinedVoiceChannel(user, m.voice.channel.id, datetime.now())
self._user_joins_vc.add_user_joined_voice_channel(join)
self._db_context.save_changes()
self._logger.warn(__name__, f'VS {m.voice}')
except Exception as e:
self._logger.error(__name__, f'Cannot get UserJoinedVoiceChannel', e)
async def on_ready(self):
self._logger.debug(__name__, f'Module {type(self)} started')
self._check_known_users()
self._check_servers()
self._check_clients()
self._check_users()
self._check_user_joins()
self._check_user_joins_vc()
self._validate_init_time()
self._logger.trace(__name__, f'Module {type(self)} stopped')
self._logger.trace(__name__, f'Module {type(self)} stopped')

View File

@ -15,11 +15,11 @@ __title__ = 'modules_core'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -15,11 +15,11 @@ __title__ = 'modules_core.abc'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')

View File

@ -15,11 +15,11 @@ __title__ = 'modules_core.service'
__author__ = 'Sven Heidemann'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2021 - 2022 sh-edraft.de'
__version__ = '0.2.0'
__version__ = '0.3.0'
from collections import namedtuple
# imports
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major='0', minor='2', micro='0')
version_info = VersionInfo(major='0', minor='3', micro='0')