From 018ca84e2d2a558d3d4a687c6a882e308db9f7b2 Mon Sep 17 00:00:00 2001
From: Yohann D'ANELLO <yohann.danello@gmail.com>
Date: Wed, 5 Aug 2020 20:40:30 +0200
Subject: [PATCH] Prevent superusers when they make a transaction with a
 non-member user

---
 apps/note/api/serializers.py     | 19 ++++++++++++++++++-
 apps/note/models/transactions.py |  3 ++-
 static/js/base.js                |  5 ++++-
 static/js/consos.js              |  3 +++
 static/js/transfer.js            | 24 ++++++++++++++++++------
 5 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py
index 99ee2cc1..b4fceeda 100644
--- a/apps/note/api/serializers.py
+++ b/apps/note/api/serializers.py
@@ -1,8 +1,12 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
-
+from django.utils import timezone
 from rest_framework import serializers
+from rest_framework.serializers import ListSerializer
 from rest_polymorphic.serializers import PolymorphicSerializer
+
+from member.api.serializers import MembershipSerializer
+from member.models import Membership
 from note_kfet.middlewares import get_current_authenticated_user
 from permission.backends import PermissionBackend
 from rest_framework.utils import model_meta
@@ -109,6 +113,8 @@ class ConsumerSerializer(serializers.ModelSerializer):
 
     email_confirmed = serializers.SerializerMethodField()
 
+    membership = serializers.SerializerMethodField()
+
     class Meta:
         model = Alias
         fields = '__all__'
@@ -127,6 +133,17 @@ class ConsumerSerializer(serializers.ModelSerializer):
             return obj.note.user.profile.email_confirmed
         return True
 
+    def get_membership(self, obj):
+        if isinstance(obj.note, NoteUser):
+            memberships = Membership.objects.filter(
+                PermissionBackend.filter_queryset(get_current_authenticated_user(), Membership, "view")).filter(
+                user=obj.note.user,
+                club=2,  # Kfet
+            ).order_by("-date_start")
+            if memberships.exists():
+                return MembershipSerializer().to_representation(memberships.first())
+        return None
+
 
 class TemplateCategorySerializer(serializers.ModelSerializer):
     """
diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py
index 3d7aeb58..6a5d4680 100644
--- a/apps/note/models/transactions.py
+++ b/apps/note/models/transactions.py
@@ -202,7 +202,8 @@ class Transaction(PolymorphicModel):
         When saving, also transfer money between two notes
         """
         with transaction.atomic():
-            self.refresh_from_db()
+            if self.pk:
+                self.refresh_from_db()
             self.source.refresh_from_db()
             self.destination.refresh_from_db()
             self.validate(False)
diff --git a/static/js/base.js b/static/js/base.js
index 52fce901..5400bf5d 100644
--- a/static/js/base.js
+++ b/static/js/base.js
@@ -105,8 +105,10 @@ function displayStyle(note) {
         css += " text-danger";
     else if (balance < 0)
         css += " text-warning";
-    if (!note.email_confirmed)
+    else if (!note.email_confirmed)
         css += " text-white bg-primary";
+    else if (note.membership && note.membership.date_end < new Date().toISOString())
+        css += "text-white bg-info";
     return css;
 }
 
@@ -263,6 +265,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
                 consumers.results.forEach(function (consumer) {
                     let note = consumer.note;
                     note.email_confirmed = consumer.email_confirmed;
+                    note.membership = consumer.membership;
                     let extra_css = displayStyle(note);
                     aliases_matched_html += li(alias_prefix + '_' + consumer.id,
                         consumer.name,
diff --git a/static/js/consos.js b/static/js/consos.js
index cb6b730f..a953eee3 100644
--- a/static/js/consos.js
+++ b/static/js/consos.js
@@ -218,6 +218,9 @@ function consume(source, source_alias, dest, quantity, amount, reason, type, cat
                     addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " +
                         "succès, mais la note émettrice " + source_alias + " est en négatif.",
                         "warning", 30000);
+                if (source.note.membership && source.note.membership.date_end > new Date().toISOString())
+                    addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.",
+                        "danger", 30000);
             }
             reset();
         }).fail(function (e) {
diff --git a/static/js/transfer.js b/static/js/transfer.js
index 88368a27..6e2f183c 100644
--- a/static/js/transfer.js
+++ b/static/js/transfer.js
@@ -260,6 +260,13 @@ $("#btn_transfer").click(function() {
                         "destination": dest.note.id,
                         "destination_alias": dest.name
                     }).done(function () {
+                        if (source.note.membership && source.note.membership.date_end > new Date().toISOString())
+                            addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.",
+                                "danger", 30000);
+                        if (dest.note.membership && dest.note.membership.date_end > new Date().toISOString())
+                            addMsg("Attention : la note destination " + dest.name + " n'est plus adhérente.",
+                                "danger", 30000);
+
                         if (!isNaN(source.note.balance)) {
                             let newBalance = source.note.balance - source.quantity * dest.quantity * amount;
                             if (newBalance <= -5000) {
@@ -327,19 +334,22 @@ $("#btn_transfer").click(function() {
     } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
         let special_note = $("#credit_type").val();
         let user_note;
+        let alias;
         let given_reason = reason;
         let source_id, dest_id;
         if ($("#type_credit").is(':checked')) {
-            user_note = dests_notes_display[0].note.id;
+            user_note = dests_notes_display[0].note;
+            alias = dests_notes_display[0].name;
             source_id = special_note;
-            dest_id = user_note;
+            dest_id = user_note.id;
             reason = "Crédit " + $("#credit_type option:selected").text().toLowerCase();
             if (given_reason.length > 0)
                 reason += " (" + given_reason + ")";
         }
         else {
-            user_note = sources_notes_display[0].note.id;
-            source_id = user_note;
+            user_note = sources_notes_display[0].note;
+            alias = sources_notes_display[0].name;
+            source_id = user_note.id;
             dest_id = special_note;
             reason = "Retrait " + $("#credit_type option:selected").text().toLowerCase();
             if (given_reason.length > 0)
@@ -355,14 +365,16 @@ $("#btn_transfer").click(function() {
                 "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
                 "resourcetype": "SpecialTransaction",
                 "source": source_id,
-                "source_alias": sources_notes_display.length ? sources_notes_display[0].name : null,
+                "source_alias": sources_notes_display.length ? alias : null,
                 "destination": dest_id,
-                "destination_alias": dests_notes_display.length ? dests_notes_display[0].name : null,
+                "destination_alias": dests_notes_display.length ? alias : null,
                 "last_name": $("#last_name").val(),
                 "first_name": $("#first_name").val(),
                 "bank": $("#bank").val()
             }).done(function () {
                 addMsg("Le crédit/retrait a bien été effectué !", "success", 10000);
+                if (user_note.membership && user_note.membership.date_end > new Date().toISOString())
+                    addMsg("Attention : la note " + alias +  " n'est plus adhérente.", "danger", 10000);
                 reset();
             }).fail(function (err) {
                 let errObj = JSON.parse(err.responseText);
-- 
GitLab