<commit_before>import crypt
import json
import hmac

from django.conf import settings
from django.contrib import messages
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
from django.shortcuts import render
from django.views.generic.base import RedirectView, TemplateView, View

from oidc_provider.models import UserConsent, Client

from xorgauth.forms import PasswordChangeForm, PasswordResetForm, SetPasswordForm

from .models import User


@login_required
def list_consents(request):
    # if a revoke request was done, process it
    revoke = request.POST.get('revoke', None)
    if revoke is not None:
        consent = UserConsent.objects.filter(user=request.user, client__client_id=revoke)
        if consent:
            revoked_client = consent[0].client
            consent[0].delete()
            messages.success(request, "Successfully revoked consent for client \"{}\"".format(revoked_client.name))
        else:
            client = Client.objects.filter(client_id=revoke)
            if client:
                messages.error(request, "You have no consent for client \"{}\".".format(client[0].name))
            else:
                messages.error(request, "Unknown client.")
    # render the result
    consents = UserConsent.objects.filter(user=request.user)
    return render(request, 'list_consents.html', {
        'consents': consents
    })


class IndexView(LoginRequiredMixin, RedirectView):
    pattern_name = 'profile'


class ProfileView(LoginRequiredMixin, TemplateView):
    template_name = 'profile.html'

    def user_has_consents(self):
        """Return true if the logged user has any consent"""
        return UserConsent.objects.filter(user=self.request.user).exists()

    def user_xorg_email(self):
        """Return an email address managed by Polytechnique.org if the user is an alumni"""
        user = self.request.user
        return user.main_email if user.is_x_alumni() else None


class SyncAxData(View):
    def post(self, request, *args, **kwargs):
        """Receive some data for syncing"""
        # Do not do anything if no secret has been defined
        if not settings.AX_SYNC_SECRET_CRYPT:
            raise Http404("AX sync has not been configured")

        try:
            data = json.loads(request.body.decode('ascii'))
        except ValueError:
            return HttpResponseBadRequest("Unable to load request")

        # data['secret'] is a password for authenticating the data provider
        digest = crypt.crypt(data.get('secret'), settings.AX_SYNC_SECRET_CRYPT)
        if not hmac.compare_digest(digest, settings.AX_SYNC_SECRET_CRYPT):
            return HttpResponseForbidden("Unauthenticated")

        # Mapping from User model to value in JSON request
        field_mapping = (
            ('alumnforce_id', 'af_id'),
            ('ax_contributor', 'ax_contributor'),
            ('axjr_subscriber', 'axjr_subscribed'),
            ('ax_last_synced', 'last_updated'),
        )
        try:
            for account_data in data['data']:
                try:
                    user = User.objects.get(hrid=account_data['xorg_id'])
                except User.DoesNotExist:
                    # Silently skip users that do not exist
                    # If they are created, they will be synced the next time a
                    # synchronisation request is sent to xorgauth.
                    continue

                # Change the account and commit the object only if there were some changes
                changed = False
                for model_field, json_field in field_mapping:<commit_msg>Make AX sync API work in real life<commit_after>import crypt
import json

from django.conf import settings
from django.contrib import messages
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
from django.shortcuts import render
from django.utils.crypto import constant_time_compare
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.base import RedirectView, TemplateView, View

from oidc_provider.models import UserConsent, Client

from xorgauth.forms import PasswordChangeForm, PasswordResetForm, SetPasswordForm

from .models import User


@login_required
def list_consents(request):
    # if a revoke request was done, process it
    revoke = request.POST.get('revoke', None)
    if revoke is not None:
        consent = UserConsent.objects.filter(user=request.user, client__client_id=revoke)
        if consent:
            revoked_client = consent[0].client
            consent[0].delete()
            messages.success(request, "Successfully revoked consent for client \"{}\"".format(revoked_client.name))
        else:
            client = Client.objects.filter(client_id=revoke)
            if client:
                messages.error(request, "You have no consent for client \"{}\".".format(client[0].name))
            else:
                messages.error(request, "Unknown client.")
    # render the result
    consents = UserConsent.objects.filter(user=request.user)
    return render(request, 'list_consents.html', {
        'consents': consents
    })


class IndexView(LoginRequiredMixin, RedirectView):
    pattern_name = 'profile'


class ProfileView(LoginRequiredMixin, TemplateView):
    template_name = 'profile.html'

    def user_has_consents(self):
        """Return true if the logged user has any consent"""
        return UserConsent.objects.filter(user=self.request.user).exists()

    def user_xorg_email(self):
        """Return an email address managed by Polytechnique.org if the user is an alumni"""
        user = self.request.user
        return user.main_email if user.is_x_alumni() else None


@method_decorator(csrf_exempt, name='dispatch')
class SyncAxData(View):
    def post(self, request, *args, **kwargs):
        """Receive some data for syncing"""
        # Do not do anything if no secret has been defined
        if not settings.AX_SYNC_SECRET_CRYPT:
            raise Http404("AX sync has not been configured")

        try:
            data = json.loads(request.body.decode('ascii'))
        except ValueError:
            return HttpResponseBadRequest("Unable to load request")

        # data['secret'] is a password for authenticating the data provider
        digest = crypt.crypt(data.get('secret', ''), settings.AX_SYNC_SECRET_CRYPT)
        if not constant_time_compare(digest, settings.AX_SYNC_SECRET_CRYPT):
            return HttpResponseForbidden("Unauthenticated")

        # Mapping from User model to value in JSON request
        field_mapping = (
            ('alumnforce_id', 'af_id'),
            ('ax_contributor', 'ax_contributor'),
            ('axjr_subscriber', 'axjr_subscribed'),
            ('ax_last_synced', 'last_updated'),
        )
        try:
            for account_data in data['data']:
                try:
                    user = User.objects.get(hrid=account_data['xorg_id'])
                except User.DoesNotExist:
                    # Silently skip users that do not exist
                    # If they are created, they will be synced the next time a
                    # synchronisation request is sent to xorgauth.
                    continue

                # Change the account and commit the object only if there were some changes
                changed = False
                for model_field, json_field in field_mapping:
{'fraction_non_alphanumeric': 0.08293869192371688, 'fraction_numerical': 0.00230385255343658, 'mean_word_length': 2.7803580067731013, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2821630', 'n_tokens_mistral': 2137, 'n_tokens_neox': 2053, 'n_words': 620}