<commit_before>import json

import ics
from django.conf import settings
from django.template.defaultfilters import floatformat
from django.urls import reverse_lazy, reverse
from django.core.exceptions import PermissionDenied
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Q, Sum
from django.http import (
    Http404,
    HttpResponseRedirect,
    HttpResponseBadRequest,
    JsonResponse,
    HttpResponse,
)
from django.utils.decorators import method_decorator
from django.utils.html import format_html, mark_safe
from django.utils.translation import ugettext as _, ugettext_lazy
from django.views.generic import (
    UpdateView,
    ListView,
    DeleteView,
    DetailView,
    TemplateView,
)
from django.views.generic.edit import ProcessFormView, FormMixin

from agir.groups.models import SupportGroup, Membership, SupportGroupSubtype
from agir.groups.tasks import send_someone_joined_notification
from agir.groups.actions.promo_codes import get_next_promo_code
from agir.lib.utils import front_url

from .forms import (
    SupportGroupForm,
    AddReferentForm,
    AddManagerForm,
    GroupGeocodingForm,
    SearchGroupForm,
)
from agir.front.view_mixins import (
    ObjectOpengraphMixin,
    ChangeLocationBaseView,
    SearchByZipcodeBaseView,
)
from agir.authentication.view_mixins import (
    HardLoginRequiredMixin,
    PermissionsRequiredMixin,
)

__all__ = [
    "SupportGroupManagementView",
    "CreateSupportGroupView",
    "PerformCreateSupportGroupView",
    "ModifySupportGroupView",
    "QuitSupportGroupView",
    "RemoveManagerView",
    "SupportGroupDetailView",
    "ThematicBookletViews",
    "ChangeGroupLocationView",
    "SupportGroupListView",
]


class CheckMembershipMixin:
    def user_is_referent(self):
        return self.user_membership is not None and self.user_membership.is_referent

    def user_is_manager(self):
        return self.user_membership is not None and (
            self.user_membership.is_referent or self.user_membership.is_manager
        )

    @property
    def user_membership(self):
        if not hasattr(self, "_user_membership"):
            if isinstance(self.object, SupportGroup):
                group = self.object
            else:
                group = self.object.supportgroup

            try:
                self._user_membership = group.memberships.get(
                    person=self.request.user.person
                )
            except Membership.DoesNotExist:
                self._user_membership = None

        return self._user_membership


class SupportGroupListView(SearchByZipcodeBaseView):
    """List of groups, filter by zipcode
    """

    min_items = 20
    template_name = "groups/group_list.html"
    context_object_name = "groups"
    form_class = SearchGroupForm

    def get_base_queryset(self):
        return SupportGroup.objects.active().order_by("name")


class SupportGroupDetailView(ObjectOpengraphMixin, DetailView):
    template_name = "groups/detail.html"
    queryset = SupportGroup.objects.active().all()

    title_prefix = "Groupe d'action"
    meta_description = "Rejoignez les groupes d'action de la France insoumise."

    def get_template_names(self):
        return ["groups/detail.html"]

    def get_context_data(self, **kwargs):
        return super().get_context_data(
            is_member=self.request.user.is_authenticated
            and self.object.memberships.filter(
                person=self.request.user.person
            ).exists(),
            is_referent_or_manager=self.request.user.is_authenticated
            and self.object.memberships.filter(
                Q(person=self.request.user.person)
                & (Q(is_referent=True) | Q(is_manager=True))
            ).exists(),
        )

    @method_decorator(login_required(login_url=reverse_lazy("short_code_login")))
    def post(self, request, *args, **kwargs):
        self.object = self.get_object()

        if request.POST["action"] == "join":
            if not self.object.memberships.filter(person=request.user.person).exists():
                membership = Membership.objects.create(
                    supportgroup=self.object, person=request.user.person
                )
                send_someone_joined_notification.delay(membership.pk)
            return HttpResponseRedirect(
                reverse("view_group", kwargs={"pk": self.object.pk})
            )

        return HttpResponseBadRequest()


