From 8769aefeb79b1e948f26f7aedbd95bb345e616e8 Mon Sep 17 00:00:00 2001
From: ThomasBidot <77505438+ThomasBidot@users.noreply.github.com>
Date: Sat, 17 Apr 2021 15:08:35 +0200
Subject: [PATCH] Notifications for Sec-Gen (#36)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Password reset feature (#8)

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* test

* Added utf-8 support to exported csv and switched delimiter from , to ; in admin interface

* Disabled emails while in dev

* Added multi selection filter in admin

* Fixed mail settings

* Added year field to Tutor serializer

* Fixed year updated before registration form filled

* commit for automatic deploy

* Testing CI

* Added filtering in admin for registration validation

* Added filter to student admin

* Added school info

* Fixed typo in filters

* Sorties (#30)

* Custom participation_inline css

* Ordered student profiles by last modification date in admin

* Ajouté infos sorties

* Sortie thomas (#32)

* Updated student admin filters (#28)

* Password reset feature (#8)

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* test

* Added utf-8 support to exported csv and switched delimiter from , to ; in admin interface

* Disabled emails while in dev

* Added multi selection filter in admin

* Fixed mail settings

* Added year field to Tutor serializer

* Fixed year updated before registration form filled

* commit for automatic deploy

* Testing CI

* Added filtering in admin for registration validation

* Added filter to student admin

Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>

* Ajout filtre sur register

* Ajout filtre participation

* Ajout de 3 filtres par etablissements

* Ajout 3 filtres pour etablissement V2

Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>
Co-authored-by: Witeden <58004019+Witeden@users.noreply.github.com>

* Sortie thomas (export CSV sorties) (#33)

* Updated student admin filters (#28)

* Password reset feature (#8)

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* test

* Added utf-8 support to exported csv and switched delimiter from , to ; in admin interface

* Disabled emails while in dev

* Added multi selection filter in admin

* Fixed mail settings

* Added year field to Tutor serializer

* Fixed year updated before registration form filled

* commit for automatic deploy

* Testing CI

* Added filtering in admin for registration validation

* Added filter to student admin

Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>

* Ajout filtre sur register

* Ajout filtre participation

* Ajout de 3 filtres par etablissements

* Ajout 3 filtres pour etablissement V2

* Ajout export CSV sorties

Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>

Co-authored-by: Dylan Sechet <dylan.sechet82@gmail.com>
Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>
Co-authored-by: Witeden <58004019+Witeden@users.noreply.github.com>

* Update runtime.txt

Changement version python

* Ordering students by updated_date

* Notifications for Sec-Gen (#35)

* Custom participation_inline css

* Ajout filtre sur register

* Ajout filtre participation

* Ordered student profiles by last modification date in admin

* Ajouté infos sorties

* Ajout de 3 filtres par etablissements

* Ajout 3 filtres pour etablissement V2

* Sortie thomas (#32)

* Updated student admin filters (#28)

* Password reset feature (#8)

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* test

* Added utf-8 support to exported csv and switched delimiter from , to ; in admin interface

* Disabled emails while in dev

* Added multi selection filter in admin

* Fixed mail settings

* Added year field to Tutor serializer

* Fixed year updated before registration form filled

* commit for automatic deploy

* Testing CI

* Added filtering in admin for registration validation

* Added filter to student admin

Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>

* Ajout filtre sur register

* Ajout filtre participation

* Ajout de 3 filtres par etablissements

* Ajout 3 filtres pour etablissement V2

Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>
Co-authored-by: Witeden <58004019+Witeden@users.noreply.github.com>

* Ajout export CSV sorties

* Sortie thomas (export CSV sorties) (#33)

* Updated student admin filters (#28)

* Password reset feature (#8)

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* Add Django Rest auth module

* Try to make the send reset password email work

* Modified template mail for reset

* test

* Added utf-8 support to exported csv and switched delimiter from , to ; in admin interface

* Disabled emails while in dev

* Added multi selection filter in admin

* Fixed mail settings

* Added year field to Tutor serializer

* Fixed year updated before registration form filled

* commit for automatic deploy

* Testing CI

* Added filtering in admin for registration validation

* Added filter to student admin

Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>

* Ajout filtre sur register

* Ajout filtre participation

* Ajout de 3 filtres par etablissements

* Ajout 3 filtres pour etablissement V2

* Ajout export CSV sorties

Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>

* Erreurs dans visits/admin résolus

* Notifications for Sec-Gen

Co-authored-by: Dylan Sechet <dylan.sechet82@gmail.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>
Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Witeden <58004019+Witeden@users.noreply.github.com>

Co-authored-by: chiahetcho <44137047+chiahetcho@users.noreply.github.com>
Co-authored-by: florimondmanca <florimond.manca@gmail.com>
Co-authored-by: Dylan Sechet <dylan.sechet82@gmail.com>
Co-authored-by: Arthur Guédon <arthur.guedon@student-cs.fr>
Co-authored-by: Arthur Guédon <60623551+arthurgdn@users.noreply.github.com>
Co-authored-by: Seon82 <46298009+Seon82@users.noreply.github.com>
Co-authored-by: Bidot-Naude Thomas <thomas.bidotnaude@student-cs.fr>
Co-authored-by: Witeden <58004019+Witeden@users.noreply.github.com>
---
 oser_backend/settings/common.py |   9 ++
 profiles/admin.py               |  19 ++--
 profiles/models.py              | 165 ++++++++++++++++----------------
 register/admin.py               |  19 ----
 requirements.txt                |   4 +
 visits/admin.py                 |  13 +--
 6 files changed, 115 insertions(+), 114 deletions(-)

diff --git a/oser_backend/settings/common.py b/oser_backend/settings/common.py
index 84ccf82..478aa5e 100644
--- a/oser_backend/settings/common.py
+++ b/oser_backend/settings/common.py
@@ -288,3 +288,12 @@ STATICFILES_DIRS = [
 
 MEDIA_URL = '/media/'
 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
+
+# Telegram bot
+TELEGRAM_BOT_TOKEN = os.getenv(
+    "TELEGRAM_BOT_TOKEN")
+TELEGRAM = {
+    'bot_token': TELEGRAM_BOT_TOKEN,
+    'channel_name': 'oserSECGEN',
+    'production': False,
+}
diff --git a/profiles/admin.py b/profiles/admin.py
index 9c8efa2..b107212 100644
--- a/profiles/admin.py
+++ b/profiles/admin.py
@@ -7,6 +7,8 @@ import codecs
 
 import csv
 from django.http import HttpResponse
+
+
 class ExportCsvMixin:
     def export_as_csv(self, request, queryset):
 
@@ -14,13 +16,15 @@ class ExportCsvMixin:
         field_names = [field.name for field in meta.fields]
 
         response = HttpResponse(content_type='text/csv')
-        response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
-        response.write(codecs.BOM_UTF8) #force response to be UTF-8
+        response['Content-Disposition'] = 'attachment; filename={}.csv'.format(
+            meta)
+        response.write(codecs.BOM_UTF8)  # force response to be UTF-8
         writer = csv.writer(response, delimiter=';')
 
         writer.writerow(field_names)
         for obj in queryset:
-            row = writer.writerow([getattr(obj, field) for field in field_names])
+            row = writer.writerow([getattr(obj, field)
+                                   for field in field_names])
 
         return response
 
@@ -33,8 +37,9 @@ class ProfileAdminMixin:
     search_fields = ('user__email', 'user__first_name', 'user__last_name',)
     actions = ["export_as_csv"]
 
+
 @admin.register(Tutor)
-class TutorAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
+class TutorAdmin(ProfileAdminMixin, admin.ModelAdmin, ExportCsvMixin):
     """Tutor admin panel."""
 
     autocomplete_fields = ('address',)
@@ -45,9 +50,11 @@ class TutorAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
 
 
 @admin.register(Student)
-class StudentAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
+class StudentAdmin(ProfileAdminMixin, admin.ModelAdmin, ExportCsvMixin):
     """Student admin panel."""
-    list_filter = (('school',MultiSelectFieldListFilter), 'year', 'registration__validated')
+    list_filter = (('school', MultiSelectFieldListFilter),
+                   'year', 'registration__validated')
+
     class Meta:  # noqa
         model = Student
     ordering = ['-updated_date']
diff --git a/profiles/models.py b/profiles/models.py
index 4c9d912..39f3925 100644
--- a/profiles/models.py
+++ b/profiles/models.py
@@ -7,6 +7,10 @@ from .utils import get_promotion_range
 from datetime import datetime
 from .notifications import SendDocs
 
+import telegram
+from django.conf import settings
+from django.template.loader import render_to_string
+
 
 class ProfileMixin:
     """Mixin with common functionnality for profiles."""
@@ -57,35 +61,34 @@ class Student(ProfileMixin, models.Model):
     )
 
     classType = models.CharField(max_length=50,
-        null=True,
-        blank=True,
-        verbose_name="général/techno",
-    )
+                                 null=True,
+                                 blank=True,
+                                 verbose_name="général/techno",
+                                 )
 
     nationality = models.CharField(max_length=50,
-        null=True,
-        blank=True,
-        verbose_name="nationalité",
-    )
+                                   null=True,
+                                   blank=True,
+                                   verbose_name="nationalité",
+                                   )
 
     specialTeaching = models.CharField(max_length=50,
-        null=True,
-        blank=True,
-        verbose_name="enseignement de spécialité",
-    )
+                                       null=True,
+                                       blank=True,
+                                       verbose_name="enseignement de spécialité",
+                                       )
 
     zipCode = models.CharField(max_length=10,
-        null=True,
-        blank=True,
-        verbose_name="code postal",
-    )
-
+                               null=True,
+                               blank=True,
+                               verbose_name="code postal",
+                               )
 
     gender = models.CharField(max_length=20,
-        null=True,
-        blank=True,
-        verbose_name="genre",
-    )
+                              null=True,
+                              blank=True,
+                              verbose_name="genre",
+                              )
 
     addressNumber = models.IntegerField(
         null=True,
@@ -94,77 +97,70 @@ class Student(ProfileMixin, models.Model):
     )
 
     street = models.CharField(max_length=70,
-        null=True,
-        blank=True,
-        verbose_name="nom de rue"
-    )
+                              null=True,
+                              blank=True,
+                              verbose_name="nom de rue"
+                              )
 
     city = models.CharField(max_length=50,
-        null=True,
-        blank=True,
-        verbose_name="nom de ville"
-    )
+                            null=True,
+                            blank=True,
+                            verbose_name="nom de ville"
+                            )
 
     personalPhone = models.CharField(max_length=12,
-        null=True,
-        blank=True,
-        verbose_name="numéro de téléphone personnel"
-    )
+                                     null=True,
+                                     blank=True,
+                                     verbose_name="numéro de téléphone personnel"
+                                     )
 
     parentsPhone = models.CharField(max_length=12,
-        null=True,
-        blank=True,
-        verbose_name="numéro de téléphone parental"
-    )
+                                    null=True,
+                                    blank=True,
+                                    verbose_name="numéro de téléphone parental"
+                                    )
 
     parentsEmail = models.EmailField(max_length=70,
-        null=True,
-        blank=True,
-        verbose_name="adresse mail parentale"
-    )
-
+                                     null=True,
+                                     blank=True,
+                                     verbose_name="adresse mail parentale"
+                                     )
 
     school = models.CharField(max_length=70,
-        null=True,
-        blank=True,
-        verbose_name="établissement"
-    )
-
+                              null=True,
+                              blank=True,
+                              verbose_name="établissement"
+                              )
 
     grade = models.CharField(max_length=20,
-        null=True,
-        blank=True,
-        verbose_name="niveau de la classe"
-    )
-
+                             null=True,
+                             blank=True,
+                             verbose_name="niveau de la classe"
+                             )
 
     scholarship = models.CharField(max_length=50,
-        null=True,
-        blank=True,
-        verbose_name="boursier"
-    )
-
+                                   null=True,
+                                   blank=True,
+                                   verbose_name="boursier"
+                                   )
 
     fatherActivity = models.CharField(max_length=70,
-        null=True,
-        blank=True,
-        verbose_name="métier du père"
-    )
-
+                                      null=True,
+                                      blank=True,
+                                      verbose_name="métier du père"
+                                      )
 
     motherActivity = models.CharField(max_length=70,
-        null=True,
-        blank=True,
-        verbose_name="métier de la mère"
-    )
-
+                                      null=True,
+                                      blank=True,
+                                      verbose_name="métier de la mère"
+                                      )
 
     parentsStatus = models.CharField(max_length=70,
-        null=True,
-        blank=True,
-        verbose_name="statut des parents"
-    )
-
+                                     null=True,
+                                     blank=True,
+                                     verbose_name="statut des parents"
+                                     )
 
     dependantsNumber = models.IntegerField(
         null=True,
@@ -173,10 +169,10 @@ class Student(ProfileMixin, models.Model):
     )
 
     year = models.CharField(max_length=10,
-        null=True,
-        blank=True,
-        verbose_name="année"
-    )
+                            null=True,
+                            blank=True,
+                            verbose_name="année"
+                            )
 
     @staticmethod
     def has_write_permission(request):
