notifications

This commit is contained in:
Egor Matveev 2022-05-15 11:05:46 +03:00
parent 138c3fa6e8
commit 4bc1981ef6
11 changed files with 205 additions and 43 deletions

View File

@ -356,6 +356,50 @@ services:
parallelism: 1
order: start-first
telegram_sender:
image: mathwave/sprint-repo:sprint
networks:
- net
command: ./manage.py telegram_sender
environment:
DB_HOST: "postgres"
FS_HOST: "storage"
RABBIT_HOST: "rabbitmq"
REDIS_HOST: "redis"
DB_PASSWORD: $DB_PASSWORD
DEBUG: $DEBUG
TELEGRAM_TOKEN: $TELEGRAM_TOKEN
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
update_config:
parallelism: 1
order: start-first
email_sender:
image: mathwave/sprint-repo:sprint
networks:
- net
command: ./manage.py email_sender
environment:
DB_HOST: "postgres"
FS_HOST: "storage"
RABBIT_HOST: "rabbitmq"
REDIS_HOST: "redis"
DB_PASSWORD: $DB_PASSWORD
DEBUG: $DEBUG
EMAIL_PASSWORD: $EMAIL_PASSWORD
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
update_config:
parallelism: 1
order: start-first
apply-languages:
image: mathwave/sprint-repo:sprint
networks:

View File

@ -360,6 +360,50 @@ services:
parallelism: 1
order: start-first
telegram_sender:
image: mathwave/sprint-repo:sprint
networks:
- net
command: ./manage.py telegram_sender
environment:
DB_HOST: "postgres"
FS_HOST: "storage"
RABBIT_HOST: "rabbitmq"
REDIS_HOST: "redis"
DB_PASSWORD: $DB_PASSWORD
DEBUG: $DEBUG
TELEGRAM_TOKEN: $TELEGRAM_TOKEN
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
update_config:
parallelism: 1
order: start-first
email_sender:
image: mathwave/sprint-repo:sprint
networks:
- net
command: ./manage.py email_sender
environment:
DB_HOST: "postgres"
FS_HOST: "storage"
RABBIT_HOST: "rabbitmq"
REDIS_HOST: "redis"
DB_PASSWORD: $DB_PASSWORD
DEBUG: $DEBUG
EMAIL_PASSWORD: $EMAIL_PASSWORD
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
update_config:
parallelism: 1
order: start-first
apply-languages:
image: mathwave/sprint-repo:sprint
networks:

View File

@ -10,8 +10,8 @@ from django.utils import timezone
from Checker.models import Checker
from FileStorage.sync import synchronized_method
from Main.models import Solution, SolutionFile, ExtraFile, Progress
from SprintLib.queue import send_to_queue
from SprintLib.utils import generate_token
from SprintLib.queue import notify as notification
def get_dynamic(request):
@ -92,13 +92,10 @@ def notify(request):
solution = Solution.objects.get(id=request.GET['solution_id'])
if checker.set != solution.set:
return JsonResponse({"status": "incorrect solution"}, status=403)
notification(
solution.user,
"solution_result",
f"Задача: {solution.task.name}\n"
f"Результат: {solution.result}\n"
f"Очки решения: {Progress.by_solution(solution).score}\n"
f"Текущий рейтинг: {solution.user.userinfo.rating}")
send_to_queue("notification", {
"type": "solution",
"solution_id": solution.id
})
return JsonResponse({"status": True})
except ObjectDoesNotExist:
return JsonResponse({"status": "incorrect token"}, status=403)

View File

@ -1,10 +1,10 @@
from django.contrib.auth.models import User
from django.db.models import Q
from SprintLib.queue import notify
from Main.models import Friendship
from SprintLib.BaseView import BaseView
from SprintLib.language import languages
from SprintLib.queue import send_to_queue
from SprintLib.utils import delete_file, write_bytes
@ -46,17 +46,26 @@ class AccountView(BaseView):
).first()
if friendship is None:
Friendship.objects.create(from_user=self.request.user, to_user=self.context["account"])
notify(self.context['account'], 'friends', f"Пользователь {self.request.user.username} хочет добавить тебя в друзья")
send_to_queue("notification", {
"type": "friends_add",
"from_user": self.request.user.id,
"to_user": self.context["account"].id
})
elif friendship.verified or friendship.from_user == self.request.user:
friendship.delete()
else:
if self.request.POST["to_do"] == "yes":
friendship.verified = True
friendship.save()
notify(self.context['account'], 'friends', f"Пользователь {self.request.user.username} добавил тебя в друзья")
else:
friendship.delete()
notify(self.context['account'], 'friends', f"Пользователь {self.request.user.username} отклонил твою заявку")
send_to_queue("notification", {
"type": "friends_accept",
"from_user": self.request.user.id,
"to_user": self.context['account'].id,
"accepted": self.request.POST['to_do'] == 'yes'
})
return "/account?username=" + self.request.GET["username"]
def post_upload_photo(self):

View File

@ -5,7 +5,7 @@ from django.contrib.auth.models import User
from Sprint import settings
from SprintLib.BaseView import BaseView
from SprintLib.queue import notify
from SprintLib.queue import send_to_queue
class SendCodeView(BaseView):
@ -23,7 +23,10 @@ class SendCodeView(BaseView):
print(f"Отправлен код для {username}", code)
user.userinfo.code = code
user.userinfo.save()
notify(user, "any", "Код для входа в сервис: " + str(code))
send_to_queue("telegram", {
"chat_id": user.userinfo.telegram_chat_id,
"text": "Код для входа в сервис: " + str(code)
})
return {"success": True, "message": "Код отправлен"}
def post_check(self):

