Skip to content

Commit

Permalink
Merge pull request #9
Browse files Browse the repository at this point in the history
dev
  • Loading branch information
ptrvsrg committed Jun 19, 2024
2 parents a8b1a5b + 2bb86f5 commit d4f4eb9
Show file tree
Hide file tree
Showing 73 changed files with 949 additions and 532 deletions.
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MAJOR_VERSION=0
MINOR_VERSION=0
MINOR_VERSION=1
PATCH_VERSION=0

LOCALE_DIR=locales
Expand All @@ -23,5 +23,8 @@ REDIS_USER=default
REDIS_PASSWORD=password
REDIS_DB=0

YANDEX_DISK_API_KEY=
YANDEX_DISK_BASE_DIR=hotdog_or_not

DEBUG=false
PORT=8080
34 changes: 17 additions & 17 deletions .github/workflows/build_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28 changes: 14 additions & 14 deletions .github/workflows/create_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ jobs:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: |
Release created automatically by Github Action
draft: false
prerelease: false
- name: Checkout code
uses: actions/checkout@v4
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: |
Release created automatically by Github Action
draft: false
prerelease: false
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ that Jian Yang developed? This app identifies whether something is hotdog or not
+ Detecting objects in the photo
+ Hotdog prediction
+ Telegram bot
+ Saving dataset to Yandex Disk

## Technologies

