Aller au contenu

Views

ClubAddMemberForm(*args, club, request_user, **kwargs)

Bases: ClubMemberForm

Form to add a member to the club, as a board member.

Source code in club/forms.py
def __init__(self, *args, club: Club, request_user: User, **kwargs):
    self.club = club
    self.request_user = request_user
    self.request_user_membership = self.club.get_membership_for(self.request_user)
    super().__init__(*args, **kwargs)
    self.fields["role"].required = True
    self.fields["role"].choices = [
        (value, name)
        for value, name in settings.SITH_CLUB_ROLES.items()
        if value <= self.max_available_role
    ]
    self.instance.club = club

max_available_role()

The greatest role that will be obtainable with this form.

Admins and the club president can attribute any role. Board members can attribute roles lower than their own. Other users cannot attribute roles with this form

Source code in club/forms.py
@cached_property
def max_available_role(self):
    """The greatest role that will be obtainable with this form.

    Admins and the club president can attribute any role.
    Board members can attribute roles lower than their own.
    Other users cannot attribute roles with this form
    """
    if self.request_user.has_perm("club.add_subscription"):
        return settings.SITH_CLUB_ROLES_ID["President"]
    membership = self.request_user_membership
    if membership is None or membership.role <= settings.SITH_MAXIMUM_FREE_ROLE:
        return -1
    if membership.role == settings.SITH_CLUB_ROLES_ID["President"]:
        return membership.role
    return membership.role - 1

clean_user()

Check that the user is not trying to add a user already in the club.

Also check that the user is valid and has a valid subscription.

Source code in club/forms.py
def clean_user(self):
    """Check that the user is not trying to add a user already in the club.

    Also check that the user is valid and has a valid subscription.
    """
    user = self.cleaned_data["user"]
    if not user.is_subscribed:
        raise forms.ValidationError(
            _("User must be subscriber to take part to a club"), code="invalid"
        )
    if self.club.get_membership_for(user):
        raise forms.ValidationError(
            _("You can not add the same user twice"), code="invalid"
        )
    return user

ClubAdminEditForm

Bases: ClubEditForm

ClubEditForm

Bases: ModelForm

ClubOldMemberForm(*args, user, club, **kwargs)

Bases: Form

Source code in club/forms.py
def __init__(self, *args, user: User, club: Club, **kwargs):
    super().__init__(*args, **kwargs)
    self.fields["members_old"].queryset = (
        Membership.objects.ongoing().filter(club=club).editable_by(user)
    )

JoinClubForm(*args, club, request_user, **kwargs)

Bases: ClubMemberForm

Form to join a club.

Source code in club/forms.py
def __init__(self, *args, club: Club, request_user: User, **kwargs):
    super().__init__(*args, club=club, request_user=request_user, **kwargs)
    # this form doesn't manage the user who will join the club,
    # so we must set this here to avoid errors
    self.instance.user = self.request_user

clean()

Check that the user is subscribed and isn't already in the club.

Source code in club/forms.py
def clean(self):
    """Check that the user is subscribed and isn't already in the club."""
    if not self.request_user.is_subscribed:
        raise forms.ValidationError(
            _("You must be subscribed to join a club"), code="invalid"
        )
    if self.club.get_membership_for(self.request_user):
        raise forms.ValidationError(
            _("You are already a member of this club"), code="invalid"
        )
    return super().clean()

MailingForm(club_id, user_id, mailings, *args, **kwargs)

Bases: Form

Form handling mailing lists right.

Source code in club/forms.py
def __init__(self, club_id, user_id, mailings, *args, **kwargs):
    super().__init__(*args, **kwargs)

    self.fields["action"] = forms.TypedChoiceField(
        choices=(
            (self.ACTION_NEW_MAILING, _("New Mailing")),
            (self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")),
            (self.ACTION_REMOVE_SUBSCRIPTION, _("Remove")),
        ),
        coerce=int,
        label=_("Action"),
        initial=1,
        required=True,
        widget=forms.HiddenInput(),
    )

    # Generate bulk removal forms, they are never required
    for mailing in mailings:
        self.fields["removal_" + str(mailing.id)] = forms.ModelMultipleChoiceField(
            mailing.subscriptions.all(),
            label=_("Remove"),
            required=False,
            widget=forms.CheckboxSelectMultiple,
        )

    # Include fields for handling mailing creation
    mailing_fields = ("email",)
    self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields))
    for field in mailing_fields:
        self.fields["mailing_" + field] = self.fields.pop(field)
        self.fields["mailing_" + field].required = False

    # Include fields for handling subscription creation
    subscription_fields = ("mailing", "email")
    self.fields.update(
        forms.fields_for_model(MailingSubscription, fields=subscription_fields)
    )
    for field in subscription_fields:
        self.fields["subscription_" + field] = self.fields.pop(field)
        self.fields["subscription_" + field].required = False

    self.fields["subscription_mailing"].queryset = Mailing.objects.filter(
        club__id=club_id, is_moderated=True
    )

