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('