View File

@ -147,6 +147,14 @@ RABBIT_PORT = 5672
FS_HOST = "http://" + os.getenv("FS_HOST", "127.0.0.1")
FS_PORT = 5555
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.yandex.ru"
EMAIL_HOST_USER = "sprint.no-reply@yandex.ru"
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_PASSWORD")
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False
# Authentication backends
AUTHENTICATION_BACKENDS = ("django.contrib.auth.backends.ModelBackend",)

View File

@ -56,11 +56,3 @@ class MessagingSupport(BaseCommand):
channel.start_consuming()
except AMQPConnectorException:
print("connection to rabbit failed: reconnecting")
def notify(user: User, notification_type: str, text: str):
send_to_queue("notifications", {
'user_id': user.id,
'type': notification_type,
'text': text,
})

View File

@ -5,7 +5,7 @@ from tempfile import TemporaryDirectory
from Main.models.progress import Progress
from Sprint.settings import CONSTS
from SprintLib.queue import notify, send_to_queue
from SprintLib.queue import send_to_queue
from SprintLib.utils import Timer
@ -111,14 +111,10 @@ class BaseTester:
def notify(self):
self.solution.user.userinfo.refresh_from_db()
notify(
self.solution.user,
"solution_result",
f"Задача: {self.solution.task.name}\n"
f"Результат: {self.solution.result}\n"
f"Очки решения: {Progress.by_solution(self.solution).score}\n"
f"Текущий рейтинг: {self.solution.user.userinfo.rating}",
)
send_to_queue("notification", {
"type": "solution",
"solution_id": self.solution.id
})
def cleanup(self):
self.solution.save()

View File

@ -0,0 +1,20 @@
from django.core.mail import send_mail
from Sprint.settings import EMAIL_HOST_USER
from SprintLib.queue import MessagingSupport
class Command(MessagingSupport):
help = "starts file email sender"
queue_name = "email"
def process(self, payload: dict):
subject = payload['subject']
message = payload['message']
email = payload['email']
send_mail(
subject,
message,
EMAIL_HOST_USER,
[email]
)

View File

@ -1,20 +1,53 @@
from django.contrib.auth.models import User
from SprintLib.queue import MessagingSupport
from daemons.management.commands.bot import bot
from Main.models import Solution, Progress
from SprintLib.queue import MessagingSupport, send_to_queue
class Command(MessagingSupport):
help = "starts file notification manager"
queue_name = "notifications"
queue_name = "notification"
def handle_solution(self, payload):
solution = Solution.objects.get(id=payload["solution_id"])
user = solution.user
if user.userinfo.notification_solution_result:
message = f"Задача: {solution.task.name}\n" \
f"Результат: {solution.result}\n" \
f"Очки решения: {Progress.by_solution(solution).score}\n" \
f"Текущий рейтинг: {solution.user.userinfo.rating}"
if user.userinfo.telegram_chat_id is not None:
yield "telegram", {"chat_id": user.userinfo.telegram_chat_id, "text": message}
if user.email:
yield "email", {"subject": "Тестирование завершено", "message": message, "email": user.email}
def handle_friends_add(self, payload):
user = User.objects.get(id=payload['to_user_id'])
from_user = User.objects.get(id=payload['from_user_id'])
if user.userinfo.notification_friends:
message = f"Пользователь {from_user.username} хочет добавить тебя в друзья"
if user.userinfo.telegram_chat_id:
yield "telegram", {"chat_id": user.userinfo.telegram_chat_id, "text": message}
if user.email:
yield "email", {"subject": "Новая заявка в друзья", "message": message, "email": user.email}
def handle_friends_accept(self, payload):
user = User.objects.get(id=payload['to_user_id'])
from_user = User.objects.get(id=payload['from_user_id'])
if user.userinfo.notification_friends:
if payload['accepted']:
message = f"Пользователь {from_user} одобрил заявку в друзья"
else:
message = f"Пользователь {from_user} отклонил заявку в друзья"
if user.userinfo.telegram_chat_id:
yield "telegram", {"chat_id": user.userinfo.telegram_chat_id, "text": message}
if user.email:
yield "email", {"subject": "Новая заявка в друзья", "message": message, "email": user.email}
def process(self, payload: dict):
user = User.objects.get(id=payload['user_id'])
notification_type = payload['type']
text = payload['text']
if notification_type == "any" or getattr(user.userinfo, "notification_" + notification_type):
bot.send_message(
user.userinfo.telegram_chat_id,
text,
parse_mode="html",
)
notification_type = payload["type"]
handler = getattr(self, "handle_" + notification_type, None)
if handler is None:
raise ValueError(f"Unknown type: {notification_type}")
for queue, payload in handler(payload):
send_to_queue(queue, payload)

View File

@ -0,0 +1,16 @@
from SprintLib.queue import MessagingSupport
from daemons.management.commands.bot import bot
class Command(MessagingSupport):
help = "starts file telegram sender"
queue_name = "telegram"
def process(self, payload: dict):
chat_id = payload['chat_id']
text = payload['text']
bot.send_message(
int(chat_id),
text,
parse_mode="html",
)