diff --git a/app/front/send_tg_notification.py b/app/front/send_tg_notification.py index 82119056..934905ae 100644 --- a/app/front/send_tg_notification.py +++ b/app/front/send_tg_notification.py @@ -1,28 +1,25 @@ 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) - - 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,27 +49,17 @@ 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') - - if not message or not has_mailing: - logger.info("Messages: The and parameters have not been passed") - return make_response(jsonify(result="Необходимо указать параметры и ."), 400) - + def post(self): + notifications = request_to_context(TelegramNotificationRequest, request) 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) - - 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"Неверно указан параметр . " - 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 new file mode 100644 index 00000000..ddb90eca --- /dev/null +++ b/app/request_models/telegram_notification.py @@ -0,0 +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() + 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 7c23a53c..42874ece 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) @@ -30,32 +31,23 @@ 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 - - # 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: """ - if self.has_mailing not in ('all', 'subscribed', 'unsubscribed'): - return False - chats_list = [] query = db_session.query(User.telegram_id).filter(User.banned.is_(False)) - if self.has_mailing == 'subscribed': + if mailing_type == MailingType.subscribed.value: chats_list = query.filter(User.has_mailing.is_(True)) - if self.has_mailing == 'unsubscribed': + if mailing_type == MailingType.unsubscribed.value: chats_list = query.filter(User.has_mailing.is_(False)) - if self.has_mailing == 'all': + 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 new file mode 100644 index 00000000..5ef0ab20 --- /dev/null +++ b/core/services/mailing_type.py @@ -0,0 +1,16 @@ +from enum import Enum, IntEnum + + +class MailingType(str, Enum): + """ + This class implements enumeration. + """ + subscribed = 'subscribed' + unsubscribed = 'unsubscribed' + all = 'all' + + +class MailingNumber(IntEnum): + subscribed = 1 + unsubscribed = 2 + all = 3 diff --git a/core/services/user_service.py b/core/services/user_service.py index a74dd559..9182df8f 100644 --- a/core/services/user_service.py +++ b/core/services/user_service.py @@ -127,16 +127,15 @@ 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)}") - - return user.has_mailing + db_session.rollback() + return user.has_mailing def change_user_category(self, telegram_id, category_id): user = User.query.filter_by(telegram_id=telegram_id).first()