@@ -187,16 +183,25 @@ class Student(ProfileMixin, models.Model):
 
     def save(self, *args, **kwargs):
         """Updates the year field based on the last modified date"""
-        if self.city != None: # Ne mettre à jour que quand les données personnelles sont remplies
+        if self.city != None:  # Ne mettre à jour que quand les données personnelles sont remplies
             date_now = datetime.now()
-            if date_now.month>=9:
+            if date_now.month >= 9:
                 self.year = f"{date_now.year}/{date_now.year+1}"
             else:
                 self.year = f"{date_now.year-1}/{date_now.year}"
 
-            SendDocs(user=self.user).send() # send email with link to registration docs
+            # send email with link to registration docs
+            SendDocs(user=self.user).send()
+
+            # send a telegram message to oserSECGEN
+            telegram_settings = settings.TELEGRAM
+            if telegram_settings['bot_token'] != None:
+                message_telegram = "Un tutoré a renseigné ses données personnelles, il attend ta validation !"
+                bot = telegram.Bot(token=telegram_settings['bot_token'])
+                bot.send_message(
+                    chat_id="@%s" % telegram_settings['channel_name'], text=message_telegram, parse_mode=telegram.ParseMode.HTML)
 
-        return super(Student,self).save(*args, **kwargs)
+        return super(Student, self).save(*args, **kwargs)
 
     class Meta:  # noqa
         verbose_name = 'lycéen'
