From 2947ddca98ab444475da4fa1a7cc393a63d7dba6 Mon Sep 17 00:00:00 2001 From: Yoan Le Clanche Date: Mon, 4 Dec 2023 17:05:27 +0100 Subject: [PATCH] Fix conference notifications --- .../teleforma-publish-notify-conferences.py | 149 ++++++++++++++++++ .../migrations/0007_auto_20231204_1650.py | 28 ++++ teleforma/models/core.py | 14 +- 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 teleforma/management/commands/teleforma-publish-notify-conferences.py create mode 100644 teleforma/migrations/0007_auto_20231204_1650.py diff --git a/teleforma/management/commands/teleforma-publish-notify-conferences.py b/teleforma/management/commands/teleforma-publish-notify-conferences.py new file mode 100644 index 00000000..2e5bbc98 --- /dev/null +++ b/teleforma/management/commands/teleforma-publish-notify-conferences.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- + +from optparse import make_option +import logging +import os +from copy import deepcopy + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.contrib.auth.models import User +from django.template.defaultfilters import slugify +from django.urls import reverse +from teleforma.models.core import Conference, Period +from teleforma.models.crfpa import Student +from teleforma.models.notification import notify +from teleforma.views.core import get_courses +import datetime + + +MINUTES_LOW_RANGE = 5 +MINUTES_HIGH_RANGE = 25 + +class Logger: + """A logging object""" + + def __init__(self, file): + self.logger = logging.getLogger('myapp') + if file: + self.hdlr = logging.FileHandler(file) + else: + self.hdlr = None + self.formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') + if self.hdlr: + self.hdlr.setFormatter(self.formatter) + self.logger.addHandler(self.hdlr) + self.logger.setLevel(logging.INFO) + + +class Command(BaseCommand): + help = """Publish conferences and notify users when \ + conference.date_publish is equal or greater \ + than current date """ + + def add_arguments(self, parser): + parser.add_argument('--logfile', type=str, required=False, + help='log file to use') + + parser.add_argument('--period', type=str, required=True, + help='period to process') + + parser.add_argument('--minute-low-range', type=int, required=False, + help='minute low range') + + parser.add_argument('--minute-high-range', type=int, required=False, + help='minute high range') + + def handle(self, *args, **options): + logpath = options['logfile'] + logger = Logger(logpath) + + + period_name = options['period'] + period = Period.objects.get(name=period_name) + + minute_low_range = options['minute_low_range'] + if not minute_low_range: + minute_low_range = MINUTES_LOW_RANGE + + minute_high_range = options['minute_high_range'] + if not minute_high_range: + minute_high_range = MINUTES_HIGH_RANGE + + now = datetime.datetime.now() + now_minus = now - datetime.timedelta(minutes=minute_low_range) + now_plus = now + datetime.timedelta(minutes=minute_high_range) + + publications = list(Conference.objects.filter( + period=period, + status=2, + notified=False, + date_publish__lte=now_plus, + date_publish__gte=now_minus, + )) + print(publications) + + logger.logger.info("Starting conference publication process") + + for publication in publications: + + conference = publication + + medias = conference.media.all() + + if medias: + publication.status = 3 + + for media in medias: + media.is_published = True + media.save() + + linked_media = media + + publication.save() + logger.logger.info("Conference published: " + conference.public_id) + + # media = conference.media.filter(mime_type='video/mp4')[0] + url = reverse('teleforma-media-detail', args=[conference.period.id, linked_media.id]) + + if conference.professor: + elm = [conference.course.title, + conference.course_type.name, conference.session, + conference.professor.user.first_name, + conference.professor.user.last_name] + else: + elm = [conference.course.title, + conference.course_type.name, conference.session] + message = "Nouvelle conférence publiée : " + ' - '.join(elm) + + students = Student.objects.filter(period=publication.period, platform_only=True) + for student in students: + try: + if student.user: + courses = get_courses(student.user, period=publication.period) + for course in courses: + if conference.course == course['course'] and \ + conference.course_type in course['types']: + notify(student.user, message, url) + logger.logger.info("Student notified: " + student.user.username) + print("notify", student) + except: + #logger.logger.info("Student NOT notified: " + str(student.id)) + print("can't notify", student) + continue + + for user in User.objects.filter(is_staff=True): + notify(user, message, url) + + publication.notified = True + publication.save() + + # streaming published end conference should have a streaming propery set to False + for conference in Conference.objects.filter( + period=period, + status=3, + streaming=True, + date_end__lt=now): + conference.streaming = False + conference.save() + diff --git a/teleforma/migrations/0007_auto_20231204_1650.py b/teleforma/migrations/0007_auto_20231204_1650.py new file mode 100644 index 00000000..fdc7ba3f --- /dev/null +++ b/teleforma/migrations/0007_auto_20231204_1650.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.13 on 2023-12-04 16:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('teleforma', '0006_groupedmessage_studentgroup'), + ] + + operations = [ + migrations.AddField( + model_name='conference', + name='date_publish', + field=models.DateTimeField(blank=True, null=True, verbose_name='publishing date'), + ), + migrations.AddField( + model_name='conference', + name='notified', + field=models.BooleanField(default=False, verbose_name='notified'), + ), + migrations.AddField( + model_name='conference', + name='notified_live', + field=models.BooleanField(default=False, verbose_name='Notifié live'), + ), + ] diff --git a/teleforma/models/core.py b/teleforma/models/core.py index 401dab67..8ae8e584 100755 --- a/teleforma/models/core.py +++ b/teleforma/models/core.py @@ -47,8 +47,9 @@ from django.core.paginator import InvalidPage from django.db import models from django.forms.fields import FileField from django.template.defaultfilters import random, slugify -from django.urls import reverse_lazy +from django.urls import reverse_lazy, reverse from django.utils.translation import ugettext_lazy as _ +import requests # from quiz.models import Quiz from sorl.thumbnail import default as sorl_default @@ -387,6 +388,7 @@ class Conference(models.Model): comment = ShortTextField(_('comment'), max_length=255, blank=True) date_begin = models.DateTimeField(_('begin date'), null=True, blank=True) date_end = models.DateTimeField(_('end date'), null=True, blank=True) + date_publish = models.DateTimeField(_('publishing date'), null=True, blank=True) readers = models.ManyToManyField(User, related_name="conference", verbose_name=_('readers'), blank=True) status = models.IntegerField( @@ -394,6 +396,8 @@ class Conference(models.Model): streaming = models.BooleanField(_('streaming'), default=True) # web_class_group = models.ForeignKey('WebClassGroup', related_name='conferences', verbose_name=_('web class group'), # blank=True, null=True, on_delete=models.SET_NULL) + notified = models.BooleanField(_('notified'), default=False) + notified_live = models.BooleanField("Notifié live", default=False) @property def description(self): @@ -430,6 +434,14 @@ class Conference(models.Model): if not self.public_id: self.public_id = get_random_hash() self.course.save() + + if self.streaming and not self.notified_live: + # Notify live conferences by sending a signal to websocket. + # This signal will be catched by the channel instance to notify students + from teleforma.models.notification import notify + requests.post(f"{settings.CHANNEL_URL}{reverse('teleforma-live-conference-notify')}", {'id': self.id}) + self.notified_live = True + super(Conference, self).save(*args, **kwargs) def to_dict(self): -- 2.39.5