class SupportGroupIcsView(DetailView):
    queryset = SupportGroup.objects.active().all()

    def render_to_response(self, context, **response_kwargs):
        calendar = ics.Calendar(
            events=[
                ics.event.Event(
                    name=event.name,
                    begin=event.start_time,<commit_msg>Corrige un léger bug (race condition pour rejoindre un groupe)<commit_after>import json

import ics
from django.conf import settings
from django.db import IntegrityError
from django.template.defaultfilters import floatformat
from django.urls import reverse_lazy, reverse
from django.core.exceptions import PermissionDenied
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Q, Sum
from django.http import (
    Http404,
    HttpResponseRedirect,
    HttpResponseBadRequest,
    JsonResponse,
    HttpResponse,
)
from django.utils.decorators import method_decorator
from django.utils.html import format_html, mark_safe
from django.utils.translation import ugettext as _, ugettext_lazy
from django.views.generic import (
    UpdateView,
    ListView,
    DeleteView,
    DetailView,
    TemplateView,
)
from django.views.generic.edit import ProcessFormView, FormMixin

from agir.groups.models import SupportGroup, Membership, SupportGroupSubtype
from agir.groups.tasks import send_someone_joined_notification
from agir.groups.actions.promo_codes import get_next_promo_code
from agir.lib.utils import front_url

from .forms import (
    SupportGroupForm,
    AddReferentForm,
    AddManagerForm,
    GroupGeocodingForm,
    SearchGroupForm,
)
from agir.front.view_mixins import (
    ObjectOpengraphMixin,
    ChangeLocationBaseView,
    SearchByZipcodeBaseView,
)
from agir.authentication.view_mixins import (
    HardLoginRequiredMixin,
    PermissionsRequiredMixin,
)

__all__ = [
    "SupportGroupManagementView",
    "CreateSupportGroupView",
    "PerformCreateSupportGroupView",
    "ModifySupportGroupView",
    "QuitSupportGroupView",
    "RemoveManagerView",
    "SupportGroupDetailView",
    "ThematicBookletViews",
    "ChangeGroupLocationView",
    "SupportGroupListView",
]


class CheckMembershipMixin:
    def user_is_referent(self):
        return self.user_membership is not None and self.user_membership.is_referent

    def user_is_manager(self):
        return self.user_membership is not None and (
            self.user_membership.is_referent or self.user_membership.is_manager
        )

    @property
    def user_membership(self):
        if not hasattr(self, "_user_membership"):
            if isinstance(self.object, SupportGroup):
                group = self.object
            else:
                group = self.object.supportgroup

            try:
                self._user_membership = group.memberships.get(
                    person=self.request.user.person
                )
            except Membership.DoesNotExist:
                self._user_membership = None

        return self._user_membership


class SupportGroupListView(SearchByZipcodeBaseView):
    """List of groups, filter by zipcode
    """

    min_items = 20
    template_name = "groups/group_list.html"
    context_object_name = "groups"
    form_class = SearchGroupForm

    def get_base_queryset(self):
        return SupportGroup.objects.active().order_by("name")


class SupportGroupDetailView(ObjectOpengraphMixin, DetailView):
    template_name = "groups/detail.html"
    queryset = SupportGroup.objects.active().all()

    title_prefix = "Groupe d'action"
    meta_description = "Rejoignez les groupes d'action de la France insoumise."

    def get_template_names(self):
        return ["groups/detail.html"]

    def get_context_data(self, **kwargs):
        return super().get_context_data(
            is_member=self.request.user.is_authenticated
            and self.object.memberships.filter(
                person=self.request.user.person
            ).exists(),
            is_referent_or_manager=self.request.user.is_authenticated
            and self.object.memberships.filter(
                Q(person=self.request.user.person)
                & (Q(is_referent=True) | Q(is_manager=True))
            ).exists(),
        )

    @method_decorator(login_required(login_url=reverse_lazy("short_code_login")))
    def post(self, request, *args, **kwargs):
        self.object = self.get_object()

        if request.POST["action"] == "join":
            try:
                membership = Membership.objects.create(
                    supportgroup=self.object, person=request.user.person
                )
                send_someone_joined_notification.delay(membership.pk)
            except IntegrityError:
                pass  # the person is already a member of the group
            return HttpResponseRedirect(
                reverse("view_group", kwargs={"pk": self.object.pk})
            )

        return HttpResponseBadRequest()


class SupportGroupIcsView(DetailView):
    queryset = SupportGroup.objects.active().all()

    def render_to_response(self, context, **response_kwargs):
        calendar = ics.Calendar(
            events=[
                ics.event.Event(
                    name=event.name,
                    begin=event.start_time,
{'fraction_non_alphanumeric': 0.08086583622626098, 'fraction_numerical': 0.0010210332856851133, 'mean_word_length': 2.9227072486984382, 'pattern_counts': {'":': 4, '<': 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': '4697842', 'n_tokens_mistral': 2800, 'n_tokens_neox': 2704, 'n_words': 552}