From 0b1cfc0356664438b29c0cd9b080af0e68655e59 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 21 Dec 2022 21:15:03 +0600 Subject: [PATCH 1/3] Refactoring send_notification and change_subscription --- bot/messages.py | 14 ++++++++------ core/services/mailing_type.py | 10 ++++++++++ core/services/user_service.py | 4 ++++ 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 core/services/mailing_type.py diff --git a/bot/messages.py b/bot/messages.py index 7c23a53c..4eac3204 100644 --- a/bot/messages.py +++ b/bot/messages.py @@ -11,6 +11,7 @@ from app.logger import bot_logger as logger from app.models import User from bot.charity_bot import dispatcher +from core.services.mailing_type import MailingType bot = Bot(config.TELEGRAM_TOKEN) @@ -31,8 +32,8 @@ class TelegramNotification: This class describes the functionality for working with notifications in Telegram. """ - def __init__(self, has_mailing: str = 'subscribed') -> None: - self.has_mailing = has_mailing + def __init__(self, sub_status: str = 'subscribed') -> None: + self.sub_status = sub_status # TODO refactoring https://github.com/python-telegram-bot/python-telegram-bot/wiki/Avoiding-flood-limits def send_notification(self, message): @@ -43,19 +44,20 @@ def send_notification(self, message): :param telegram_chats: Users query :return: """ - if self.has_mailing not in ('all', 'subscribed', 'unsubscribed'): + values = [member.value for member in MailingType] + if self.sub_status not in values: return False chats_list = [] query = db_session.query(User.telegram_id).filter(User.banned.is_(False)) - if self.has_mailing == 'subscribed': + if self.sub_status == MailingType.SUBSCRIBED.value: chats_list = query.filter(User.has_mailing.is_(True)) - if self.has_mailing == 'unsubscribed': + if self.sub_status == MailingType.UNSUBSCRIBED.value: chats_list = query.filter(User.has_mailing.is_(False)) - if self.has_mailing == 'all': + if self.sub_status == MailingType.ALL.value: chats_list = query user_notification_context = SendUserNotificationsContext([]) diff --git a/core/services/mailing_type.py b/core/services/mailing_type.py new file mode 100644 index 00000000..cd5079f6 --- /dev/null +++ b/core/services/mailing_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class MailingType(Enum): + """ + This class implements enumeration. + """ + SUBSCRIBED = 'subscribed' + UNSUBSCRIBED = 'unsubscribed' + ALL = 'all' diff --git a/core/services/user_service.py b/core/services/user_service.py index a74dd559..d50df471 100644 --- a/core/services/user_service.py +++ b/core/services/user_service.py @@ -1,3 +1,4 @@ +from flask import request, jsonify, make_response from sqlalchemy.exc import SQLAlchemyError from app.models import ReasonCanceling, User, Category, Task, Users_Categories, ExternalSiteUser @@ -135,7 +136,10 @@ def change_subscription(self, telegram_id): db_session.commit() except SQLAlchemyError as ex: logger.error(f"User DB - 'change_subscription' method: {str(ex)}") + db_session.rollback() + return user.has_mailing + logger.info("Subscription: Status successfully changed.") return user.has_mailing def change_user_category(self, telegram_id, category_id): From 2a433bcab8be744cc56510069db1f74d26dd4634 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 27 Dec 2022 00:24:35 +0600 Subject: [PATCH 2/3] After first review --- app/front/send_tg_notification.py | 34 +++++++++------------ app/request_models/telegram_notification.py | 8 +++++ bot/messages.py | 18 ++++------- core/services/user_service.py | 11 ++----- 4 files changed, 32 insertions(+), 39 deletions(-) create mode 100644 app/request_models/telegram_notification.py diff --git a/app/front/send_tg_notification.py b/app/front/send_tg_notification.py index 82119056..141f6543 100644 --- a/app/front/send_tg_notification.py +++ b/app/front/send_tg_notification.py @@ -1,28 +1,26 @@ import datetime -from flask import jsonify, make_response -from flask_apispec import doc, use_kwargs +from flask import jsonify, make_response, request +from flask_apispec import doc from flask_apispec.views import MethodResource from flask_jwt_extended import jwt_required, get_jwt_identity from flask_restful import Resource -from marshmallow import fields, Schema from sqlalchemy.exc import SQLAlchemyError from app import config from app.database import db_session from app.logger import app_logger as logger from app.models import Notification +from app.request_models.telegram_notification import TelegramNotificationRequest +from app.webhooks.check_request import request_to_context +from app.webhooks.check_webhooks_token import check_webhooks_token from bot.messages import TelegramNotification - - - -class TelegramNotificationSchema(Schema): - message = fields.String(required=True) - has_mailing = fields.String(required=True) +from core.services.mailing_type import MailingType class SendTelegramNotification(Resource, MethodResource): + method_decorators = {'post': [check_webhooks_token]} @doc(description='Sends message to the Telegram chat. Requires "message" parameter.' ' Messages can be sent either to subscribed users or not.To do this,' @@ -52,26 +50,24 @@ class SendTelegramNotification(Resource, MethodResource): 'Authorization': config.PARAM_HEADER_AUTH, # Only if request requires authorization } ) - @use_kwargs(TelegramNotificationSchema) @jwt_required() - def post(self, **kwargs): - message = kwargs.get('message').replace(' ', '') - has_mailing = kwargs.get('has_mailing') + def post(self): + notifications = request_to_context(TelegramNotificationRequest, request) - if not message or not has_mailing: + if ['message', 'has_mailing'] not in notifications: logger.info("Messages: The and parameters have not been passed") return make_response(jsonify(result="Необходимо указать параметры и ."), 400) authorized_user = get_jwt_identity() - message = Notification(message=message, sent_by=authorized_user) + message = Notification(message=notifications['message'], sent_by=authorized_user) db_session.add(message) try: db_session.commit() - job_queue = TelegramNotification(has_mailing) + job_queue = TelegramNotification() - if not job_queue.send_notification(message=message.message): - logger.info(f"Messages: Passed invalid parameter. Passed: {has_mailing}") - return make_response(jsonify(result=f"Неверно указан параметр . " + if not job_queue.send_notification(message=message, mailing_type=MailingType.value): + logger.info(f"Messages: Passed invalid parameter. Passed: {MailingType.value}") + return make_response(jsonify(result=f"Неверно указан параметр . " f"Сообщение не отправлено."), 400) message.was_sent = True diff --git a/app/request_models/telegram_notification.py b/app/request_models/telegram_notification.py new file mode 100644 index 00000000..31cd39f1 --- /dev/null +++ b/app/request_models/telegram_notification.py @@ -0,0 +1,8 @@ +from pydantic import Field, StrictStr + +from app.request_models.request_base import RequestBase + + +class TelegramNotificationRequest(RequestBase): + message: StrictStr = Field() + has_mailing: StrictStr = Field() diff --git a/bot/messages.py b/bot/messages.py index 4eac3204..1385ec7b 100644 --- a/bot/messages.py +++ b/bot/messages.py @@ -31,33 +31,27 @@ class TelegramNotification: """ This class describes the functionality for working with notifications in Telegram. """ - - def __init__(self, sub_status: str = 'subscribed') -> None: - self.sub_status = sub_status - - # TODO refactoring https://github.com/python-telegram-bot/python-telegram-bot/wiki/Avoiding-flood-limits - def send_notification(self, message): + def send_notification(self, mailing_type, message): """ Adds queue to send notification to telegram chats. - + :param mailing_type: Type of subscription :param message: Message to add to the sending queue - :param telegram_chats: Users query :return: """ values = [member.value for member in MailingType] - if self.sub_status not in values: + if mailing_type not in values: return False chats_list = [] query = db_session.query(User.telegram_id).filter(User.banned.is_(False)) - if self.sub_status == MailingType.SUBSCRIBED.value: + if mailing_type == MailingType.SUBSCRIBED.value: chats_list = query.filter(User.has_mailing.is_(True)) - if self.sub_status == MailingType.UNSUBSCRIBED.value: + if mailing_type == MailingType.UNSUBSCRIBED.value: chats_list = query.filter(User.has_mailing.is_(False)) - if self.sub_status == MailingType.ALL.value: + if mailing_type == MailingType.ALL.value: chats_list = query user_notification_context = SendUserNotificationsContext([]) diff --git a/core/services/user_service.py b/core/services/user_service.py index d50df471..9182df8f 100644 --- a/core/services/user_service.py +++ b/core/services/user_service.py @@ -1,4 +1,3 @@ -from flask import request, jsonify, make_response from sqlalchemy.exc import SQLAlchemyError from app.models import ReasonCanceling, User, Category, Task, Users_Categories, ExternalSiteUser @@ -128,20 +127,16 @@ def change_subscription(self, telegram_id): """ user = User.query.options(load_only('has_mailing')).filter_by(telegram_id=telegram_id).first() - if user.has_mailing: - user.has_mailing = False - else: - user.has_mailing = True try: + user.has_mailing = not user.has_mailing db_session.commit() + logger.info("Subscription: Status successfully changed.") + return user.has_mailing except SQLAlchemyError as ex: logger.error(f"User DB - 'change_subscription' method: {str(ex)}") db_session.rollback() return user.has_mailing - logger.info("Subscription: Status successfully changed.") - return user.has_mailing - def change_user_category(self, telegram_id, category_id): user = User.query.filter_by(telegram_id=telegram_id).first() category = Category.query.get(category_id) From 36b07a7d36ded621454dcd6f9e909eb9dc1f63b8 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 28 Dec 2022 00:55:09 +0600 Subject: [PATCH 3/3] After second review --- app/front/send_tg_notification.py | 15 +++------------ app/request_models/telegram_notification.py | 7 ++++++- bot/messages.py | 10 +++------- core/services/mailing_type.py | 16 +++++++++++----- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/app/front/send_tg_notification.py b/app/front/send_tg_notification.py index 141f6543..934905ae 100644 --- a/app/front/send_tg_notification.py +++ b/app/front/send_tg_notification.py @@ -16,7 +16,6 @@ from app.webhooks.check_webhooks_token import check_webhooks_token from bot.messages import TelegramNotification -from core.services.mailing_type import MailingType class SendTelegramNotification(Resource, MethodResource): @@ -53,22 +52,14 @@ class SendTelegramNotification(Resource, MethodResource): @jwt_required() def post(self): notifications = request_to_context(TelegramNotificationRequest, request) - - if ['message', 'has_mailing'] not in notifications: - logger.info("Messages: The and parameters have not been passed") - return make_response(jsonify(result="Необходимо указать параметры и ."), 400) - authorized_user = get_jwt_identity() message = Notification(message=notifications['message'], sent_by=authorized_user) db_session.add(message) + try: db_session.commit() - job_queue = TelegramNotification() - - if not job_queue.send_notification(message=message, mailing_type=MailingType.value): - logger.info(f"Messages: Passed invalid parameter. Passed: {MailingType.value}") - return make_response(jsonify(result=f"Неверно указан параметр . " - f"Сообщение не отправлено."), 400) + notifier = TelegramNotification() + notifier.send_notification(mailing_type=notifications, message=message.message) message.was_sent = True message.sent_date = datetime.datetime.now() diff --git a/app/request_models/telegram_notification.py b/app/request_models/telegram_notification.py index 31cd39f1..ddb90eca 100644 --- a/app/request_models/telegram_notification.py +++ b/app/request_models/telegram_notification.py @@ -1,8 +1,13 @@ from pydantic import Field, StrictStr from app.request_models.request_base import RequestBase +from core.services.mailing_type import MailingType, MailingNumber class TelegramNotificationRequest(RequestBase): message: StrictStr = Field() - has_mailing: StrictStr = Field() + mailing_type: MailingType = MailingType.subscribed + mailing_number: MailingNumber = MailingNumber.subscribed + + class Config: + use_enum_values = True diff --git a/bot/messages.py b/bot/messages.py index 1385ec7b..42874ece 100644 --- a/bot/messages.py +++ b/bot/messages.py @@ -38,20 +38,16 @@ def send_notification(self, mailing_type, message): :param message: Message to add to the sending queue :return: """ - values = [member.value for member in MailingType] - if mailing_type not in values: - return False - chats_list = [] query = db_session.query(User.telegram_id).filter(User.banned.is_(False)) - if mailing_type == MailingType.SUBSCRIBED.value: + if mailing_type == MailingType.subscribed.value: chats_list = query.filter(User.has_mailing.is_(True)) - if mailing_type == MailingType.UNSUBSCRIBED.value: + if mailing_type == MailingType.unsubscribed.value: chats_list = query.filter(User.has_mailing.is_(False)) - if mailing_type == MailingType.ALL.value: + if mailing_type == MailingType.all.value: chats_list = query user_notification_context = SendUserNotificationsContext([]) diff --git a/core/services/mailing_type.py b/core/services/mailing_type.py index cd5079f6..5ef0ab20 100644 --- a/core/services/mailing_type.py +++ b/core/services/mailing_type.py @@ -1,10 +1,16 @@ -from enum import Enum +from enum import Enum, IntEnum -class MailingType(Enum): +class MailingType(str, Enum): """ This class implements enumeration. """ - SUBSCRIBED = 'subscribed' - UNSUBSCRIBED = 'unsubscribed' - ALL = 'all' + subscribed = 'subscribed' + unsubscribed = 'unsubscribed' + all = 'all' + + +class MailingNumber(IntEnum): + subscribed = 1 + unsubscribed = 2 + all = 3