Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# This file is a template of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production

LOG_LEVEL=
LOG_FORMAT=
TOKEN=<bot-token>
PORT=80
CHAT_ID=<admin-chat-id>
ERRORS_CHAT_ID=<errors-chat-id>
ERRORS_THREAD_ID=<errors-thread-id>
TELEGRAM_SECRET=<random-secret-string>
BASE_URL=http://localhost:8000/
WEBHOOK_PATH=webhook
API_ACCESS_TOKEN=<api-access-token>

TOKEN=TOKEN
CHAT_ID=13173823
TELEGRAM_SECRET=mysecretpassword
BASE_URL=URL
WEBHOOK_PATH=/webhook
NGROK_AUTHTOKEN=
API_URL=<api-url>
FRONT_BASE_URL=<frontend-base-url>

FRONT_BASE_URL=https://fictadvisor.com
API_URL=https://dev.fictadvisor.com/api/v2
LOG_LEVEL=info
LOG_FORMAT=info
12 changes: 9 additions & 3 deletions app/api/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ async def async_exception_handler(request: Request, exc: Exception) -> JSONRespo
async def on_startup(*a: Any, **kw: Any) -> None: # pragma: no cover
if settings.DEVELOPMENT:
from ngrok import ngrok
port = int(sys.argv[sys.argv.index("--port") + 1]) if "--port" in sys.argv else 8000

port = (
int(sys.argv[sys.argv.index("--port") + 1])
if "--port" in sys.argv
else 8000
)
ngrok.set_auth_token(settings.NGROK_AUTHTOKEN.get_secret_value() if settings.NGROK_AUTHTOKEN else None) # type: ignore
tunnel = await ngrok.connect(port) # type: ignore[misc]
public_url = tunnel.url()
Expand All @@ -68,11 +73,12 @@ async def on_startup(*a: Any, **kw: Any) -> None: # pragma: no cover
async def on_shutdown(*a: Any, **kw: Any) -> None: # pragma: no cover
if settings.DEVELOPMENT:
from ngrok import ngrok

ngrok.disconnect()
await dispatcher.emit_shutdown(**workflow_data)

app.add_event_handler('startup', on_startup)
app.add_event_handler('shutdown', on_shutdown)
app.add_event_handler("startup", on_startup)
app.add_event_handler("shutdown", on_shutdown)

app.include_router(api)

