diff --git a/src/api/settings.py b/src/api/settings.py
index 88c78fa044..92473e3f1d 100644
--- a/src/api/settings.py
+++ b/src/api/settings.py
@@ -382,3 +382,7 @@
# allow insecure transports for OAUTHLIB in DEBUG mode
if DEBUG:
os.environ.setdefault('OAUTHLIB_INSECURE_TRANSPORT', 'y')
+
+# Get the promo
+PROMO_CODE_KEY = os.environb.get(b'PROMO_CODE_KEY', b'prout')
+PROMO_CODE_TAG = os.environ.get('PROMO_CODE_TAG', 'Groupe certifié')
diff --git a/src/front/templates/front/groups/manage.html b/src/front/templates/front/groups/manage.html
index f7d9db7ab6..8591394ab4 100644
--- a/src/front/templates/front/groups/manage.html
+++ b/src/front/templates/front/groups/manage.html
@@ -33,6 +33,20 @@
Contact
+
+ {% if certified %}
+ Mon code promo pour ce mois-ci
+
+
+ {{ group_promo_code }}
+
+
+
+ Ce code peut être utilisé sur le site d'achat de matériel.
+
+
+ {% endif %}
+
Les animateurs et autres gestionnaires du groupe
Les animateurs du groupe
diff --git a/src/front/views/groups.py b/src/front/views/groups.py
index 42695b93f1..19cb79e8df 100644
--- a/src/front/views/groups.py
+++ b/src/front/views/groups.py
@@ -6,9 +6,11 @@
from django.contrib import messages
from django.http import Http404, HttpResponseForbidden, HttpResponseRedirect, HttpResponseBadRequest
from django.core.urlresolvers import reverse_lazy, reverse
+from django.conf import settings
from groups.models import SupportGroup, Membership
from groups.tasks import send_someone_joined_notification
+from groups.actions.promo_codes import get_next_promo_code
from ..forms import SupportGroupForm, AddReferentForm, AddManagerForm, GroupGeocodingForm
from ..view_mixins import (
@@ -110,17 +112,18 @@ def get_forms(self):
}
def get_context_data(self, **kwargs):
- referents = self.object.memberships.filter(is_referent=True).order_by('created')
- managers = self.object.memberships.filter(is_manager=True, is_referent=False).order_by('created')
- members = self.object.memberships.all().order_by('created')
+ kwargs['referents'] = self.object.memberships.filter(is_referent=True).order_by('created')
+ kwargs['managers'] = self.object.memberships.filter(is_manager=True, is_referent=False).order_by('created')
+ kwargs['members'] = self.object.memberships.all().order_by('created')
+ kwargs['certified'] = self.object.tags.filter(label=settings.PROMO_CODE_TAG).exists()
+ if kwargs['certified']:
+ kwargs['group_promo_code'] = get_next_promo_code(self.object)
return super().get_context_data(
- referents=referents,
- managers=managers,
- members=members,
is_referent=self.user_membership is not None and self.user_membership.is_referent,
is_manager=self.user_membership is not None and (self.user_membership.is_referent or self.user_membership.is_manager),
- **self.get_forms()
+ **self.get_forms(),
+ **kwargs
)
def get(self, request, *args, **kwargs):
diff --git a/src/groups/actions/__init__.py b/src/groups/actions/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/groups/actions/promo_codes.py b/src/groups/actions/promo_codes.py
new file mode 100644
index 0000000000..507e75de30
--- /dev/null
+++ b/src/groups/actions/promo_codes.py
@@ -0,0 +1,95 @@
+import struct
+import base64
+import hmac
+import hashlib
+from datetime import date
+
+from django.conf import settings
+from django.utils import timezone
+
+REFERENCE_DATE = date(2017, 1, 1)
+GROUP_ID_SIZE = 6
+SIGNATURE_SIZE = 6
+DIGESTMOD = hashlib.sha1
+BASE64ENC = base64.urlsafe_b64encode
+
+
+def generate_date_fragment(expiration_date):
+ """Generate a two-character encoding of the expiration date
+
+ That encoding is done that way:
+ * Compute the number of days since the REFERENCE_DATE
+ * encode it as two bytes (low-endian)
+ * left shift the second byte by four bits
+
+ It should now look that way (second hexdigit of second byte is all zero after left shift) :
+ xxxx xxxx xxxx 0000
+ Only twelve bits of data ==> can be encoded by two base64 characters
+
+ * Encode it in base64 and keep the two first characters
+
+ :param expiration_date: a date corresponding to the day the promo code should expire
+ :return: base64 encoding of the input date (bytes object)
+ """
+ days = (expiration_date - REFERENCE_DATE).days
+ assert days < 4096 # 2^12 or the maximum value that can be set in 2 Base64 characters
+
+ # use little-endian for packing
+ b = bytearray(struct.pack('