Moved bot to kdb-bot #70

This commit is contained in:
2022-10-15 23:17:45 +02:00
parent 029b46d7de
commit ead3f69a69
216 changed files with 0 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,46 @@
{
"ProjectSettings": {
"Name": "database",
"Version": {
"Major": "1",
"Minor": "0",
"Micro": "0.dev1"
},
"Author": "Sven Heidemann",
"AuthorEmail": "sven.heidemann@sh-edraft.de",
"Description": "Keksdose bot - db module",
"LongDescription": "Discord bot for the Keksdose discord Server - database module",
"URL": "https://www.sh-edraft.de",
"CopyrightDate": "2022",
"CopyrightName": "sh-edraft.de",
"LicenseName": "MIT",
"LicenseDescription": "MIT, see LICENSE for more details.",
"Dependencies": [
"cpl-core>=2022.10.0.post2"
],
"DevDependencies": [
"cpl-cli==2022.10.0"
],
"PythonVersion": ">=3.10.4",
"PythonPath": {
"linux": ""
},
"Classifiers": []
},
"BuildSettings": {
"ProjectType": "library",
"SourcePath": "",
"OutputPath": "../../dist",
"Main": "database.main",
"EntryPoint": "database",
"IncludePackageData": false,
"Included": [],
"Excluded": [
"*/__pycache__",
"*/logs",
"*/tests"
],
"PackageData": {},
"ProjectReferences": []
}
}

View File

@@ -0,0 +1,27 @@
from datetime import datetime
from cpl_core.application.application_extension_abc import ApplicationExtensionABC
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.logging import LoggerABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.service.migration_service import MigrationService
class DatabaseExtension(ApplicationExtensionABC):
def __init__(self):
pass
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings)
if not feature_flags.get_flag(FeatureFlagsEnum.data_module):
return
logger: LoggerABC = services.get_service(DatabaseLogger)
logger.debug(__name__, 'Database extension started')
config.add_configuration('Database_StartTime', str(datetime.now()))
migrations: MigrationService = services.get_service(MigrationService)
migrations.migrate()

View File

@@ -0,0 +1,23 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
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.database.database_on_ready_event import DatabaseOnReadyEvent
class DatabaseModule(ModuleABC):
def __init__(self, dc: DiscordCollectionABC):
ModuleABC.__init__(self, dc, FeatureFlagsEnum.database_module)
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
pass
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
# commands
# events
self._dc.add_event(DiscordEventTypesEnum.on_ready.value, DatabaseOnReadyEvent)

View File

@@ -0,0 +1,314 @@
from ctypes import Union
from datetime import datetime, timedelta
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.logging.database_logger import DatabaseLogger
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
from bot_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.client import Client
from bot_data.model.known_user import KnownUser
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 bot_data.service.user_repository_service import ServerRepositoryABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class DatabaseOnReadyEvent(OnReadyABC):
def __init__(
self,
config: ConfigurationABC,
logger: DatabaseLogger,
bot: DiscordBotServiceABC,
db_context: DatabaseContextABC,
server_repo: ServerRepositoryABC,
user_repo: UserRepositoryABC,
client_repo: ClientRepositoryABC,
known_users: KnownUserRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
dtp: DateTimeOffsetPipe
):
self._config = config
self._logger = logger
self._bot = bot
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
self._dtp = dtp
OnReadyABC.__init__(self)
self._logger.info(__name__, f'Module {type(self)} loaded')
def _validate_init_time(self):
try:
start_time = self._config.get_configuration('Database_StartTime')
init_time = round((datetime.now() - datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S.%f')).total_seconds(), 2)
self._config.add_configuration('Database_InitTime', str(init_time))
self._logger.debug(__name__, f'Database Init time: {init_time}s')
# print warning if initialisation took too long
if init_time >= 30:
self._logger.warn(
__name__, 'It takes too long to prepare the database!')
# print error if initialisation took way too long
elif init_time >= 90:
self._logger.error(
__name__, 'It takes far too long to prepare the database!!!')
except Exception as e: #
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:
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:
self._logger.error(__name__, f'Cannot get server', 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_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
try:
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}')
for u in g.members:
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:
continue
self._logger.warn(__name__, f'User not found in database: {u.id}')
self._logger.debug(__name__, f'Add user: {u.id}')
self._users.add_user(User(u.id, 0, server))
self._db_context.save_changes()
self._logger.debug(__name__, f'Added User: {u.id}')
except Exception as e:
self._logger.error(__name__, f'Cannot get User', e)
results = self._users.get_users()
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, self._dtp.transform(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 member in guild.members:
if member.bot:
self._logger.trace(__name__, f'User {member.id} is ignored, because its a bot')
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
if user is None:
self._logger.fatal(__name__, f'User not found in database: {member.id}')
joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.user_id)
if joins is None or len(joins) == 0:
continue
for join in joins:
self._logger.warn(__name__, f'Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}')
join.leaved_on = datetime.now()
settings: BaseServerSettings = self._config.get_configuration(f'BaseServerSettings_{guild.id}')
if ((join.leaved_on - join.joined_on).total_seconds() / 60 / 60) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joins_vc.update_user_joined_voice_channel(join)
# todo: maybe add XP
self._db_context.save_changes()
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f'User {member.id} is ignored, because its a bot')
continue
if member.voice is None:
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id)
if user is None:
self._logger.fatal(__name__, f'User not found in database: {member.id}')
join = UserJoinedVoiceChannel(user, member.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 {member.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')