Expand Down
2 changes: 1 addition & 1 deletion app/bot/filters/is_captain_or_deputy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async def __call__(self, update: Union[Message, CallbackQuery]) -> Union[bool, D
if user.group.role in (Role.CAPTAIN, Role.MODERATOR):
return {"user": user}
except ResponseException as e:
await send_answer(update, "Прив'яжіть телеграм до аккаунта FictAdvisor")
await send_answer(update, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
else:
await send_answer(update, "Ця команда лише для старости або заступників")
Expand Down
12 changes: 10 additions & 2 deletions app/bot/handlers/private/enable.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from typing import Optional

from aiogram.types import Message
Expand All @@ -14,11 +15,18 @@
UpdateTelegramGroup,
)
from app.services.user_api import UserAPI
from app.utils.telegram import send_answer


async def enable(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with TelegramGroupAPI() as telegram_group_api:
try:
telegram_groups: TelegramGroups = await telegram_group_api.get_telegram_groups(user.group.id)
Expand Down
24 changes: 20 additions & 4 deletions app/bot/handlers/private/fortnight.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import logging

from aiogram.types import CallbackQuery, Message

from app.bot.keyboards.types.select_week import SelectWeek
from app.bot.keyboards.week_keyboard import get_week_keyboard
from app.messages.events import WEEK_EVENT_LIST
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.user_api import UserAPI
from app.utils.date_service import DateService
from app.utils.events import check_odd
from app.utils.telegram import send_answer


async def fortnight(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_fortnight(user.group.id, user_id=user.id)

Expand All @@ -28,8 +38,14 @@ async def fortnight(message: Message) -> None:


async def select_week(callback: CallbackQuery, callback_data: SelectWeek) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(callback.from_user.id)
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(callback.from_user.id)
except ResponseException as e:
await send_answer(callback, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_fortnight(callback_data.group_id, user_id=user.id)
week = callback_data.week
Expand Down
13 changes: 11 additions & 2 deletions app/bot/handlers/private/left.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import logging
from datetime import datetime, timedelta
from typing import Optional

import pytz
from aiogram.types import Message

from app.messages.events import LEFT_EVENT
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.user_api import UserAPI
from app.utils.events import group_by_time
from app.utils.telegram import send_answer


async def left_command(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_day(user.group.id, user_id=user.id)

Expand Down
13 changes: 11 additions & 2 deletions app/bot/handlers/private/next.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import logging
from datetime import datetime
from typing import Iterable, Optional, Tuple

import pytz
from aiogram.types import Message

from app.messages.events import NEXT_EVENT
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.types.general_event import GeneralEvent
from app.services.user_api import UserAPI
from app.utils.events import group_by_time
from app.utils.telegram import send_answer


async def next_command(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_day(user.group.id, user_id=user.id)

Expand Down
13 changes: 11 additions & 2 deletions app/bot/handlers/private/now.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import logging
from datetime import datetime, timedelta
from typing import Iterable, Optional, Tuple

import pytz
from aiogram.types import Message

from app.messages.events import NOW_EVENT
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.types.general_event import GeneralEvent
from app.services.user_api import UserAPI
from app.utils.events import group_by_time
from app.utils.telegram import send_answer


async def now_command(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_day(user.group.id, user_id=user.id)

Expand Down
18 changes: 13 additions & 5 deletions app/bot/handlers/private/poll.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from aiogram.fsm.context import FSMContext
from aiogram.fsm.scene import ScenesManager
from aiogram.types import CallbackQuery, Message
Expand All @@ -7,16 +9,24 @@
)
from app.bot.keyboards.types.select_teacher import SelectTeacher
from app.bot.scenes.poll import PollScene
from app.services.exceptions.response_exception import ResponseException
from app.services.poll_api import PollAPI
from app.services.types.student import Student
from app.services.types.users_teachers import UsersTeachers
from app.services.user_api import UserAPI
from app.utils.telegram import send_answer


async def poll_command(message: Message, state: FSMContext) -> None:
async with UserAPI() as user_api:
user: Student = await user_api.get_user_by_telegram_id(message.from_user.id) #type: ignore[union-attr]
await state.update_data({"user": user})
try:
async with UserAPI() as user_api:
user: Student = await user_api.get_user_by_telegram_id(message.from_user.id) #type: ignore[union-attr]
await state.update_data({"user": user})
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with PollAPI() as poll_api:
users_teachers: UsersTeachers = await poll_api.get_users_teachers(user_id=user.id)

Expand All @@ -30,5 +40,3 @@ async def select_teacher(callback: CallbackQuery, callback_data: SelectTeacher,
await callback.message.delete()
await scenes.enter(PollScene, discipline_teacher_id=callback_data.discipline_teacher_id)
await callback.answer()


14 changes: 12 additions & 2 deletions app/bot/handlers/private/today.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import logging

from aiogram.types import Message

from app.messages.events import EVENT_LIST
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.user_api import UserAPI
from app.utils.date_service import DateService
from app.utils.telegram import send_answer


async def today(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_day(user.group.id, user_id=user.id, day=DateService.get_current_day())

Expand Down
14 changes: 12 additions & 2 deletions app/bot/handlers/private/tomorrow.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import logging

from aiogram.types import Message

from app.messages.events import EVENT_LIST
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.user_api import UserAPI
from app.utils.date_service import DateService
from app.utils.telegram import send_answer


async def tomorrow(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_day(
user.group.id, user_id=user.id, day=DateService.get_current_day() + 1
Expand Down
14 changes: 12 additions & 2 deletions app/bot/handlers/private/week.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import logging

from aiogram.types import Message

from app.messages.events import WEEK_EVENT_LIST
from app.services.exceptions.response_exception import ResponseException
from app.services.schedule_api import ScheduleAPI
from app.services.user_api import UserAPI
from app.utils.telegram import send_answer


async def week(message: Message) -> None:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
try:
async with UserAPI() as user_api:
user = await user_api.get_user_by_telegram_id(message.from_user.id) # type: ignore[union-attr]
except ResponseException as e:
await send_answer(message, "Прив'яжіть телеграм до аккаунта FICE Advisor")
logging.error(e)
return

async with ScheduleAPI() as schedule_api:
general_events = await schedule_api.get_general_group_events_by_week(user.group.id, user_id=user.id)

Expand Down
22 changes: 16 additions & 6 deletions app/bot/middlewares/throttling.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Any, Awaitable, Callable, Dict, MutableMapping, Optional

from aiogram import BaseMiddleware
from aiogram.exceptions import TelegramBadRequest
from aiogram.types import TelegramObject, User
from cachetools import TTLCache

Expand All @@ -9,19 +10,28 @@ class ThrottlingMiddleware(BaseMiddleware):
RATE_LIMIT = 0.7

def __init__(self, rate_limit: float = RATE_LIMIT) -> None:
self._cache: MutableMapping[int, None] = TTLCache(maxsize=10_000, ttl=rate_limit)
self._cache: MutableMapping[int, None] = TTLCache(
maxsize=10_000, ttl=rate_limit
)

async def __call__(
self,
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
event: TelegramObject,
data: Dict[str, Any],
self,
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
event: TelegramObject,
data: Dict[str, Any],
) -> Optional[Any]:
user: Optional[User] = data.get("event_from_user", None)

if user is not None:
if user.id in self._cache:
return None

self._cache[user.id] = None

return await handler(event, data)
try:
return await handler(event, data)
except TelegramBadRequest as e:
if "message is not modified" in str(e):
return None

raise
Loading