diff --git a/register/admin.py b/register/admin.py
index 482cba4..95a4138 100644
--- a/register/admin.py
+++ b/register/admin.py
@@ -5,25 +5,6 @@ from .models import Registration
 from profiles.models import Student
 
 
-class SchoolFilter(admin.SimpleListFilter):
-    title = 'établissement'
-    parameter_name = 'profiles__school'
-
-    def lookups(self, request, model_admin):
-        list_of_school = []
-        query = Student.objects.values_list(
-            "school", flat=True).distinct()
-        for school in query:
-            list_of_school.append((school, school))
-        return list_of_school
-
-    def queryset(self, request, queryset):
-        if self.value():
-            emails = Student.objects.filter(
-                school=self.value()).values_list("user__email", flat=True)
-            return queryset.filter(email__in=emails)
-
-
 class SchoolFilter(admin.SimpleListFilter):
     title = 'établissement'
     parameter_name = 'profiles__school'
diff --git a/requirements.txt b/requirements.txt
index 85baa93..e1b2a84 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,6 +12,10 @@ django-sendgrid-v5
 django-filter
 django-rest-auth
 
+# Telegram messages via python-telegram-bot
+tornado==5.1.1 
+python-telegram-bot==12.2.0
+
 # Storage of files in AWS S3
 django-storages
 boto3
