Skip to content

Commit

Permalink
feat: add periodic sending of lists to administrators
Browse files Browse the repository at this point in the history
  • Loading branch information
thisisfabrics committed Sep 15, 2024
1 parent 189dd0d commit 9ce2c82
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 11 deletions.
1 change: 1 addition & 0 deletions alembic/versions/_2023_12_15_18_47_init_alembic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Create Date: 2023-12-15 18:47:16.975938
"""

from typing import Sequence, Union

from alembic import op
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Create Date: 2024-01-04 21:20:05.067718
"""

from typing import Sequence, Union

from alembic import op
Expand Down
14 changes: 14 additions & 0 deletions settings.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ $defs:
- type: 'null'
default: null
title: Redis Url
users:
default: []
items:
type: integer
title: Users
type: array
notification_time:
anyOf:
- format: time
type: string
- type: 'null'
default: null
description: According to UTC
title: Notification Time
required:
- bot_token
- api_url
Expand Down
21 changes: 13 additions & 8 deletions src/api/users/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@

# docx
@router.get("/users/export", response_class=Response)
async def get_list_of_all_users(verified: VerifiedDep):
if verified.user_id is None:
raise ForbiddenException()
issuer = await user_repository.get_user(verified.user_id)
if issuer.status != UserStatus.LORD:
raise ForbiddenException()
async def get_list_of_all_users(verified: VerifiedDep, as_bot: bool = False):
if as_bot:
if verified.source != VerificationSource.BOT:
raise ForbiddenException()
else:
if verified.user_id is None:
raise ForbiddenException()
issuer = await user_repository.get_user(verified.user_id)
if issuer.status != UserStatus.LORD:
raise ForbiddenException()

users = await user_repository.get_all_users()
users.sort(key=lambda x: x.name or "")
Expand Down Expand Up @@ -61,14 +65,15 @@ async def get_list_of_all_users(verified: VerifiedDep):

bytes_stream = io.BytesIO()
document.save(bytes_stream)
val = bytes_stream.getvalue()
bytes_ = bytes_stream.getvalue()

bytes_stream.close()
date = datetime.datetime.now().strftime("%d.%m.%Y")
headers = {
"Content-Disposition": f"attachment; filename={date}.docx",
}
return Response(
content=val,
content=bytes_,
headers=headers,
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)
Expand Down
42 changes: 40 additions & 2 deletions src/bot/__main__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import asyncio
import datetime

import pytz
from aiogram import Bot, F
from aiogram import types
from aiogram.filters import ExceptionTypeFilter
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.fsm.storage.redis import RedisStorage, DefaultKeyBuilder
from aiogram.types import ErrorEvent
from aiogram.types import ErrorEvent, BufferedInputFile
from aiogram_dialog import setup_dialogs
from aiogram_dialog.api.exceptions import UnknownIntent

import src.bot.logging_ # noqa: F401
from src.bot.api import api_client
from src.bot.constants import (
bot_name,
bot_description,
bot_short_description,
bot_commands,
)
from src.bot.dispatcher import CustomDispatcher
from src.bot.logging_ import logger
from src.bot.middlewares import LogAllEventsMiddleware
from src.config import bot_settings
from src.config import bot_settings, settings

bot = Bot(token=bot_settings.bot_token.get_secret_value())
if bot_settings.redis_url:
Expand Down Expand Up @@ -53,6 +57,39 @@ async def unknown_intent_handler(event: ErrorEvent, callback_query: types.Callba
setup_dialogs(dp)


async def receptionist_notifications_loop():
if not settings.bot_settings.users or not settings.bot_settings.notification_time:
return
while True:
current_time = datetime.datetime.now(datetime.UTC)
planned_time = datetime.datetime(
current_time.year,
current_time.month,
current_time.day,
settings.bot_settings.notification_time.hour,
settings.bot_settings.notification_time.minute,
tzinfo=pytz.UTC,
)
if planned_time < current_time:
planned_time += datetime.timedelta(days=1)
await asyncio.sleep((planned_time - current_time).seconds)
for telegram_id in settings.bot_settings.users:
while True:
# noinspection PyBroadException
try:
response = await api_client.export_users_as_bot()
if response:
bytes_, filename = response
document = BufferedInputFile(bytes_, filename)
await bot.send_document(telegram_id, document, caption="Here is the list of users.")
else:
raise RuntimeError("Response was None")
break
except: # noqa: E722
logger.warning("Something went wrong. Please check.")
pass


async def main():
# Set bot name, description and commands
existing_bot = {
Expand All @@ -72,6 +109,7 @@ async def main():
await bot.set_my_commands(bot_commands)
# Drop pending updates
await bot.delete_webhook(drop_pending_updates=True)
await receptionist_notifications_loop()
# Start long-polling
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())

Expand Down
8 changes: 8 additions & 0 deletions src/bot/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,13 @@ async def export_users(self, telegram_id: int) -> tuple[bytes, str]:
filename = response.headers["Content-Disposition"].split("filename=")[1]
return bytes_, filename

async def export_users_as_bot(self) -> tuple[bytes, str]:
async with self._create_client() as client:
response = await client.get("/users/export", params={"as_bot": True})
if response.status_code == 200:
bytes_ = response.read()
filename = response.headers["Content-Disposition"].split("filename=")[1]
return bytes_, filename


api_client: InNoHassleMusicRoomAPI = InNoHassleMusicRoomAPI(bot_settings.api_url)
2 changes: 1 addition & 1 deletion src/bot/routers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async def enable_admin_mode(message: types.Message, bot: Bot, status: str):
await bot.set_my_commands(bot_commands, scope=BotCommandScopeChat(chat_id=message.from_user.id))


@router.message(Command("export_users"), StatusFilter(UserStatus.LORD))
@router.message(Command("export_users"))
async def export_users(message: types.Message):
response = await api_client.export_users(message.from_user.id)
if response:
Expand Down
3 changes: 3 additions & 0 deletions src/config_schema.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
from enum import StrEnum
from pathlib import Path

Expand All @@ -16,6 +17,8 @@ class BotSettings(BaseModel):
bot_token: SecretStr = Field(..., description="Bot token from @BotFather")
api_url: str
redis_url: SecretStr | None = None
users: list[int] = []
notification_time: datetime.time | None = Field(None, description="According to UTC")


class Accounts(BaseModel):
Expand Down

0 comments on commit 9ce2c82

Please sign in to comment.