check_required(cleaned_data, field)

If the given field doesn't exist or has no value, add a required error on it.

Source code in club/forms.py
def check_required(self, cleaned_data, field):
    """If the given field doesn't exist or has no value, add a required error on it."""
    if not cleaned_data.get(field, None):
        self.add_error(field, _("This field is required"))

clean_subscription_users()

Convert given users into real users and check their validity.

Source code in club/forms.py
def clean_subscription_users(self):
    """Convert given users into real users and check their validity."""
    cleaned_data = super().clean()
    users = []
    for user in cleaned_data["subscription_users"]:
        if not user.email:
            raise forms.ValidationError(
                _("One of the selected users doesn't have an email address"),
                code="invalid",
            )
        users.append(user)
    return users

SellingsForm(club, *args, **kwargs)

Bases: Form

Source code in club/forms.py
def __init__(self, club, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # postgres struggles really hard with a single query having three WHERE conditions,
    # but deals perfectly fine with UNION of multiple queryset with their own WHERE clause,
    # so we do this to get the ids, which we use to build another queryset that can be used by django.
    club_sales_subquery = Selling.objects.filter(counter=OuterRef("pk"), club=club)
    ids = (
        Counter.objects.filter(Q(club=club) | Q(products__club=club))
        .union(Counter.objects.filter(Exists(club_sales_subquery)))
        .values_list("id", flat=True)
    )
    counters_qs = Counter.objects.filter(id__in=ids).order_by(Lower("name"))
    self.fields["counters"] = forms.ModelMultipleChoiceField(
        counters_qs, label=_("Counter"), required=False
    )
    self.fields["products"] = forms.ModelMultipleChoiceField(
        club.products.order_by("name").filter(archived=False).all(),
        label=_("Products"),
        required=False,
    )
    self.fields["archived_products"] = forms.ModelMultipleChoiceField(
        club.products.order_by("name").filter(archived=True).all(),
        label=_("Archived products"),
        required=False,
    )

Club

Bases: Model

The Club class, made as a tree to allow nice tidy organization.

president()

Fetch the membership of the current president of this club.

Source code in club/models.py
@cached_property
def president(self) -> Membership | None:
    """Fetch the membership of the current president of this club."""
    return self.members.filter(
        role=settings.SITH_CLUB_ROLES_ID["President"], end_date=None
    ).first()

check_loop()

Raise a validation error when a loop is found within the parent list.

Source code in club/models.py
def check_loop(self):
    """Raise a validation error when a loop is found within the parent list."""
    objs = []
    cur = self
    while cur.parent is not None:
        if cur in objs:
            raise ValidationError(_("You can not make loops in clubs"))
        objs.append(cur)
        cur = cur.parent

is_owned_by(user)

Method to see if that object can be super edited by the given user.

Source code in club/models.py
def is_owned_by(self, user: User) -> bool:
    """Method to see if that object can be super edited by the given user."""
    if user.is_anonymous:
        return False
    return user.is_root or user.is_board_member

can_be_edited_by(user)

Method to see if that object can be edited by the given user.

Source code in club/models.py
def can_be_edited_by(self, user: User) -> bool:
    """Method to see if that object can be edited by the given user."""
    return self.has_rights_in_club(user)

get_membership_for(user)

Return the current membership the given user.

Note

The result is cached.

Source code in club/models.py
def get_membership_for(self, user: User) -> Membership | None:
    """Return the current membership the given user.

    Note:
        The result is cached.
    """
    if user.is_anonymous:
        return None
    membership = cache.get(f"membership_{self.id}_{user.id}")
    if membership == "not_member":
        return None
    if membership is None:
        membership = self.members.filter(user=user, end_date=None).first()
        if membership is None:
            cache.set(f"membership_{self.id}_{user.id}", "not_member")
        else:
            cache.set(f"membership_{self.id}_{user.id}", membership)
    return membership

Mailing

Bases: Model

A Mailing list for a club.

Warning

Remember that mailing lists should be validated by UTBM.

MailingSubscription

Bases: Model

Link between user and mailing list.

Membership

Bases: Model

The Membership class makes the connection between User and Clubs.

Both Users and Clubs can have many Membership objects
  • a user can be a member of many clubs at a time
  • a club can have many members at a time too

A User is currently member of all the Clubs where its Membership has an end_date set to null/None. Otherwise, it's a past membership kept because it can be very useful to see who was in which Club in the past.

is_owned_by(user)

Method to see if that object can be super edited by the given user.

Source code in club/models.py
def is_owned_by(self, user: User) -> bool:
    """Method to see if that object can be super edited by the given user."""
    if user.is_anonymous:
        return False
    return user.is_root or user.is_board_member

can_be_edited_by(user)

Check if that object can be edited by the given user.

Source code in club/models.py
def can_be_edited_by(self, user: User) -> bool:
    """Check if that object can be edited by the given user."""
    if user.is_root or user.is_board_member:
        return True
    membership = self.club.get_membership_for(user)
    return membership is not None and membership.role >= self.role

ClubTabsMixin

ClubListView

Bases: ListView

List the Clubs.

ClubView

Bases: ClubTabsMixin, DetailView

Front page of a Club.

ClubRevView

Bases: ClubView

Display a specific page revision.

ClubPageEditView

ClubPageHistView

Bases: ClubTabsMixin, PermissionRequiredMixin, DetailView

Modification hostory of the page.

ClubToolsView

Bases: ClubTabsMixin, CanEditMixin, DetailView

Tools page of a Club.

ClubAddMembersFragment

Bases: FragmentMixin, PermissionRequiredMixin, SuccessMessageMixin, CreateView

ClubMembersView

Bases: ClubTabsMixin, UseFragmentsMixin, PermissionRequiredMixin, DetailFormView

View of a club's members.

ClubOldMembersView

Bases: ClubTabsMixin, PermissionRequiredMixin, DetailView

Old members of a club.

ClubSellingView

Bases: ClubTabsMixin, CanEditMixin, DetailFormView

Sellings of a club.

ClubSellingCSVView

Bases: ClubSellingView

Generate sellings in csv for a given period.

StreamWriter

Implements a file-like interface for streaming the CSV.

write(value)

Write the value by returning it, instead of storing in a buffer.

Source code in club/views.py
def write(self, value):
    """Write the value by returning it, instead of storing in a buffer."""
    return value

ClubEditView

Bases: ClubTabsMixin, CanEditMixin, UpdateView

Edit a Club.

Regular club board members will be able to edit the main infos (like the logo and the description). Admins will also be able to edit the club properties (like the name and the parent club).

ClubCreateView

Bases: PermissionRequiredMixin, CreateView

Create a club (for the Sith admin).

MembershipSetOldView

Bases: CanEditMixin, DetailView

Set a membership as beeing old.

MembershipDeleteView

Bases: PermissionRequiredMixin, DeleteView

Delete a membership (for admins only).

ClubMailingView

Bases: ClubTabsMixin, CanEditMixin, DetailFormView

A list of mailing for a given club.

add_new_mailing(cleaned_data)

Create a new mailing list from the form.

Source code in club/views.py
def add_new_mailing(self, cleaned_data) -> ValidationError | None:
    """Create a new mailing list from the form."""
    mailing = Mailing(
        club=self.object,
        email=cleaned_data["mailing_email"],
        moderator=self.request.user,
        is_moderated=False,
    )
    try:
        mailing.clean()
    except ValidationError as validation_error:
        return validation_error
    mailing.save()
    return None

add_new_subscription(cleaned_data)

Add mailing subscriptions for each user given and/or for the specified email in form.

Source code in club/views.py
def add_new_subscription(self, cleaned_data) -> ValidationError | None:
    """Add mailing subscriptions for each user given and/or for the specified email in form."""
    users_to_save = []

    for user in cleaned_data["subscription_users"]:
        sub = MailingSubscription(
            mailing=cleaned_data["subscription_mailing"], user=user
        )
        try:
            sub.clean()
        except ValidationError as validation_error:
            return validation_error

        sub.save()
        users_to_save.append(sub)

    if cleaned_data["subscription_email"]:
        sub = MailingSubscription(
            mailing=cleaned_data["subscription_mailing"],
            email=cleaned_data["subscription_email"],
        )

    try:
        sub.clean()
    except ValidationError as validation_error:
        return validation_error
    sub.save()

    # Save users after we are sure there is no error
    for user in users_to_save:
        user.save()

    return None

remove_subscription(cleaned_data)

Remove specified users from a mailing list.

Source code in club/views.py
def remove_subscription(self, cleaned_data):
    """Remove specified users from a mailing list."""
    fields = [
        val for key, val in cleaned_data.items() if key.startswith("removal_")
    ]
    for field in fields:
        for sub in field:
            sub.delete()

MailingDeleteView

Bases: CanEditMixin, DeleteView

MailingSubscriptionDeleteView

Bases: CanEditMixin, DeleteView

MailingAutoGenerationView

Bases: View

PosterListView

Bases: ClubTabsMixin, PosterListBaseView

List communication posters.

PosterCreateView

Bases: ClubTabsMixin, PosterCreateBaseView

Create communication poster.

PosterEditView

Bases: ClubTabsMixin, PosterEditBaseView

Edit communication poster.

PosterDeleteView

Bases: ClubTabsMixin, PosterDeleteBaseView

Delete communication poster.