diff --git a/visits/admin.py b/visits/admin.py
index 7d49e11..6ca578e 100644
--- a/visits/admin.py
+++ b/visits/admin.py
@@ -110,13 +110,11 @@ class ParticipationInline(admin.TabularInline):
         school = Student.objects.get(user = participation.user).school
         return school
     school.short_description = "Établissement"
-
     def name(self, participation: Participation):
         """Returns the participation's user's name"""
         return participation.user.first_name + " " + participation.user.last_name
     name.short_description = "Nom"
 
-
     class Media:
         css = { "all" : ("css/hide_admin_original.css",) }
 
@@ -171,11 +169,10 @@ class ParticipationAdmin(admin.ModelAdmin):
 
     def school(self, participation: Participation):
         """Return a link to the participation's user's school."""
-        school = Student.objects.get(user = participation.user).school
+        school = Student.objects.get(user=participation.user).school
         return school
     school.short_description = "Établissement"
 
-
     def export_as_csv(self, request, queryset):
         meta = self.model._meta
         field_names = [field.name for field in meta.fields]
@@ -205,8 +202,7 @@ class ParticipationAdmin(admin.ModelAdmin):
     export_as_csv.short_description = "Exporter sélection (en .csv)"
 
 
-
-@admin.register(Visit.organizers.through)
+@ admin.register(Visit.organizers.through)
 class VisitOrganizersAdmin(admin.ModelAdmin):
     """Admin panel for visit organizers."""
 
@@ -220,7 +216,7 @@ class OrganizersInline(admin.TabularInline):
     extra = 0
 
 
-@admin.register(Visit)
+@ admin.register(Visit)
 class VisitAdmin(admin.ModelAdmin):
     """Admin panel for visits."""
 
@@ -239,8 +235,7 @@ class VisitAdmin(admin.ModelAdmin):
         return obj.participants.count()
     num_participants.short_description = 'Participants'
 
-    
-@admin.register(Place)
+@ admin.register(Place)
 class PlaceAdmin(admin.ModelAdmin):
     """Admin panel for places."""
 
-- 
GitLab