13 Commits

Author SHA1 Message Date
db61a764eb Merge pull request 'staging' (#447) from staging into master
All checks were successful
Deploy prod on push / on-push-deploy_sh-edraft (push) Successful in 3m45s
Reviewed-on: #447
2023-12-02 19:34:22 +01:00
919eef79f6 Merge branch 'master' into staging
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 3m58s
2023-12-02 19:33:58 +01:00
a2dd447dbd Always check scheduled_events after scheduled_event update #410
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 4m26s
Deploy dev on push / on-push-deploy_sh-edraft (push) Successful in 3m33s
2023-12-02 15:32:16 +01:00
8a76b46165 Improved event time loading #410
All checks were successful
Deploy dev on push / on-push-deploy_sh-edraft (push) Successful in 5m12s
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 3m40s
2023-12-02 15:24:13 +01:00
af3084ad36 Fixed scheduled event end update #410
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 4m41s
Deploy dev on push / on-push-deploy_sh-edraft (push) Successful in 3m39s
2023-12-01 21:04:29 +01:00
285b8bdbe4 Fixed scheduled events #410
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 4m44s
2023-12-01 20:40:44 +01:00
e2da4f09ee Fixed command
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 4m50s
2023-12-01 20:02:42 +01:00
4ed99da689 Merge pull request 'dev' (#445) from dev into staging
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 3m32s
Reviewed-on: #445
2023-12-01 19:55:54 +01:00
bc94d31a8d Added logs cleanup
All checks were successful
Deploy dev on push / on-push-deploy_sh-edraft (push) Successful in 4m30s
2023-12-01 19:50:18 +01:00
0d3db75190 Improved scheduled_event handling #410
Some checks reported warnings
Deploy dev on push / on-push-deploy_sh-edraft (push) Has been cancelled
2023-12-01 19:06:11 +01:00
090f217f93 Fixed scheduled_events #410
All checks were successful
Deploy staging on push / on-push-deploy_sh-edraft (push) Successful in 3m37s
Deploy dev on push / on-push-deploy_sh-edraft (push) Successful in 3m39s
2023-11-30 17:57:43 +01:00
b98828fce3 Fixed mass move #444 2023-11-30 17:54:31 +01:00
5de6710261 Merge pull request 'staging' (#435) from staging into master
All checks were successful
Deploy prod on push / on-push-deploy_sh-edraft (push) Successful in 3m34s
Reviewed-on: #435
2023-11-07 20:37:13 +01:00
10 changed files with 150 additions and 107 deletions

View File

@@ -0,0 +1,22 @@
import os
import shutil
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_query.extension import List
class CleanLogsExtension(ApplicationExtensionABC):
def __init__(self):
pass
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
(
List(str, os.listdir("logs/"))
.where(lambda x: os.path.isdir(f"logs/{x}"))
.order_by()
.where(lambda x: (datetime.now() - datetime.strptime(x, "%Y-%m-%d")).days >= 7)
.for_each(lambda x: shutil.rmtree(f"logs/{x}"))
)

View File

@@ -6,6 +6,7 @@ from cpl_core.application import ApplicationBuilder
from cpl_core.console import Console
from bot.application import Application
from bot.extension.clean_logs_extension import CleanLogsExtension
from bot.extension.init_bot_extension import InitBotExtension
from bot.startup import Startup
from bot.startup_discord_extension import StartupDiscordExtension
@@ -31,6 +32,7 @@ class Program:
.use_extension(StartupDiscordExtension)
.use_extension(StartupModuleExtension)
.use_extension(StartupMigrationExtension)
.use_extension(CleanLogsExtension)
.use_extension(DatabaseExtension)
.use_extension(ConfigExtension)
.use_extension(InitBotExtension)

View File

@@ -7,6 +7,7 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.module_abc import ModuleABC
from bot_core.abc.task_abc import TaskABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from modules.base.command.scheduled_events_group import ScheduledEventsCommand
from modules.base.tasks.birthday_watcher import BirthdayWatcher
from modules.base.command.afk_command import AFKCommand
from modules.base.command.game_server_group import GameServerGroup
@@ -83,6 +84,7 @@ class BaseModule(ModuleABC):
services.add_transient(RegisterGroup)
services.add_transient(UnregisterGroup)
services.add_transient(GameServerGroup)
services.add_transient(ScheduledEventsCommand)
# events
services.add_transient(DiscordEventTypesEnum.on_command.value, BaseOnCommandEvent)
services.add_transient(DiscordEventTypesEnum.on_command_error.value, BaseOnCommandErrorEvent)

View File

@@ -38,7 +38,7 @@ class MassMoveCommand(DiscordCommandABC):
self,
ctx: Context,
channel_to: discord.VoiceChannel,
channel_from: Transform[str, VoiceChannelTransformer] = None,
channel_from: Transform[discord.VoiceChannel, VoiceChannelTransformer] = None,
):
self._logger.debug(__name__, f"Received command mass-move {ctx}")

View File

@@ -0,0 +1,37 @@
from cpl_discord.command import DiscordCommandABC
from discord.ext import commands
from discord.ext.commands import Context
from bot_core.helper.command_checks import CommandChecks
from bot_core.logging.command_logger import CommandLogger
from modules.base.service.event_service import EventService
class ScheduledEventsCommand(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
events: EventService,
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._events = events
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
@commands.hybrid_group(name="scheduled-events")
@commands.guild_only()
async def scheduled_events(self, ctx: Context):
pass
@scheduled_events.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator()
async def reload(self, ctx: Context):
self._logger.debug(__name__, "Running scheduled-events reload")
try:
await self._events.check_and_create_scheduled_events(ctx.guild)
except Exception as e:
self._logger.error(__name__, f"Reloading scheduled events failed", e)

View File

@@ -42,4 +42,5 @@ class BaseOnScheduledEventUpdateEvent(OnScheduledEventUpdateABC):
return
self._events.remove_event(event)
await self._events.check_and_create_scheduled_events(before.guild)
self._logger.debug(__name__, f"Module {type(self)} stopped")

View File

@@ -25,7 +25,7 @@ class VoiceChannelTransformer(Transformer):
return [
app_commands.Choice(
name=f"{vc.name}" if vc.category is None else f"{vc.name}: {vc.category.name}",
value=vc.name,
value=str(vc.id),
)
for vc in get_client_utils().get_auto_complete_list(voice_channels, current, lambda x: x.name)
]

View File

@@ -1,13 +1,22 @@
import calendar
from datetime import datetime, timedelta
from typing import Optional
from zoneinfo import ZoneInfo
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_discord.container import Guild
from cpl_query.extension import List
from discord import PrivacyLevel
from discord.scheduled_event import ScheduledEvent as DiscordEvent
from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.scheduled_event import ScheduledEvent
from bot_data.model.scheduled_event_interval_enum import ScheduledEventIntervalEnum
from bot_data.model.server_config import ServerConfig
from modules.base.model.active_event import ActiveEvent
@@ -20,12 +29,14 @@ class EventService:
servers: ServerRepositoryABC,
users: UserRepositoryABC,
db: DatabaseContextABC,
events: ScheduledEventRepositoryABC,
):
self._config = config
self._logger = logger
self._servers = servers
self._users = users
self._db = db
self._events = events
self._active_events = List(ActiveEvent)
@@ -61,3 +72,72 @@ class EventService:
self._users.update_user(user)
self._db.save_changes()
active_event.participants.append(user)
def _append_interval(self, interval: ScheduledEventIntervalEnum, ts: datetime) -> datetime:
now = datetime.now().replace(tzinfo=ZoneInfo("Europe/Berlin"))
if ts >= now:
return ts
if interval == ScheduledEventIntervalEnum.daily:
ts = ts + timedelta(days=1)
elif interval == ScheduledEventIntervalEnum.weekly:
ts = ts + timedelta(weeks=1)
elif interval == ScheduledEventIntervalEnum.monthly:
days_in_month = calendar.monthrange(ts.year, ts.month + 1)[1]
ts = ts + timedelta(days=days_in_month)
elif interval == ScheduledEventIntervalEnum.yearly:
ts = ts + timedelta(days=365)
while ts < now:
ts = self._append_interval(interval, ts)
return ts
async def check_and_create_scheduled_events(self, guild: Guild):
server = self._servers.get_server_by_discord_id(guild.id)
scheduled_events_from_db = self._events.get_scheduled_events_by_server_id(server.id)
for scheduled_event in scheduled_events_from_db:
scheduled_event: ScheduledEvent = scheduled_event
from_guild = List(DiscordEvent, guild.scheduled_events).where(
lambda x: x.name == scheduled_event.name
and x.description == scheduled_event.description
and x.entity_type == scheduled_event.entity_type
)
if from_guild.count() != 0:
continue
kwargs = {"name": scheduled_event.name, "description": scheduled_event.description}
if scheduled_event.channel_id is not None:
kwargs["channel"] = guild.get_channel(scheduled_event.channel_id)
if scheduled_event.start_time is not None:
start_time = self._append_interval(
scheduled_event.interval, scheduled_event.start_time.replace(tzinfo=ZoneInfo("Europe/Berlin"))
)
kwargs["start_time"] = start_time
scheduled_event.start_time = scheduled_event.start_time.replace(tzinfo=None)
if scheduled_event.end_time is not None:
end_time = self._append_interval(
scheduled_event.interval, scheduled_event.end_time.replace(tzinfo=ZoneInfo("Europe/Berlin"))
)
kwargs["end_time"] = end_time
scheduled_event.end_time = scheduled_event.end_time.replace(tzinfo=None)
kwargs["entity_type"] = scheduled_event.entity_type
if scheduled_event.location is not None:
kwargs["location"] = scheduled_event.location
kwargs["privacy_level"] = PrivacyLevel.guild_only
try:
self._logger.debug(__name__, f"Try to create scheduled event for guild {guild.name}")
await guild.create_scheduled_event(**kwargs)
self._events.update_scheduled_event(scheduled_event)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f"Watching scheduled events failed", e)

View File

@@ -1,23 +1,14 @@
import calendar
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from cpl_translation import TranslatePipe
from discord import Guild, PrivacyLevel
from discord.ext import tasks
from discord.scheduled_event import ScheduledEvent as DiscordEvent
from bot_core.abc.task_abc import TaskABC
from bot_core.logging.task_logger import TaskLogger
from bot_core.service.message_service import MessageService
from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.model.scheduled_event import ScheduledEvent
from bot_data.model.scheduled_event_interval_enum import ScheduledEventIntervalEnum
from modules.base.service.event_service import EventService
class ScheduledEventsWatcher(TaskABC):
@@ -28,7 +19,7 @@ class ScheduledEventsWatcher(TaskABC):
bot: DiscordBotServiceABC,
db: DatabaseContextABC,
servers: ServerRepositoryABC,
events: ScheduledEventRepositoryABC,
events: EventService,
message_service: MessageService,
t: TranslatePipe,
):
@@ -46,78 +37,12 @@ class ScheduledEventsWatcher(TaskABC):
if not self._is_maintenance():
self.watch.start()
def _append_interval(self, interval: ScheduledEventIntervalEnum, ts: datetime) -> datetime:
now = datetime.now()
if ts >= now:
return ts
if interval == ScheduledEventIntervalEnum.daily:
ts = ts + timedelta(days=1)
elif interval == ScheduledEventIntervalEnum.weekly:
ts = ts + timedelta(weeks=1)
elif interval == ScheduledEventIntervalEnum.monthly:
days_in_month = calendar.monthrange(ts.year, ts.month + 1)[1]
ts = ts + timedelta(days=days_in_month)
elif interval == ScheduledEventIntervalEnum.yearly:
ts = ts + timedelta(days=365)
return ts
@tasks.loop(hours=24)
@tasks.loop(hours=12)
async def watch(self):
self._logger.info(__name__, "Watching scheduled events")
try:
for guild in self._bot.guilds:
guild: Guild = guild
server = self._servers.get_server_by_discord_id(guild.id)
scheduled_events_from_guild = self._events.get_scheduled_events_by_server_id(server.id)
for scheduled_event in scheduled_events_from_guild:
scheduled_event: ScheduledEvent = scheduled_event
from_guild = List(DiscordEvent, guild.scheduled_events).where(
lambda x: x.name == scheduled_event.name
and x.description == scheduled_event.description
and x.entity_type == scheduled_event.entity_type
)
if from_guild.count() != 0:
continue
kwargs = {"name": scheduled_event.name, "description": scheduled_event.description}
if scheduled_event.channel_id is not None:
kwargs["channel"] = guild.get_channel(scheduled_event.channel_id)
if scheduled_event.start_time is not None:
scheduled_event.start_time = self._append_interval(
scheduled_event.interval, scheduled_event.start_time
)
start_time = scheduled_event.start_time.replace(tzinfo=ZoneInfo("Europe/Berlin"))
kwargs["start_time"] = start_time
if scheduled_event.end_time is not None:
scheduled_event.end_time = self._append_interval(
scheduled_event.interval, scheduled_event.end_time
)
end_time = scheduled_event.end_time.replace(tzinfo=ZoneInfo("Europe/Berlin"))
kwargs["end_time"] = end_time
kwargs["entity_type"] = scheduled_event.entity_type
if scheduled_event.location is not None:
kwargs["location"] = scheduled_event.location
kwargs["privacy_level"] = PrivacyLevel.guild_only
try:
self._logger.debug(__name__, f"Try to create scheduled event for guild {guild.name}")
await guild.create_scheduled_event(**kwargs)
self._events.update_scheduled_event(scheduled_event)
self._db.save_changes()
except Exception as e:
self._logger.error(__name__, f"Watching scheduled events failed", e)
await self._events.check_and_create_scheduled_events(guild)
except Exception as e:
self._logger.error(__name__, f"Watching scheduled events failed", e)

View File

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