From 834949963f142b317fb0d15b40cb92034e28af03 Mon Sep 17 00:00:00 2001 From: Alexander Timchenko Date: Sun, 22 Sep 2024 16:07:44 +0300 Subject: [PATCH 1/5] add last_interaction models field --- ...9-22_16.01.34_add_user_last_interaction.py | 30 +++++++++++++++++++ src/core/db/models.py | 2 ++ 2 files changed, 32 insertions(+) create mode 100644 src/core/db/migrations/versions/2024-09-22_16.01.34_add_user_last_interaction.py diff --git a/src/core/db/migrations/versions/2024-09-22_16.01.34_add_user_last_interaction.py b/src/core/db/migrations/versions/2024-09-22_16.01.34_add_user_last_interaction.py new file mode 100644 index 00000000..d9f76b16 --- /dev/null +++ b/src/core/db/migrations/versions/2024-09-22_16.01.34_add_user_last_interaction.py @@ -0,0 +1,30 @@ +"""add user.last_interaction + +Revision ID: f4524481b9dc +Revises: b155a83b9476 +Create Date: 2024-09-22 16:01:34.651499 + +""" + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = "f4524481b9dc" +down_revision = "b155a83b9476" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("external_site_users", sa.Column("last_interaction", sa.DateTime(), nullable=True)) + op.add_column("users", sa.Column("last_interaction", sa.DateTime(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("users", "last_interaction") + op.drop_column("external_site_users", "last_interaction") + # ### end Alembic commands ### diff --git a/src/core/db/models.py b/src/core/db/models.py index 5ef4bfbd..e957a329 100644 --- a/src/core/db/models.py +++ b/src/core/db/models.py @@ -71,6 +71,7 @@ class User(Base): external_id: Mapped[int | None] = mapped_column(ForeignKey("external_site_users.id"), nullable=True) external_user: Mapped["ExternalSiteUser"] = relationship(back_populates="user") + last_interaction: Mapped[datetime | None] = mapped_column(nullable=True) @property def is_volunteer(self) -> bool: @@ -116,6 +117,7 @@ class ExternalSiteUser(ArchivableBase): has_mailing_profile: Mapped[bool] = mapped_column(nullable=True) has_mailing_my_tasks: Mapped[bool] = mapped_column(nullable=True) has_mailing_procharity: Mapped[bool] = mapped_column(nullable=True) + last_interaction: Mapped[datetime | None] = mapped_column(nullable=True) def __repr__(self): return f"" From b6b7718ac4f874bfe9b878689e8bff235154cb3e Mon Sep 17 00:00:00 2001 From: Alexander Timchenko Date: Sun, 22 Sep 2024 19:59:59 +0300 Subject: [PATCH 2/5] add user repository update_last_interaction() --- src/core/db/repository/external_site_user.py | 7 ++++++- src/core/db/repository/user.py | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/db/repository/external_site_user.py b/src/core/db/repository/external_site_user.py index 6752df51..d7a76758 100644 --- a/src/core/db/repository/external_site_user.py +++ b/src/core/db/repository/external_site_user.py @@ -1,4 +1,4 @@ -from sqlalchemy import select +from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from src.core.db.models import ExternalSiteUser, Task, TaskResponseVolunteer @@ -100,3 +100,8 @@ async def set_has_mailing_procharity(self, site_user: ExternalSiteUser, has_mail """Изменяет настройку уведомлений о ProCharity.""" site_user.has_mailing_procharity = has_mailing_procharity await self.update(site_user.id, site_user) + + async def update_last_interaction(self, site_user: ExternalSiteUser) -> None: + """Обновляет статус ExternalSiteUser.last_interaction текущим временем.""" + site_user.last_interaction = func.now() + await self.update(site_user.id, site_user) diff --git a/src/core/db/repository/user.py b/src/core/db/repository/user.py index abdb9a06..0413a071 100644 --- a/src/core/db/repository/user.py +++ b/src/core/db/repository/user.py @@ -149,3 +149,8 @@ async def get_filtered_objects_by_page( ) objects = await self._session.scalars(statement.limit(limit).offset(offset).order_by(desc(column_name))) return objects.all() + + async def update_last_interaction(self, user: User) -> None: + """Обновляет статус User.last_interaction текущим временем.""" + user.last_interaction = func.now() + await self.update(user.id, user) From a1901d6c4c0e385cfff16369381ef05561920024 Mon Sep 17 00:00:00 2001 From: Alexander Timchenko Date: Sun, 22 Sep 2024 20:46:19 +0300 Subject: [PATCH 3/5] add last_interaction update in decorator and service --- src/bot/services/external_site_user.py | 9 +++++++++ src/bot/utils.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/bot/services/external_site_user.py b/src/bot/services/external_site_user.py index ad4f9529..5854e544 100644 --- a/src/bot/services/external_site_user.py +++ b/src/bot/services/external_site_user.py @@ -52,3 +52,12 @@ async def toggle_has_mailing(self, site_user_id: int, field: HasMailingField) -> await self._repository.set_has_mailing_my_tasks(site_user, not site_user.has_mailing_my_tasks) case HasMailingField.procharity: await self._repository.set_has_mailing_procharity(site_user, not site_user.has_mailing_procharity) + + async def update_last_interaction(self, site_user: ExternalSiteUser) -> None: + """Обновляет last_interaction для site_user и соответствующего user.""" + if not site_user: + return + await self._repository.update_last_interaction(site_user) + user = await self._user_repository.get_by_external_id(site_user.id) + if user: + await self._user_repository.update_last_interaction(user) diff --git a/src/bot/utils.py b/src/bot/utils.py index 8c20ae6a..2c9dc419 100644 --- a/src/bot/utils.py +++ b/src/bot/utils.py @@ -82,6 +82,8 @@ async def decorated_handler( parse_mode=ParseMode.HTML, reply_markup=keyboard, ) + if ext_site_user: + await ext_site_user_service.update_last_interaction(ext_site_user) return decorated_handler From 26de51d0f7e84492b563479470cbb8d310b33047 Mon Sep 17 00:00:00 2001 From: Alexander Timchenko Date: Sun, 6 Oct 2024 20:39:54 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD?= =?UTF-8?q?=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20use?= =?UTF-8?q?r=5Fservice.update=5Flast=5Finteraction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bot/services/external_site_user.py | 5 +---- src/bot/services/user.py | 11 +++++++++++ src/bot/utils.py | 5 ++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/bot/services/external_site_user.py b/src/bot/services/external_site_user.py index 5854e544..00eb5d2a 100644 --- a/src/bot/services/external_site_user.py +++ b/src/bot/services/external_site_user.py @@ -54,10 +54,7 @@ async def toggle_has_mailing(self, site_user_id: int, field: HasMailingField) -> await self._repository.set_has_mailing_procharity(site_user, not site_user.has_mailing_procharity) async def update_last_interaction(self, site_user: ExternalSiteUser) -> None: - """Обновляет last_interaction для site_user и соответствующего user.""" + """Обновляет last_interaction для site_user.""" if not site_user: return await self._repository.update_last_interaction(site_user) - user = await self._user_repository.get_by_external_id(site_user.id) - if user: - await self._user_repository.update_last_interaction(user) diff --git a/src/bot/services/user.py b/src/bot/services/user.py index 0295e886..64e836f4 100644 --- a/src/bot/services/user.py +++ b/src/bot/services/user.py @@ -144,3 +144,14 @@ async def get_by_user_id(self, user_id: int) -> User: """Возвращает пользователя (или None) по user_id.""" user = await self._user_repository.get_by_user_id(user_id) return user + + async def get_by_telegram_id(self, telegram_id: int) -> User: + """Возвращает пользователя (или None) по telegram_id.""" + user = await self._user_repository.get_by_telegram_id(telegram_id) + return user + + async def update_last_interaction(self, user: User) -> None: + """Обновляет last_interaction для user.""" + if not user: + return + await self._user_repository.update_last_interaction(user) diff --git a/src/bot/utils.py b/src/bot/utils.py index 2c9dc419..4d7f6b8f 100644 --- a/src/bot/utils.py +++ b/src/bot/utils.py @@ -7,7 +7,7 @@ from telegram.ext import ContextTypes from src.bot.keyboards import get_unregistered_user_keyboard -from src.bot.services import ExternalSiteUserService +from src.bot.services import ExternalSiteUserService, UserService from src.core.depends import Container from src.core.enums import UserRoles, UserStatus @@ -54,6 +54,7 @@ async def decorated_handler( ext_site_user_service: ExternalSiteUserService = Provide[ Container.bot_services_container.bot_site_user_service ], + user_service: UserService = Provide[Container.bot_services_container.bot_user_service], *args, **kwargs, ): @@ -84,6 +85,8 @@ async def decorated_handler( ) if ext_site_user: await ext_site_user_service.update_last_interaction(ext_site_user) + if user := await user_service.get_by_telegram_id(telegram_user.id): + await user_service.update_last_interaction(user) return decorated_handler From 5230affccd18422a44f4b2727280141fa92067ed Mon Sep 17 00:00:00 2001 From: Alexander Timchenko Date: Sat, 12 Oct 2024 18:35:11 +0300 Subject: [PATCH 5/5] fix registered_user_required decorator --- src/bot/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bot/utils.py b/src/bot/utils.py index 4d7f6b8f..99038534 100644 --- a/src/bot/utils.py +++ b/src/bot/utils.py @@ -54,7 +54,7 @@ async def decorated_handler( ext_site_user_service: ExternalSiteUserService = Provide[ Container.bot_services_container.bot_site_user_service ], - user_service: UserService = Provide[Container.bot_services_container.bot_user_service], + bot_user_service: UserService = Provide[Container.bot_services_container.bot_user_service], *args, **kwargs, ): @@ -85,8 +85,8 @@ async def decorated_handler( ) if ext_site_user: await ext_site_user_service.update_last_interaction(ext_site_user) - if user := await user_service.get_by_telegram_id(telegram_user.id): - await user_service.update_last_interaction(user) + if user := await bot_user_service.get_by_telegram_id(telegram_user.id): + await bot_user_service.update_last_interaction(user) return decorated_handler