From 4d05f1f10d541ad052f7d6e808c448a7f35800e8 Mon Sep 17 00:00:00 2001 From: End-rey Date: Sun, 25 Feb 2024 05:35:06 +0300 Subject: [PATCH] make more functionals --- backend/app/common/AuthUser.py | 13 +++ backend/app/common/keyboards.py | 29 ++++++ .../app/database/bloodcentre/Bloodcentre.py | 24 +++-- .../bloodcentre/bloodcentre_orm_handlres.py | 71 +++++++++++++ backend/app/database/donation/Donation.py | 21 ++-- .../donation/donation_orm_handlers.py | 50 ++++++++++ backend/app/database/users/User.py | 67 ++++++------- .../app/database/users/user_orm_handlers.py | 24 +++-- backend/app/filters/admin_filter.py | 8 -- backend/app/filters/auth_filter.py | 11 +++ backend/app/filters/what_webapp.py | 13 +++ backend/app/handlers/for_auth_handlers.py | 99 +++++++++++++++++++ backend/app/handlers/start.py | 50 ++++------ backend/app/handlers/user_private.py | 5 - backend/main.py | 5 +- 15 files changed, 387 insertions(+), 103 deletions(-) create mode 100644 backend/app/common/AuthUser.py create mode 100644 backend/app/common/keyboards.py create mode 100644 backend/app/database/bloodcentre/bloodcentre_orm_handlres.py create mode 100644 backend/app/database/donation/donation_orm_handlers.py delete mode 100644 backend/app/filters/admin_filter.py create mode 100644 backend/app/filters/auth_filter.py create mode 100644 backend/app/filters/what_webapp.py create mode 100644 backend/app/handlers/for_auth_handlers.py diff --git a/backend/app/common/AuthUser.py b/backend/app/common/AuthUser.py new file mode 100644 index 0000000..d66a60c --- /dev/null +++ b/backend/app/common/AuthUser.py @@ -0,0 +1,13 @@ + +from typing import Optional, Self + + +class AuthUser(object): + def __init__(self, user_id: Optional[int] = None): + self.user_id = user_id + self.city_id = None + + def __new__(cls) -> Self: + if not hasattr(cls, 'instance'): + cls.instance = super(AuthUser, cls).__new__(cls) + return cls.instance \ No newline at end of file diff --git a/backend/app/common/keyboards.py b/backend/app/common/keyboards.py new file mode 100644 index 0000000..a57b019 --- /dev/null +++ b/backend/app/common/keyboards.py @@ -0,0 +1,29 @@ +from app.keyboards.reply import get_reply_keyboard +from aiogram import types + + +web_app_auth = types.WebAppInfo( + url="https://end-rey.github.io/DonorSearch-Module/auth") + + +web_up_profile = types.WebAppInfo( + url="https://end-rey.github.io/DonorSearch-Module/profile" +) +web_up_donation = types.WebAppInfo( + url="https://end-rey.github.io/DonorSearch-Module/" +) + +keyboard_profile = get_reply_keyboard("Профиль", + "Запланировать донацию", + "Список центров сдачи крови", + "Мои донации", + "Выйти", + web_app={ + 0: web_up_profile, + 1: web_up_donation + }, sizes=(2,2)) + + +keyboard_login_register = get_reply_keyboard( + "Вход / Регистрация", web_app={0: web_app_auth}, sizes=(1,)) + diff --git a/backend/app/database/bloodcentre/Bloodcentre.py b/backend/app/database/bloodcentre/Bloodcentre.py index db32957..30df613 100644 --- a/backend/app/database/bloodcentre/Bloodcentre.py +++ b/backend/app/database/bloodcentre/Bloodcentre.py @@ -1,5 +1,5 @@ -from sqlalchemy import Integer, String, Boolean -from sqlalchemy.orm import Mapped, mapped_column +from sqlalchemy import Float, Integer, String, Boolean, ForeignKey +from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database.models import Base @@ -8,20 +8,30 @@ class City(Base): id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) name: Mapped[str] = mapped_column(String, nullable=False) - region_id: Mapped[int] = mapped_column(Integer, nullable=False) + latitude: Mapped[float] = mapped_column(Float, nullable=False) + longitude: Mapped[float] = mapped_column(Float, nullable=False) + region_id: Mapped[int] = mapped_column(Integer, ForeignKey("region.id"), nullable=False) + + region = relationship("Region", back_populates="cities") + bloodcentres = relationship("BloodCentre", back_populates="city") class Region(Base): __tablename__ = "region" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) name: Mapped[str] = mapped_column(String, nullable=False) - country_id: Mapped[int] = mapped_column(Integer, nullable=False) + country_id: Mapped[int] = mapped_column(Integer, ForeignKey("country.id"), nullable=False) + + cities = relationship("City", back_populates="region") + country = relationship("Country", back_populates="regions") class Country(Base): __tablename__ = "country" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) name: Mapped[str] = mapped_column(String, nullable=False) + + regions = relationship("Region", back_populates="country") class BloodCentre(Base): __tablename__ = "bloodcentre" @@ -29,11 +39,13 @@ class BloodCentre(Base): id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) name: Mapped[str] = mapped_column(String, nullable=False) address: Mapped[str] = mapped_column(String, nullable=False) - city_id: Mapped[int] = mapped_column(Integer, nullable=False) + city_id: Mapped[int] = mapped_column(Integer, ForeignKey("city.id"), nullable=False) is_no_registration: Mapped[bool] = mapped_column(Boolean, nullable=False) is_typing: Mapped[bool] = mapped_column(Boolean, nullable=False) is_work_on_sat: Mapped[bool] = mapped_column(Boolean, nullable=False) is_work_on_sun: Mapped[bool] = mapped_column(Boolean, nullable=False) schedule: Mapped[str] = mapped_column(String, nullable=False) phone_numbers: Mapped[str] = mapped_column(String, nullable=False) - is_closed: Mapped[bool] = mapped_column(Boolean, nullable=False) \ No newline at end of file + is_closed: Mapped[bool] = mapped_column(Boolean, nullable=False) + + city = relationship("City", back_populates="bloodcentres") \ No newline at end of file diff --git a/backend/app/database/bloodcentre/bloodcentre_orm_handlres.py b/backend/app/database/bloodcentre/bloodcentre_orm_handlres.py new file mode 100644 index 0000000..5c87d7c --- /dev/null +++ b/backend/app/database/bloodcentre/bloodcentre_orm_handlres.py @@ -0,0 +1,71 @@ +from datetime import datetime +from sqlalchemy import func, select, update +from sqlalchemy.ext.asyncio import AsyncSession + +from app.database.bloodcentre.Bloodcentre import BloodCentre, Country, City, Region +from app.logger import get_logger +logger = get_logger() + +async def create_blood_centre(session: AsyncSession, dict: dict): + new_centre = BloodCentre( + name=dict['name'], + address=dict['address'], + city_id=dict['city_id'], + is_no_registration=dict['is_no_registration'], + is_typing=dict['is_typing'], + is_work_on_sat=dict['is_work_on_sat'], + is_work_on_sun=dict['is_work_on_sun'], + schedule=dict['schedule'], + phone_numbers=dict['phone_numbers'], + is_closed=dict['is_closed'] + ) + session.add(new_centre) + await session.commit() + +async def get_blood_centre_by_id(session: AsyncSession, centre_id: int): + stmt = select(BloodCentre).filter(BloodCentre.id == centre_id) + result = await session.execute(stmt) + return result.scalars().first() + +async def get_blood_centres_by_city(session: AsyncSession, city_id: int): + stmt = select(BloodCentre).filter(BloodCentre.city_id == city_id) + result = await session.execute(stmt) + return result.scalars().all() + +async def update_blood_centre(session: AsyncSession, centre_id: int, **kwargs): + stmt = select(BloodCentre).filter(BloodCentre.id == centre_id) + result = await session.execute(stmt) + centre = result.scalars().first() + if centre: + for attr, value in kwargs.items(): + setattr(centre, attr, value) + await session.commit() + else: + raise ValueError("Blood Centre not found") + +async def delete_blood_centre(session: AsyncSession, centre_id: int): + stmt = select(BloodCentre).filter(BloodCentre.id == centre_id) + result = await session.execute(stmt) + centre = result.scalars().first() + if centre: + session.delete(centre) + await session.commit() + else: + raise ValueError("Blood Centre not found") + +async def get_city_by_name(session: AsyncSession, city_name: str): + stmt = select(City).filter(City.name == city_name) + result = await session.execute(stmt) + return result.scalars().first() + +async def get_city_by_coordinates(session: AsyncSession, latitude: float, longitude: float): + stmt = select( + City, + func.sqrt( + func.pow(func.radians(latitude) - func.radians(City.latitude), 2) + + func.pow(func.radians(longitude) - func.radians(City.longitude), 2) + ).label("distance") + ).order_by("distance") + result = await session.execute(stmt) + nearest_city = result.scalars().first() + return nearest_city \ No newline at end of file diff --git a/backend/app/database/donation/Donation.py b/backend/app/database/donation/Donation.py index 51b6283..d416df4 100644 --- a/backend/app/database/donation/Donation.py +++ b/backend/app/database/donation/Donation.py @@ -1,23 +1,26 @@ -from sqlalchemy import Column, Enum, Integer, String, DateTime, Boolean, func -from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column +from enum import Enum +from sqlalchemy import Column, Enum as PgEnum, Integer, String, DateTime, Boolean, func, ForeignKey +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from app.database.models import Base class DonationType(Enum): - blood: "кровь" - plasma: "плазма" - platelets: "тромбоциты" - erythrocytes: "эритроциты" - leukocytes: "гранулоциты" + blood = "blood" + plasma = "plasma" + trombs = "trombs" + erits = "erits" + granuls = "granuls" class Donation(Base): __tablename__ = "donation" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) date: Mapped[DateTime] = mapped_column(DateTime, nullable=False) - user_id: Mapped[int] = mapped_column(Integer, nullable=False) - donation_type_id: Mapped[DonationType] = mapped_column(DonationType, nullable=False) + user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) + donation_type_id: Mapped[DonationType] = mapped_column(PgEnum(DonationType, name="donation_type"), nullable=False) is_commerce: Mapped[bool] = mapped_column(Boolean, nullable=False) is_confirmed: Mapped[bool] = mapped_column(Boolean, nullable=False) is_in_stationary_point: Mapped[bool] = mapped_column(Boolean, nullable=False) blood_centre_id: Mapped[int] = mapped_column(Integer, nullable=False) + + user = relationship("User", back_populates="donations") diff --git a/backend/app/database/donation/donation_orm_handlers.py b/backend/app/database/donation/donation_orm_handlers.py new file mode 100644 index 0000000..86affd1 --- /dev/null +++ b/backend/app/database/donation/donation_orm_handlers.py @@ -0,0 +1,50 @@ +from datetime import datetime +from sqlalchemy import select, update +from sqlalchemy.ext.asyncio import AsyncSession + +from app.database.donation.Donation import Donation, DonationType +from app.logger import get_logger +logger = get_logger() + + +async def get_all_donations(session: AsyncSession): + return await session.execute(select(Donation)) + + +async def get_donation_by_id(session: AsyncSession, donation_id: int): + result = await session.execute(select(Donation).filter(Donation.id == donation_id)) + donation = result.scalars().first() + return donation + + +async def get_donations_by_user_id(session: AsyncSession, user_id: int) -> list[Donation]: + result = await session.execute(select(Donation).filter(Donation.user_id == user_id)) + donation = result.scalars().all() + return donation + + +async def add_donation(session: AsyncSession, dict: dict): + try: + date = datetime.strptime(dict['donationData'], '%Y-%m-%dT%H:%M:%S.%fZ').date() + new_donation = Donation( + date = date, + user_id = dict['user_id'], + donation_type_id = DonationType(dict['donationType']), + is_commerce = dict['donationPrice'] == 'money', + is_confirmed = dict['donationCertificateDate'] == 'today', + is_in_stationary_point = dict['donationPlace'] == 'station', + blood_centre_id = 0 + ) + session.add(new_donation) + await session.commit() + return new_donation.id + except Exception as e: + logger.error(e) + await session.rollback() + return None + + +async def update_Donation(session: AsyncSession, donation_id, **kwargs): + stmt = update(Donation).where(Donation.id == donation_id).values(**kwargs) + await session.execute(stmt) + await session.commit() \ No newline at end of file diff --git a/backend/app/database/users/User.py b/backend/app/database/users/User.py index 361f51b..404ccfb 100644 --- a/backend/app/database/users/User.py +++ b/backend/app/database/users/User.py @@ -1,47 +1,48 @@ -from sqlalchemy import Enum, Integer, String, DateTime, Boolean +from enum import Enum +from sqlalchemy import Enum as PgEnum, Integer, String, DateTime, Boolean from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from app.database.models import Base +from sqlalchemy.orm import relationship + +class Gender(Enum): + male = "мужчина" + female = "женщина" class User(Base): __tablename__ = "users" + date_joined: Mapped[DateTime] = mapped_column(DateTime, nullable=False) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) first_name: Mapped[str] = mapped_column(String(255), nullable=False) email: Mapped[str] = mapped_column(String, unique=True, nullable=False) phone: Mapped[str] = mapped_column(String, nullable=False) password: Mapped[str] = mapped_column(String, nullable=False) + last_name: Mapped[str] = mapped_column(String(255), nullable=True) + middle_name: Mapped[str] = mapped_column(String(255), nullable=True) + maiden_name: Mapped[str] = mapped_column(String(255), nullable=True) + birth_date: Mapped[DateTime] = mapped_column(DateTime, nullable=True) + gender: Mapped[Gender] = mapped_column(PgEnum(Gender, name="gender"), nullable=True) + login_via_phone: Mapped[bool] = mapped_column(Boolean, nullable=True) + about: Mapped[str] = mapped_column(String(130), nullable=True) + city_id: Mapped[int] = mapped_column(Integer, nullable=False) + is_in_top_20: Mapped[bool] = mapped_column(Boolean, nullable=True) + is_in_top_100: Mapped[bool] = mapped_column(Boolean, nullable=True) + photo: Mapped[str] = mapped_column(String, nullable=True) + blood_group: Mapped[str] = mapped_column(String, nullable=False) + is_email_verified: Mapped[str] = mapped_column(String, nullable=False) + is_phone_verified: Mapped[str] = mapped_column(String, nullable=False) + email_reconfirmed_at: Mapped[str] = mapped_column(String, nullable=True) + phone_reconfirmed_at: Mapped[str] = mapped_column(String, nullable=True) + legacy_avatar: Mapped[str] = mapped_column(String, nullable=True) + start_donor_year: Mapped[int] = mapped_column(Integer, nullable=False) + referal_code: Mapped[str] = mapped_column(String, nullable=True) + parent_user_id: Mapped[int] = mapped_column(Integer, nullable=True) + donor_status: Mapped[str] = mapped_column(String, nullable=False) + managed_organizations: Mapped[str] = mapped_column(String, nullable=True) + joined_events: Mapped[str] = mapped_column(String, nullable=True) + joined_organizations: Mapped[str] = mapped_column(String, nullable=True) + donor_certificate: Mapped[bool] = mapped_column(Boolean, nullable=True) - # id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) - # date_joined: Mapped[DateTime] = mapped_column(DateTime, nullable=False) - # username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) - # first_name: Mapped[str] = mapped_column(String(255), nullable=False) - # last_name: Mapped[str] = mapped_column(String(255)) - # middle_name: Mapped[str] = mapped_column(String(255)) - # maiden_name: Mapped[str] = mapped_column(String(255)) - # birth_date: Mapped[DateTime] = mapped_column(DateTime) - # gender: Mapped[Gender] = mapped_column(Gender) - # email: Mapped[str] = mapped_column(String, unique=True, nullable=False) - # phone: Mapped[str] = mapped_column(String, unique=True, nullable=False) - # password: Mapped[str] = mapped_column(String, nullable=False) - # login_via_phone: Mapped[bool] = mapped_column(Boolean) - # about: Mapped[str] = mapped_column(String(130)) - # city_id: Mapped[int] = mapped_column(Integer, nullable=False) - # is_in_top_20: Mapped[bool] = mapped_column(Boolean) - # is_in_top_100: Mapped[bool] = mapped_column(Boolean) - # photo: Mapped[str] = mapped_column(String, nullable=False) - # blood_group: Mapped[str] = mapped_column(String, nullable=False) - # is_email_verified: Mapped[str] = mapped_column(String, nullable=False) - # is_phone_verified: Mapped[str] = mapped_column(String, nullable=False) - # email_reconfirmed_at: Mapped[str] = mapped_column(String) - # phone_reconfirmed_at: Mapped[str] = mapped_column(String) - # legacy_avatar: Mapped[str] = mapped_column(String, nullable=False) - # start_donor_year: Mapped[int] = mapped_column(Integer, nullable=False) - # referal_code: Mapped[str] = mapped_column(String, nullable=False) - # parent_user_id: Mapped[int] = mapped_column(Integer, nullable=False) - # donor_status: Mapped[str] = mapped_column(String, nullable=False) - # managed_organizations: Mapped[str] = mapped_column(String, nullable=False) - # joined_events: Mapped[str] = mapped_column(String, nullable=False) - # joined_organizations: Mapped[str] = mapped_column(String, nullable=False) - # donor_certificate: Mapped[bool] = mapped_column(Boolean) + donations = relationship("Donation", back_populates="user") diff --git a/backend/app/database/users/user_orm_handlers.py b/backend/app/database/users/user_orm_handlers.py index af9cd70..6beccaf 100644 --- a/backend/app/database/users/user_orm_handlers.py +++ b/backend/app/database/users/user_orm_handlers.py @@ -1,7 +1,6 @@ import datetime import hashlib - -from psycopg2 import IntegrityError +import uuid from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncSession @@ -28,7 +27,7 @@ async def get_user_by_username(session: AsyncSession, username): async def register_user(session: AsyncSession, dict: dict): - user = await session.execute(select(User).where(User.first_name == dict['first_name'])) + user = await session.execute(select(User).where(User.email == dict['email'])) if user.scalar() is not None: logger.info("User already exists") return None @@ -37,23 +36,30 @@ async def register_user(session: AsyncSession, dict: dict): date_joined = datetime.datetime.now() hashed_password = hashlib.sha256(dict['password'].encode()).hexdigest() new_user = User( - username=dict['first_name'], - first_name='', + date_joined=date_joined, + username=str(uuid.uuid4()), + first_name=dict['first_name'], email=dict['email'], phone='', password=hashed_password, + city_id=0, + blood_group='', + is_email_verified='False', + is_phone_verified='False', + start_donor_year=date_joined.year, + donor_status='' ) session.add(new_user) await session.commit() - # (await session.execute(select(User).where(User.name == dict['username']))).id return new_user.id - except IntegrityError: - session.rollback() + except Exception as e: + logger.error(e) + await session.rollback() return None async def login_user(session: AsyncSession, dict: dict): - user = await session.execute(select(User).where(User.username == dict['username'])) + user = await session.execute(select(User).where(User.email == dict['username'])) user = user.scalar() if user is not None and user.password == hashlib.sha256(dict['password'].encode()).hexdigest(): return user diff --git a/backend/app/filters/admin_filter.py b/backend/app/filters/admin_filter.py deleted file mode 100644 index d9f07eb..0000000 --- a/backend/app/filters/admin_filter.py +++ /dev/null @@ -1,8 +0,0 @@ -from aiogram.filters import Filter - -class AdminFilter(Filter): - def __init__(self, admins: list[int]): - self.admins = admins - - async def __call__(self, message): - return message.from_user.id in self.admins \ No newline at end of file diff --git a/backend/app/filters/auth_filter.py b/backend/app/filters/auth_filter.py new file mode 100644 index 0000000..0bc167c --- /dev/null +++ b/backend/app/filters/auth_filter.py @@ -0,0 +1,11 @@ +from aiogram import types +from typing import Optional +from aiogram.filters import Filter +from app.common.AuthUser import AuthUser + +auth_user = AuthUser() + +class isAuth(Filter): + async def __call__(self, message: types.Message): + return auth_user.user_id is not None + \ No newline at end of file diff --git a/backend/app/filters/what_webapp.py b/backend/app/filters/what_webapp.py new file mode 100644 index 0000000..2bd4b49 --- /dev/null +++ b/backend/app/filters/what_webapp.py @@ -0,0 +1,13 @@ +from aiogram import types +from typing import Optional +from aiogram.filters import Filter +from app.common.AuthUser import AuthUser + +auth_user = AuthUser() + +class whatWebApp(Filter): + def __init__(self, name: str): + self.name = name + + async def __call__(self, message: types.Message): + return message.web_app_data.button_text == self.name \ No newline at end of file diff --git a/backend/app/handlers/for_auth_handlers.py b/backend/app/handlers/for_auth_handlers.py new file mode 100644 index 0000000..31245b3 --- /dev/null +++ b/backend/app/handlers/for_auth_handlers.py @@ -0,0 +1,99 @@ +import types +from aiogram import Router +import json + +from aiogram import Router, types, F +from aiogram.fsm.state import StatesGroup, State +from aiogram.fsm.context import FSMContext +from aiogram.filters import StateFilter + +from sqlalchemy.ext.asyncio import AsyncSession + +from app.common.AuthUser import AuthUser +from app.filters.auth_filter import isAuth +from app.filters.what_webapp import whatWebApp +from app.database.donation import donation_orm_handlers +from app.database.bloodcentre import bloodcentre_orm_handlres +from app.common.keyboards import keyboard_profile, keyboard_login_register +from app.keyboards.inline import get_callback_btns +from app.keyboards.reply import get_reply_keyboard + +auth_user = AuthUser() +auth_router = Router() + +keyboard_location = get_reply_keyboard("Указать город", "Дать свое местоположение", reqest_location=1, sizes=(2,)) + +@auth_router.message(F.content_type == "web_app_data", isAuth(), whatWebApp("Профиль")) +async def webapp_profile_handler(message: types.Message) -> None: + await message.answer("Ваш профиль", reply_markup=keyboard_profile) + + +@auth_router.message(F.content_type == "web_app_data", isAuth(), whatWebApp("Запланировать донацию")) +async def donation_handler(message: types.Message, session: AsyncSession) -> None: + data = json.loads(message.web_app_data.data) + data['user_id'] = auth_user.user_id + donation_id = await donation_orm_handlers.add_donation(session, data) + if donation_id: + await message.answer("Запланировано!", reply_markup=keyboard_profile) + else: + await message.answer("Что-то пошло не так =(, повторите позже", reply_markup=keyboard_profile) + +@auth_router.message(F.text == "Мои донации", isAuth()) +async def my_donation_handler(message: types.Message, session: AsyncSession) -> None: + donations = await donation_orm_handlers.get_donations_by_user_id(session, user_id=auth_user.user_id) + if donations: + for donation in donations: + await message.answer(f"Запланировано на {donation.date}, здача {donation.donation_type_id.name}", reply_markup=keyboard_profile) + else: + await message.answer("Что-то пошло не так =(, повторите позже", reply_markup=keyboard_profile) + +@auth_router.message(F.text == "Список центров сдачи крови", isAuth()) +async def bloodcentres_handler(message: types.Message, session: AsyncSession) -> None: + if auth_user.city_id is None: + await message.answer("Укажите город или свой местоположение", reply_markup=keyboard_location) + return + bloodcentres = await bloodcentre_orm_handlres.get_blood_centres_by_city(session, city_id=auth_user.city_id) + if bloodcentres: + for bloodcentre in bloodcentres: + await message.answer(f"Название: {bloodcentre.name}, \ + \nАдрес: {bloodcentre.address}, \ + \nТелефон: {bloodcentre.phone_numbers}, \ + \nРасписание: {bloodcentre.schedule}", + reply_markup=keyboard_profile) + else: + await message.answer("Что-то пошло не так =(, повторите позже", reply_markup=keyboard_profile) + +class Sity(StatesGroup): + waiting_for_sity = State() + +@auth_router.message(F.text == "Указать город", isAuth(), StateFilter(None)) +async def set_city_handler(message: types.Message, state: FSMContext) -> None: + await message.answer("Пожалуйста, выберите свой город", reply_markup=types.ReplyKeyboardRemove()) + await state.set_state(Sity.waiting_for_sity) + +@auth_router.message(Sity.waiting_for_sity, isAuth()) +async def handle_sity(message: types.Message, session: AsyncSession, state: FSMContext) -> None: + city = await bloodcentre_orm_handlres.get_city_by_name(session, message.text) + if city: + auth_user.city_id = city.id + await message.answer(f"Ваш город: {city.name}", reply_markup=keyboard_profile) + else: + await message.answer("Не получилось =(, повторите позже", reply_markup=keyboard_profile) + await state.clear() + +@auth_router.message(F.content_type == types.ContentType.LOCATION, isAuth()) +async def handle_location(message: types.Message, session: AsyncSession) -> None: + latitude = message.location.latitude + longitude = message.location.longitude + city = await bloodcentre_orm_handlres.get_city_by_coordinates(session, latitude, longitude) + if city: + auth_user.city_id = city.id + await message.answer(f"Ваш город: {city.name}", reply_markup=keyboard_profile) + else: + await message.answer("Не получилось =(, повторите позже", reply_markup=keyboard_profile) + + +@auth_router.message(F.text == "Выйти", isAuth()) +async def my_donation_handler(message: types.Message) -> None: + auth_user.user_id = None + await message.answer("Вы вышли из аккаунта!", reply_markup=keyboard_login_register) \ No newline at end of file diff --git a/backend/app/handlers/start.py b/backend/app/handlers/start.py index 90ed9dc..dd692e7 100644 --- a/backend/app/handlers/start.py +++ b/backend/app/handlers/start.py @@ -6,54 +6,42 @@ from aiogram.fsm.context import FSMContext from sqlalchemy.ext.asyncio import AsyncSession +from app.common.AuthUser import AuthUser from app.database.users.user_orm_handlers import login_user, register_user -from app.keyboards.reply import get_reply_keyboard +from app.filters.auth_filter import isAuth +from app.common.keyboards import keyboard_profile, keyboard_login_register -class UnauthorizedUser(StatesGroup): - authorization = State() +auth_user = AuthUser() start_router = Router() -web_app_auth = types.WebAppInfo( - url="https://end-rey.github.io/DonorSearch-Module/auth") -web_up_profile = types.WebAppInfo( - url="https://end-rey.github.io/DonorSearch-Module/profile" -) -web_up_donation = types.WebAppInfo( - url="https://end-rey.github.io/DonorSearch-Module/" -) +@start_router.message(CommandStart(), isAuth()) +async def command_start_handler(message: types.Message) -> None: + await message.answer(f"Ты уже вошел, {auth_user.user_id}!", reply_markup=keyboard_profile) -keyboard_login_reister = get_reply_keyboard( - "Вход / Регистрация", web_app={0: web_app_auth}, sizes=(1,)) -keyboard_profile = get_reply_keyboard("Профиль", "Список донаций", web_app={0: web_up_profile, 1: web_up_donation}, sizes=(2,)) +@start_router.message(CommandStart()) +async def command_start_without_handler(message: types.Message) -> None: + await message.answer(f"Зарегистрируйся или войди в свой аккаунт!", reply_markup=keyboard_login_register) -@start_router.message(CommandStart(), StateFilter(None)) -async def command_start_handler(message: types.Message, state: FSMContext) -> None: - await message.answer(f"Привет, {hbold(message.from_user.full_name)}!", reply_markup=keyboard_login_reister) - await state.set_state(UnauthorizedUser.authorization) - -@start_router.message(F.content_type == "web_app_data", UnauthorizedUser.authorization) -async def webapp_data_handler(message: types.Message, session: AsyncSession, state: FSMContext) -> None: +@start_router.message(F.content_type == "web_app_data", ~isAuth()) +async def webapp_auth_handler(message: types.Message, session: AsyncSession) -> None: data = json.loads(message.web_app_data.data) if data['action'] == 'login': user = await login_user(session=session, dict=data) if user: - await message.answer("Добро пожаловать!", reply_markup=keyboard_profile) - await state.clear() + auth_user.user_id = user.id + await message.answer(f"Добро пожаловать, {auth_user.user_id}!", reply_markup=keyboard_profile) else: - await message.answer("Неверные данные!", reply_markup=keyboard_login_reister) + await message.answer("Неверные данные!", reply_markup=keyboard_login_register) elif data['action'] == 'register': user = await register_user(session=session, dict=data) if user: - await message.answer("Регистрация прошла успешно!", reply_markup=keyboard_login_reister) + await message.answer("Регистрация прошла успешно!", reply_markup=keyboard_login_register) else: - await message.answer("Пользователь с таким именем уже существует!", reply_markup=keyboard_login_reister) - + await message.answer("Пользователь с таким именем уже существует!", reply_markup=keyboard_login_register) + else: + await message.answer("Что-то пошло не так =(, повторите еще раз", reply_markup=keyboard_login_register) -@start_router.message(F.content_type == "web_app_data") -async def donation_handler(message: types.Message) -> None: - data = json.loads(message.web_app_data.data) - await message.answer(f"Молодец, будешь сдавать {data['donationType']}!", reply_markup=keyboard_profile) diff --git a/backend/app/handlers/user_private.py b/backend/app/handlers/user_private.py index 36670a8..0d53bb4 100644 --- a/backend/app/handlers/user_private.py +++ b/backend/app/handlers/user_private.py @@ -5,11 +5,6 @@ list_of_commands = ["menu", "site", "user", "needs_stations"] -@user_private_router.message(Command("menu")) -async def menu_handler(message: types.Message) -> None: - await message.answer("Menu") - - @user_private_router.message() async def echo_handler(message: types.Message) -> None: try: diff --git a/backend/main.py b/backend/main.py index eff9ba6..043e567 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,15 +3,16 @@ from aiogram import Bot, Dispatcher, types from aiogram.enums import ParseMode +from app.common.AuthUser import AuthUser from app.config import load_config from app.handlers.user_private import user_private_router from app.handlers.start import start_router +from app.handlers.for_auth_handlers import auth_router from app.common.bot_cmds_list import private from app.database.engine import DB from app.logger import get_logger from app.middlewares.db import DatabaseMiddleware -from app.database.engine import async_sessionmaker logger = get_logger() config = load_config(".env") @@ -23,10 +24,10 @@ dp = Dispatcher() dp.include_routers( start_router, + auth_router, user_private_router ) - async def on_startup(bot): await database.create_db() await bot.delete_webhook(drop_pending_updates=True)