Expand All @@ -26,6 +27,7 @@ that Jian Yang developed? This app identifies whether something is hotdog or not
- [OpenCV](https://opencv.org/)
- [SQLAlchemy](https://www.sqlalchemy.org/)
- [i18next](https://pypi.org/project/i18next/)
- [yadisk](https://yadisk.readthedocs.io/ru/latest/)

## Requirements

Expand Down Expand Up @@ -63,15 +65,15 @@ pip install -r requirements.txt
> **_NOTE:_** Run in a separate terminal.
> **_NOTE:_** ngrok is a globally distributed reverse proxy. We will use it to test the webhook.
After launching we have to copy forwarding URL.
> After launching we have to copy forwarding URL.
```shell
ngrok http 8080
```

5. Set up environment variables

> **_NOTE:_** Initialize environment variable **WEBHOOK_URL** with the value \<public URL from ngrok\>/webhook
> **_NOTE:_** Initialize environment variable **WEBHOOK_URL** with the value \<public URL from ngrok\>/webhook
```shell
cp .env.exmaple .env
Expand Down
16 changes: 11 additions & 5 deletions app/bot/callback_data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
from app.bot.callback_data.cancel_callback_factory import CancelCallbackFactory
from app.bot.callback_data.main_menu_callback_factory import MainMenuCallbackFactory
from app.bot.callback_data.result_callback_factory import ResultCallbackFactory
from app.bot.callback_data.select_image_callback_factory import SelectImageCallbackFactory
from app.bot.callback_data.subscription_buy_callback_factory import SubscriptionBuyCallbackFactory
from app.bot.callback_data.sudscription_callback_factory import SubscriptionCallbackFactory
from app.bot.callback_data.result_callback_factory import ResultFeedbackCallbackFactory
from app.bot.callback_data.select_image_callback_factory import (
SelectImageCallbackFactory,
)
from app.bot.callback_data.subscription_buy_callback_factory import (
SubscriptionBuyCallbackFactory,
)
from app.bot.callback_data.sudscription_callback_factory import (
SubscriptionCallbackFactory,
)

__all__ = [
"MainMenuCallbackFactory",
"SubscriptionBuyCallbackFactory",
"SubscriptionCallbackFactory",
"CancelCallbackFactory",
"SelectImageCallbackFactory",
"ResultCallbackFactory",
"ResultFeedbackCallbackFactory",
]
3 changes: 2 additions & 1 deletion app/bot/callback_data/result_callback_factory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from aiogram.filters.callback_data import CallbackData


class ResultCallbackFactory(CallbackData, prefix="result"):
class ResultFeedbackCallbackFactory(CallbackData, prefix="result"):
action: str
message_id: int
1 change: 1 addition & 0 deletions app/bot/callback_data/select_image_callback_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@

class SelectImageCallbackFactory(CallbackData, prefix="select_image"):
index: int
message_id: int
4 changes: 3 additions & 1 deletion app/bot/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from app.bot.handlers.predict_images_handler import router as predict_router
from app.bot.handlers.profile_callback_handler import router as profile_router
from app.bot.handlers.start_command_handler import router as start_router
from app.bot.handlers.subscription_callbacks_handler import router as subscription_router
from app.bot.handlers.subscription_callbacks_handler import (
router as subscription_router,
)

__all__ = [
"start_router",
Expand Down
92 changes: 48 additions & 44 deletions app/bot/handlers/admin_callbacks_handler.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,89 @@
import logging

from aiogram import Router, F
from aiogram.fsm.context import FSMContext
from aiogram.types import Message, CallbackQuery
from i18next import trans
from i18next import trans as t

from app.bot.callback_data import MainMenuCallbackFactory
from app.bot.keyboards import create_cancel_menu
from app.bot.states import AdminStates
from app.bot.utils.callback_utils import get_username_from_callback
from app.bot.utils.message_utils import get_username_from_message
from app.service import user_service, UserAlreadyBannedException, UserNotBannedException

router = Router(name="admin")
logger = logging.getLogger("admin_callbacks")


@router.callback_query(MainMenuCallbackFactory.filter(F.action == "ban_user"))
async def ban_user(callback: CallbackQuery, state: FSMContext):
logger.info(f"{get_username_from_callback(callback)}: Start ban user")
await callback.message.answer(trans("message.enter_username"), reply_markup=create_cancel_menu())
await callback.message.answer(
t("message.enter_username"), reply_markup=create_cancel_menu()
)
await state.set_state(AdminStates.awaiting_banned_username)
logger.info(f"{get_username_from_callback(callback)}: Awaiting username of banned user")


@router.message(AdminStates.awaiting_banned_username)
async def process_ban(message: Message, state: FSMContext):
logger.info(
f"{get_username_from_message(message)}: Enter username of banned user {message.text}")
username = message.text
if username.startswith('@'):
try:
user_service.ban_user(username[1:])
await message.answer(trans("message.user_is_banned", params={"username": username}))
logger.info(f"{get_username_from_message(message)}: User {username} is banned")
except UserAlreadyBannedException as e:
logger.warning(e)
await message.answer(trans("error.user_already_banned", params={"username": username}))
else:
await message.answer(trans("error.incorrect_username"))
logger.warning(
f"{get_username_from_message(message)}: Incorrect username of banned user {username}")
banned_username = message.text

if not banned_username.startswith("@"):
await message.answer(t("error.incorrect_username"))
await state.clear()
return

try:
user_service.ban_user(banned_username[1:])
await message.answer(
t("message.user_is_banned", params={"username": banned_username})
)
except UserAlreadyBannedException as e:
await message.answer(
t("error.user_already_banned", params={"username": banned_username})
)
await state.clear()


@router.callback_query(MainMenuCallbackFactory.filter(F.action == "unban_user"))
async def unban_user(callback: CallbackQuery, state: FSMContext):
logger.info(f"{get_username_from_callback(callback)}: Start unban user")
await callback.message.answer(trans("message.enter_username"), reply_markup=create_cancel_menu())
await callback.message.answer(
t("message.enter_username"), reply_markup=create_cancel_menu()
)
await state.set_state(AdminStates.awaiting_unbanned_username)
logger.info(f"{get_username_from_callback(callback)}: Awaiting username of unbanned user")


@router.message(AdminStates.awaiting_unbanned_username)
async def process_ban(message: Message, state: FSMContext):
username = message.text
logger.info(f"{get_username_from_message(message)}: Enter username of unbanned user {username}")
if username.startswith('@'):
try:
user_service.unban_user(username[1:])
await message.answer(trans("message.user_is_unbanned", params={"username": username}))
logger.info(f"{get_username_from_message(message)}: User {username} is unbanned")
except UserNotBannedException as e:
logger.warning(e)
await message.answer(trans("error.user_not_banned", params={"username": username}))
else:
await message.answer(trans("error.incorrect_username"))
logger.warning(
f"{get_username_from_message(message)}: Incorrect username of unbanned user {username}")
if not username.startswith("@"):
await message.answer(t("error.incorrect_username"))
await state.clear()
return

try:
user_service.unban_user(username[1:])
await message.answer(
t("message.user_is_unbanned", params={"username": username})
)
except UserNotBannedException as e:
await message.answer(t("error.user_not_banned", params={"username": username}))
await state.clear()


@router.callback_query(MainMenuCallbackFactory.filter(F.action == "list_banned_users"))
async def list_banned_users(callback: CallbackQuery):
banned_users = user_service.get_banned_users()
if len(banned_users) > 0:
content = trans("message.list_banned_users") + "\n"
content = t("message.list_banned_users") + "\n"
for banned_user in banned_users:
content += "\n@" + banned_user.username
else:
content = trans("message.no_banned_users")
content = t("message.no_banned_users")
await callback.message.answer(content)


@router.callback_query(MainMenuCallbackFactory.filter(F.action == "list_admins"))
async def list_admins(callback: CallbackQuery):
admins = user_service.get_admins()
if len(admins) > 0:
content = t("message.list_admins") + "\n"
for admin in admins:
content += "\n@" + admin.username
else:
content = t("message.no_admins")
await callback.message.answer(content)
logger.info(f"{get_username_from_callback(callback)}: List banned users")
8 changes: 1 addition & 7 deletions app/bot/handlers/cancel_callback_handler.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import logging

from aiogram import Router
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery
from i18next import trans

from app.bot.callback_data import CancelCallbackFactory
from app.bot.utils.callback_utils import get_username_from_callback

router = Router(name="cancel")
logger = logging.getLogger("cancel")


@router.callback_query(CancelCallbackFactory.filter())
async def cancel(callback: CallbackQuery, state: FSMContext):
await callback.message.answer(trans("message.canceled"))
await state.clear()
logger.info(f"{get_username_from_callback(callback)}: Cancel the operation")
await callback.message.delete()
11 changes: 4 additions & 7 deletions app/bot/handlers/menu_command_handler.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import logging

from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message
from i18next import trans
from i18next import trans as t

from app.bot.keyboards import create_main_menu
from app.bot.utils.message_utils import get_username_from_message

router = Router(name="menu")
logger = logging.getLogger("menu")


@router.message(Command(commands=["menu"]))
async def menu(message: Message):
username = get_username_from_message(message)
await message.answer(trans("message.available_commands"),
reply_markup=create_main_menu(username))
logger.info(f"{get_username_from_message(message)}: Show main menu")
await message.answer(
t("message.available_commands"), reply_markup=create_main_menu(username)
)
Loading

0 comments on commit d4f4eb9

Please sign in to comment.