diff --git a/accounting/models.py b/accounting/models.py index 254a41ba..9276441e 100644 --- a/accounting/models.py +++ b/accounting/models.py @@ -29,9 +29,7 @@ from core.models import SithFile, User class CurrencyField(models.DecimalField): - """ - This is a custom database field used for currency - """ + """Custom database field used for currency.""" def __init__(self, *args, **kwargs): kwargs["max_digits"] = 12 @@ -71,30 +69,22 @@ class Company(models.Model): return self.name def is_owned_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): return True return False def can_be_edited_by(self, user): - """ - Method to see if that object can be edited by the given user - """ - for club in user.memberships.filter(end_date=None).all(): - if club and club.role == settings.SITH_CLUB_ROLES_ID["Treasurer"]: - return True - return False + """Check if that object can be edited by the given user.""" + return user.memberships.filter( + end_date=None, club__role=settings.SITH_CLUB_ROLES_ID["Treasurer"] + ).exists() def can_be_viewed_by(self, user): - """ - Method to see if that object can be viewed by the given user - """ - for club in user.memberships.filter(end_date=None).all(): - if club and club.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]: - return True - return False + """Check if that object can be viewed by the given user.""" + return user.memberships.filter( + end_date=None, club__role_gte=settings.SITH_CLUB_ROLES_ID["Treasurer"] + ).exists() class BankAccount(models.Model): @@ -119,9 +109,7 @@ class BankAccount(models.Model): return reverse("accounting:bank_details", kwargs={"b_account_id": self.id}) def is_owned_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_anonymous: return False if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): @@ -158,9 +146,7 @@ class ClubAccount(models.Model): return reverse("accounting:club_details", kwargs={"c_account_id": self.id}) def is_owned_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_anonymous: return False if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): @@ -168,18 +154,14 @@ class ClubAccount(models.Model): return False def can_be_edited_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" m = self.club.get_membership_for(user) if m and m.role == settings.SITH_CLUB_ROLES_ID["Treasurer"]: return True return False def can_be_viewed_by(self, user): - """ - Method to see if that object can be viewed by the given user - """ + """Check if that object can be viewed by the given user.""" m = self.club.get_membership_for(user) if m and m.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]: return True @@ -202,9 +184,7 @@ class ClubAccount(models.Model): class GeneralJournal(models.Model): - """ - Class storing all the operations for a period of time - """ + """Class storing all the operations for a period of time.""" start_date = models.DateField(_("start date")) end_date = models.DateField(_("end date"), null=True, blank=True, default=None) @@ -231,9 +211,7 @@ class GeneralJournal(models.Model): return reverse("accounting:journal_details", kwargs={"j_id": self.id}) def is_owned_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_anonymous: return False if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): @@ -243,9 +221,7 @@ class GeneralJournal(models.Model): return False def can_be_edited_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): return True if self.club_account.can_be_edited_by(user): @@ -271,9 +247,7 @@ class GeneralJournal(models.Model): class Operation(models.Model): - """ - An operation is a line in the journal, a debit or a credit - """ + """An operation is a line in the journal, a debit or a credit.""" number = models.IntegerField(_("number")) journal = models.ForeignKey( @@ -422,9 +396,7 @@ class Operation(models.Model): return tar def is_owned_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_anonymous: return False if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): @@ -437,9 +409,7 @@ class Operation(models.Model): return False def can_be_edited_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): return True if self.journal.closed: @@ -451,10 +421,9 @@ class Operation(models.Model): class AccountingType(models.Model): - """ - Class describing the accounting types. + """Accounting types. - Thoses are numbers used in accounting to classify operations + Those are numbers used in accounting to classify operations """ code = models.CharField( @@ -488,9 +457,7 @@ class AccountingType(models.Model): return reverse("accounting:type_list") def is_owned_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Check if that object can be edited by the given user.""" if user.is_anonymous: return False if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): @@ -499,9 +466,7 @@ class AccountingType(models.Model): class SimplifiedAccountingType(models.Model): - """ - Class describing the simplified accounting types. - """ + """Simplified version of `AccountingType`.""" label = models.CharField(_("label"), max_length=128) accounting_type = models.ForeignKey( @@ -533,7 +498,7 @@ class SimplifiedAccountingType(models.Model): class Label(models.Model): - """Label allow a club to sort its operations""" + """Label allow a club to sort its operations.""" name = models.CharField(_("label"), max_length=64) club_account = models.ForeignKey( diff --git a/accounting/views.py b/accounting/views.py index 691bbbdc..85d1a4c7 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -53,9 +53,7 @@ from counter.models import Counter, Product, Selling class BankAccountListView(CanViewMixin, ListView): - """ - A list view for the admins - """ + """A list view for the admins.""" model = BankAccount template_name = "accounting/bank_account_list.jinja" @@ -66,18 +64,14 @@ class BankAccountListView(CanViewMixin, ListView): class SimplifiedAccountingTypeListView(CanViewMixin, ListView): - """ - A list view for the admins - """ + """A list view for the admins.""" model = SimplifiedAccountingType template_name = "accounting/simplifiedaccountingtype_list.jinja" class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView): - """ - An edit view for the admins - """ + """An edit view for the admins.""" model = SimplifiedAccountingType pk_url_kwarg = "type_id" @@ -86,9 +80,7 @@ class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView): class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView): - """ - Create an accounting type (for the admins) - """ + """Create an accounting type (for the admins).""" model = SimplifiedAccountingType fields = ["label", "accounting_type"] @@ -99,18 +91,14 @@ class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView): class AccountingTypeListView(CanViewMixin, ListView): - """ - A list view for the admins - """ + """A list view for the admins.""" model = AccountingType template_name = "accounting/accountingtype_list.jinja" class AccountingTypeEditView(CanViewMixin, UpdateView): - """ - An edit view for the admins - """ + """An edit view for the admins.""" model = AccountingType pk_url_kwarg = "type_id" @@ -119,9 +107,7 @@ class AccountingTypeEditView(CanViewMixin, UpdateView): class AccountingTypeCreateView(CanCreateMixin, CreateView): - """ - Create an accounting type (for the admins) - """ + """Create an accounting type (for the admins).""" model = AccountingType fields = ["code", "label", "movement_type"] @@ -132,9 +118,7 @@ class AccountingTypeCreateView(CanCreateMixin, CreateView): class BankAccountEditView(CanViewMixin, UpdateView): - """ - An edit view for the admins - """ + """An edit view for the admins.""" model = BankAccount pk_url_kwarg = "b_account_id" @@ -143,9 +127,7 @@ class BankAccountEditView(CanViewMixin, UpdateView): class BankAccountDetailView(CanViewMixin, DetailView): - """ - A detail view, listing every club account - """ + """A detail view, listing every club account.""" model = BankAccount pk_url_kwarg = "b_account_id" @@ -153,9 +135,7 @@ class BankAccountDetailView(CanViewMixin, DetailView): class BankAccountCreateView(CanCreateMixin, CreateView): - """ - Create a bank account (for the admins) - """ + """Create a bank account (for the admins).""" model = BankAccount fields = ["name", "club", "iban", "number"] @@ -165,9 +145,7 @@ class BankAccountCreateView(CanCreateMixin, CreateView): class BankAccountDeleteView( CanEditPropMixin, DeleteView ): # TODO change Delete to Close - """ - Delete a bank account (for the admins) - """ + """Delete a bank account (for the admins).""" model = BankAccount pk_url_kwarg = "b_account_id" @@ -179,9 +157,7 @@ class BankAccountDeleteView( class ClubAccountEditView(CanViewMixin, UpdateView): - """ - An edit view for the admins - """ + """An edit view for the admins.""" model = ClubAccount pk_url_kwarg = "c_account_id" @@ -190,9 +166,7 @@ class ClubAccountEditView(CanViewMixin, UpdateView): class ClubAccountDetailView(CanViewMixin, DetailView): - """ - A detail view, listing every journal - """ + """A detail view, listing every journal.""" model = ClubAccount pk_url_kwarg = "c_account_id" @@ -200,9 +174,7 @@ class ClubAccountDetailView(CanViewMixin, DetailView): class ClubAccountCreateView(CanCreateMixin, CreateView): - """ - Create a club account (for the admins) - """ + """Create a club account (for the admins).""" model = ClubAccount fields = ["name", "club", "bank_account"] @@ -220,9 +192,7 @@ class ClubAccountCreateView(CanCreateMixin, CreateView): class ClubAccountDeleteView( CanEditPropMixin, DeleteView ): # TODO change Delete to Close - """ - Delete a club account (for the admins) - """ + """Delete a club account (for the admins).""" model = ClubAccount pk_url_kwarg = "c_account_id" @@ -282,9 +252,7 @@ class JournalTabsMixin(TabedViewMixin): class JournalCreateView(CanCreateMixin, CreateView): - """ - Create a general journal - """ + """Create a general journal.""" model = GeneralJournal form_class = modelform_factory( @@ -304,9 +272,7 @@ class JournalCreateView(CanCreateMixin, CreateView): class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView): - """ - A detail view, listing every operation - """ + """A detail view, listing every operation.""" model = GeneralJournal pk_url_kwarg = "j_id" @@ -315,9 +281,7 @@ class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView): class JournalEditView(CanEditMixin, UpdateView): - """ - Update a general journal - """ + """Update a general journal.""" model = GeneralJournal pk_url_kwarg = "j_id" @@ -326,9 +290,7 @@ class JournalEditView(CanEditMixin, UpdateView): class JournalDeleteView(CanEditPropMixin, DeleteView): - """ - Delete a club account (for the admins) - """ + """Delete a club account (for the admins).""" model = GeneralJournal pk_url_kwarg = "j_id" @@ -467,9 +429,7 @@ class OperationForm(forms.ModelForm): class OperationCreateView(CanCreateMixin, CreateView): - """ - Create an operation - """ + """Create an operation.""" model = Operation form_class = OperationForm @@ -487,7 +447,7 @@ class OperationCreateView(CanCreateMixin, CreateView): return ret def get_context_data(self, **kwargs): - """Add journal to the context""" + """Add journal to the context.""" kwargs = super().get_context_data(**kwargs) if self.journal: kwargs["object"] = self.journal @@ -495,9 +455,7 @@ class OperationCreateView(CanCreateMixin, CreateView): class OperationEditView(CanEditMixin, UpdateView): - """ - An edit view, working as detail for the moment - """ + """An edit view, working as detail for the moment.""" model = Operation pk_url_kwarg = "op_id" @@ -505,16 +463,14 @@ class OperationEditView(CanEditMixin, UpdateView): template_name = "accounting/operation_edit.jinja" def get_context_data(self, **kwargs): - """Add journal to the context""" + """Add journal to the context.""" kwargs = super().get_context_data(**kwargs) kwargs["object"] = self.object.journal return kwargs class OperationPDFView(CanViewMixin, DetailView): - """ - Display the PDF of a given operation - """ + """Display the PDF of a given operation.""" model = Operation pk_url_kwarg = "op_id" @@ -666,9 +622,7 @@ class OperationPDFView(CanViewMixin, DetailView): class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView): - """ - Display a statement sorted by labels - """ + """Display a statement sorted by labels.""" model = GeneralJournal pk_url_kwarg = "j_id" @@ -726,16 +680,14 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView): return statement def get_context_data(self, **kwargs): - """Add infos to the context""" + """Add infos to the context.""" kwargs = super().get_context_data(**kwargs) kwargs["statement"] = self.big_statement() return kwargs class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView): - """ - Calculate a dictionary with operation target and sum of operations - """ + """Calculate a dictionary with operation target and sum of operations.""" model = GeneralJournal pk_url_kwarg = "j_id" @@ -765,7 +717,7 @@ class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView): return sum(self.statement(movement_type).values()) def get_context_data(self, **kwargs): - """Add journal to the context""" + """Add journal to the context.""" kwargs = super().get_context_data(**kwargs) kwargs["credit_statement"] = self.statement("CREDIT") kwargs["debit_statement"] = self.statement("DEBIT") @@ -775,9 +727,7 @@ class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView): class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView): - """ - Calculate a dictionary with operation type and sum of operations - """ + """Calculate a dictionary with operation type and sum of operations.""" model = GeneralJournal pk_url_kwarg = "j_id" @@ -795,7 +745,7 @@ class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView) return statement def get_context_data(self, **kwargs): - """Add journal to the context""" + """Add journal to the context.""" kwargs = super().get_context_data(**kwargs) kwargs["statement"] = self.statement() return kwargs @@ -810,9 +760,7 @@ class CompanyListView(CanViewMixin, ListView): class CompanyCreateView(CanCreateMixin, CreateView): - """ - Create a company - """ + """Create a company.""" model = Company fields = ["name"] @@ -821,9 +769,7 @@ class CompanyCreateView(CanCreateMixin, CreateView): class CompanyEditView(CanCreateMixin, UpdateView): - """ - Edit a company - """ + """Edit a company.""" model = Company pk_url_kwarg = "co_id" @@ -882,9 +828,7 @@ class CloseCustomerAccountForm(forms.Form): class RefoundAccountView(FormView): - """ - Create a selling with the same amount than the current user money - """ + """Create a selling with the same amount than the current user money.""" template_name = "accounting/refound_account.jinja" form_class = CloseCustomerAccountForm diff --git a/api/views/__init__.py b/api/views/__init__.py index d5ca6289..5017806b 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -23,9 +23,9 @@ from core.views import can_edit, can_view def check_if(obj, user, test): - """ - Detect if it's a single object or a queryset - aply a given test on individual object and return global permission + """Detect if it's a single object or a queryset. + + Apply a given test on individual object and return global permission. """ if isinstance(obj, QuerySet): for o in obj: @@ -39,9 +39,7 @@ def check_if(obj, user, test): class ManageModelMixin: @action(detail=True) def id(self, request, pk=None): - """ - Get by id (api/v1/router/{pk}/id/) - """ + """Get by id (api/v1/router/{pk}/id/).""" self.queryset = get_object_or_404(self.queryset.filter(id=pk)) serializer = self.get_serializer(self.queryset) return Response(serializer.data) diff --git a/api/views/api.py b/api/views/api.py index 6e3a056d..9de0a87e 100644 --- a/api/views/api.py +++ b/api/views/api.py @@ -23,9 +23,7 @@ from core.templatetags.renderer import markdown @api_view(["POST"]) @renderer_classes((StaticHTMLRenderer,)) def RenderMarkdown(request): - """ - Render Markdown - """ + """Render Markdown.""" try: data = markdown(request.POST["text"]) except: diff --git a/api/views/club.py b/api/views/club.py index 2333fffb..6c4c5b0b 100644 --- a/api/views/club.py +++ b/api/views/club.py @@ -31,9 +31,7 @@ class ClubSerializer(serializers.ModelSerializer): class ClubViewSet(RightModelViewSet): - """ - Manage Clubs (api/v1/club/) - """ + """Manage Clubs (api/v1/club/).""" serializer_class = ClubSerializer queryset = Club.objects.all() diff --git a/api/views/counter.py b/api/views/counter.py index a9fd64ce..3fbaa931 100644 --- a/api/views/counter.py +++ b/api/views/counter.py @@ -33,18 +33,14 @@ class CounterSerializer(serializers.ModelSerializer): class CounterViewSet(RightModelViewSet): - """ - Manage Counters (api/v1/counter/) - """ + """Manage Counters (api/v1/counter/).""" serializer_class = CounterSerializer queryset = Counter.objects.all() @action(detail=False) def bar(self, request): - """ - Return all bars (api/v1/counter/bar/) - """ + """Return all bars (api/v1/counter/bar/).""" self.queryset = self.queryset.filter(type="BAR") serializer = self.get_serializer(self.queryset, many=True) return Response(serializer.data) diff --git a/api/views/group.py b/api/views/group.py index c9183ed0..da37dbbc 100644 --- a/api/views/group.py +++ b/api/views/group.py @@ -25,9 +25,7 @@ class GroupSerializer(serializers.ModelSerializer): class GroupViewSet(RightModelViewSet): - """ - Manage Groups (api/v1/group/) - """ + """Manage Groups (api/v1/group/).""" serializer_class = GroupSerializer queryset = RealGroup.objects.all() diff --git a/api/views/launderette.py b/api/views/launderette.py index eae35a19..cb88d80c 100644 --- a/api/views/launderette.py +++ b/api/views/launderette.py @@ -60,54 +60,42 @@ class LaunderetteTokenSerializer(serializers.ModelSerializer): class LaunderettePlaceViewSet(RightModelViewSet): - """ - Manage Launderette (api/v1/launderette/place/) - """ + """Manage Launderette (api/v1/launderette/place/).""" serializer_class = LaunderettePlaceSerializer queryset = Launderette.objects.all() class LaunderetteMachineViewSet(RightModelViewSet): - """ - Manage Washing Machines (api/v1/launderette/machine/) - """ + """Manage Washing Machines (api/v1/launderette/machine/).""" serializer_class = LaunderetteMachineSerializer queryset = Machine.objects.all() class LaunderetteTokenViewSet(RightModelViewSet): - """ - Manage Launderette's tokens (api/v1/launderette/token/) - """ + """Manage Launderette's tokens (api/v1/launderette/token/).""" serializer_class = LaunderetteTokenSerializer queryset = Token.objects.all() @action(detail=False) def washing(self, request): - """ - Return all washing tokens (api/v1/launderette/token/washing) - """ + """Return all washing tokens (api/v1/launderette/token/washing).""" self.queryset = self.queryset.filter(type="WASHING") serializer = self.get_serializer(self.queryset, many=True) return Response(serializer.data) @action(detail=False) def drying(self, request): - """ - Return all drying tokens (api/v1/launderette/token/drying) - """ + """Return all drying tokens (api/v1/launderette/token/drying).""" self.queryset = self.queryset.filter(type="DRYING") serializer = self.get_serializer(self.queryset, many=True) return Response(serializer.data) @action(detail=False) def avaliable(self, request): - """ - Return all avaliable tokens (api/v1/launderette/token/avaliable) - """ + """Return all avaliable tokens (api/v1/launderette/token/avaliable).""" self.queryset = self.queryset.filter( borrow_date__isnull=True, user__isnull=True ) @@ -116,9 +104,7 @@ class LaunderetteTokenViewSet(RightModelViewSet): @action(detail=False) def unavaliable(self, request): - """ - Return all unavaliable tokens (api/v1/launderette/token/unavaliable) - """ + """Return all unavaliable tokens (api/v1/launderette/token/unavaliable).""" self.queryset = self.queryset.filter( borrow_date__isnull=False, user__isnull=False ) diff --git a/api/views/user.py b/api/views/user.py index d5aecd15..84078ce2 100644 --- a/api/views/user.py +++ b/api/views/user.py @@ -39,9 +39,9 @@ class UserSerializer(serializers.ModelSerializer): class UserViewSet(RightModelViewSet): - """ - Manage Users (api/v1/user/) - Only show active users + """Manage Users (api/v1/user/). + + Only show active users. """ serializer_class = UserSerializer @@ -49,9 +49,7 @@ class UserViewSet(RightModelViewSet): @action(detail=False) def birthday(self, request): - """ - Return all users born today (api/v1/user/birstdays) - """ + """Return all users born today (api/v1/user/birstdays).""" date = datetime.datetime.today() self.queryset = self.queryset.filter(date_of_birth=date) serializer = self.get_serializer(self.queryset, many=True) diff --git a/api/views/uv.py b/api/views/uv.py index a83a8936..09292d8e 100644 --- a/api/views/uv.py +++ b/api/views/uv.py @@ -28,10 +28,10 @@ def uv_endpoint(request): return Response(make_clean_uv(short_uv, full_uv)) -def find_uv(lang, year, code): - """ - Uses the UTBM API to find an UV. - short_uv is the UV entry in the UV list. It is returned as it contains +def find_uv(lang: str, year: int | str, code: str) -> tuple[dict | None, dict | None]: + """Uses the UTBM API to find an UV. + + Short_uv is the UV entry in the UV list. It is returned as it contains information which are not in full_uv. full_uv is the detailed representation of an UV. """ @@ -44,7 +44,7 @@ def find_uv(lang, year, code): # find the first UV which matches the code short_uv = next(uv for uv in uvs if uv["code"] == code) except StopIteration: - return (None, None) + return None, None # get detailed information about the UV uv_url = settings.SITH_PEDAGOGY_UTBM_API + "/uv/{}/{}/{}/{}".format( @@ -53,13 +53,11 @@ def find_uv(lang, year, code): response = urllib.request.urlopen(uv_url) full_uv = json.loads(response.read().decode("utf-8")) - return (short_uv, full_uv) + return short_uv, full_uv -def make_clean_uv(short_uv, full_uv): - """ - Cleans the data up so that it corresponds to our data representation. - """ +def make_clean_uv(short_uv: dict, full_uv: dict): + """Cleans the data up so that it corresponds to our data representation.""" res = {} res["credit_type"] = short_uv["codeCategorie"] diff --git a/club/forms.py b/club/forms.py index ad3273c6..3a21fd6d 100644 --- a/club/forms.py +++ b/club/forms.py @@ -44,9 +44,7 @@ class ClubEditForm(forms.ModelForm): class MailingForm(forms.Form): - """ - Form handling mailing lists right - """ + """Form handling mailing lists right.""" ACTION_NEW_MAILING = 1 ACTION_NEW_SUBSCRIPTION = 2 @@ -105,16 +103,12 @@ class MailingForm(forms.Form): ) 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 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")) def clean_subscription_users(self): - """ - Convert given users into real users and check their validity - """ + """Convert given users into real users and check their validity.""" cleaned_data = super().clean() users = [] for user in cleaned_data["subscription_users"]: @@ -177,9 +171,7 @@ class SellingsForm(forms.Form): class ClubMemberForm(forms.Form): - """ - Form handling the members of a club - """ + """Form handling the members of a club.""" error_css_class = "error" required_css_class = "required" @@ -236,9 +228,9 @@ class ClubMemberForm(forms.Form): self.fields.pop("start_date") def clean_users(self): - """ - Check that the user is not trying to add an user already in the club - Also check that the user is valid and has a valid subscription + """Check that the user is not trying to add an user already in the club. + + Also check that the user is valid and has a valid subscription. """ cleaned_data = super().clean() users = [] @@ -260,9 +252,7 @@ class ClubMemberForm(forms.Form): return users def clean(self): - """ - Check user rights for adding an user - """ + """Check user rights for adding an user.""" cleaned_data = super().clean() if "start_date" in cleaned_data and not cleaned_data["start_date"]: diff --git a/club/models.py b/club/models.py index e315f1d2..0ed51389 100644 --- a/club/models.py +++ b/club/models.py @@ -21,7 +21,7 @@ # Place - Suite 330, Boston, MA 02111-1307, USA. # # -from typing import Optional +from __future__ import annotations from django.conf import settings from django.core import validators @@ -46,9 +46,7 @@ def get_default_owner_group(): class Club(models.Model): - """ - The Club class, made as a tree to allow nice tidy organization - """ + """The Club class, made as a tree to allow nice tidy organization.""" id = models.AutoField(primary_key=True, db_index=True) name = models.CharField(_("name"), max_length=64) @@ -141,7 +139,7 @@ class Club(models.Model): ).first() def check_loop(self): - """Raise a validation error when a loop is found within the parent list""" + """Raise a validation error when a loop is found within the parent list.""" objs = [] cur = self while cur.parent is not None: @@ -223,9 +221,7 @@ class Club(models.Model): return self.name def is_owned_by(self, user): - """ - Method to see if that object can be super edited by the given user - """ + """Method to see if that object can be super edited by the given user.""" if user.is_anonymous: return False return user.is_board_member @@ -234,24 +230,21 @@ class Club(models.Model): return "https://%s%s" % (settings.SITH_URL, self.logo.url) def can_be_edited_by(self, user): - """ - Method to see if that object can be edited by the given user - """ + """Method to see if that object can be edited by the given user.""" return self.has_rights_in_club(user) def can_be_viewed_by(self, user): - """ - Method to see if that object can be seen by the given user - """ + """Method to see if that object can be seen by the given user.""" sub = User.objects.filter(pk=user.pk).first() if sub is None: return False return sub.was_subscribed - def get_membership_for(self, user: User) -> Optional["Membership"]: - """ - Return the current membership the given user. - The result is cached. + 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 @@ -273,15 +266,12 @@ class Club(models.Model): class MembershipQuerySet(models.QuerySet): def ongoing(self) -> "MembershipQuerySet": - """ - Filter all memberships which are not finished yet - """ + """Filter all memberships which are not finished yet.""" # noinspection PyTypeChecker return self.filter(Q(end_date=None) | Q(end_date__gte=timezone.now())) def board(self) -> "MembershipQuerySet": - """ - Filter all memberships where the user is/was in the board. + """Filter all memberships where the user is/was in the board. Be aware that users who were in the board in the past are included, even if there are no more members. @@ -293,9 +283,9 @@ class MembershipQuerySet(models.QuerySet): return self.filter(role__gt=settings.SITH_MAXIMUM_FREE_ROLE) def update(self, **kwargs): - """ - Work just like the default Django's update() method, - but add a cache refresh for the elements of the queryset. + """Refresh the cache for the elements of the queryset. + + Besides that, does the same job as a regular update method. Be aware that this adds a db query to retrieve the updated objects """ @@ -315,8 +305,7 @@ class MembershipQuerySet(models.QuerySet): ) def delete(self): - """ - Work just like the default Django's delete() method, + """Work just like the default Django's delete() method, but add a cache invalidation for the elements of the queryset before the deletion. @@ -332,8 +321,7 @@ class MembershipQuerySet(models.QuerySet): class Membership(models.Model): - """ - The Membership class makes the connection between User and Clubs + """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 @@ -390,17 +378,13 @@ class Membership(models.Model): return reverse("club:club_members", kwargs={"club_id": self.club_id}) def is_owned_by(self, user): - """ - Method to see if that object can be super edited by the given user - """ + """Method to see if that object can be super edited by the given user.""" if user.is_anonymous: return False return user.is_board_member def can_be_edited_by(self, user: User) -> bool: - """ - Check if that object can be edited by the given user - """ + """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) @@ -414,9 +398,10 @@ class Membership(models.Model): class Mailing(models.Model): - """ - This class correspond to a mailing list - Remember that mailing lists should be validated by UTBM + """A Mailing list for a club. + + Warning: + Remember that mailing lists should be validated by UTBM. """ club = models.ForeignKey( @@ -508,9 +493,7 @@ class Mailing(models.Model): class MailingSubscription(models.Model): - """ - This class makes the link between user and mailing list - """ + """Link between user and mailing list.""" mailing = models.ForeignKey( Mailing, diff --git a/club/tests.py b/club/tests.py index b893cb99..af8aafde 100644 --- a/club/tests.py +++ b/club/tests.py @@ -29,8 +29,8 @@ from sith.settings import SITH_BAR_MANAGER, SITH_MAIN_CLUB_ID class ClubTest(TestCase): - """ - Set up data for test cases related to clubs and membership + """Set up data for test cases related to clubs and membership. + The generated dataset is the one created by the populate command, plus the following modifications : @@ -94,8 +94,7 @@ class ClubTest(TestCase): class MembershipQuerySetTest(ClubTest): def test_ongoing(self): - """ - Test that the ongoing queryset method returns the memberships that + """Test that the ongoing queryset method returns the memberships that are not ended. """ current_members = list(self.club.members.ongoing().order_by("id")) @@ -108,9 +107,8 @@ class MembershipQuerySetTest(ClubTest): assert current_members == expected def test_board(self): - """ - Test that the board queryset method returns the memberships - of user in the club board + """Test that the board queryset method returns the memberships + of user in the club board. """ board_members = list(self.club.members.board().order_by("id")) expected = [ @@ -123,9 +121,8 @@ class MembershipQuerySetTest(ClubTest): assert board_members == expected def test_ongoing_board(self): - """ - Test that combining ongoing and board returns users - who are currently board members of the club + """Test that combining ongoing and board returns users + who are currently board members of the club. """ members = list(self.club.members.ongoing().board().order_by("id")) expected = [ @@ -136,9 +133,7 @@ class MembershipQuerySetTest(ClubTest): assert members == expected def test_update_invalidate_cache(self): - """ - Test that the `update` queryset method properly invalidate cache - """ + """Test that the `update` queryset method properly invalidate cache.""" mem_skia = self.skia.memberships.get(club=self.club) cache.set(f"membership_{mem_skia.club_id}_{mem_skia.user_id}", mem_skia) self.skia.memberships.update(end_date=localtime(now()).date()) @@ -157,10 +152,7 @@ class MembershipQuerySetTest(ClubTest): assert new_mem.role == 5 def test_delete_invalidate_cache(self): - """ - Test that the `delete` queryset properly invalidate cache - """ - + """Test that the `delete` queryset properly invalidate cache.""" mem_skia = self.skia.memberships.get(club=self.club) mem_comptable = self.comptable.memberships.get(club=self.club) cache.set(f"membership_{mem_skia.club_id}_{mem_skia.user_id}", mem_skia) @@ -180,9 +172,7 @@ class MembershipQuerySetTest(ClubTest): class ClubModelTest(ClubTest): def assert_membership_started_today(self, user: User, role: int): - """ - Assert that the given membership is active and started today - """ + """Assert that the given membership is active and started today.""" membership = user.memberships.ongoing().filter(club=self.club).first() assert membership is not None assert localtime(now()).date() == membership.start_date @@ -195,17 +185,14 @@ class ClubModelTest(ClubTest): assert user.is_in_group(name=board_group) def assert_membership_ended_today(self, user: User): - """ - Assert that the given user have a membership which ended today - """ + """Assert that the given user have a membership which ended today.""" today = localtime(now()).date() assert user.memberships.filter(club=self.club, end_date=today).exists() assert self.club.get_membership_for(user) is None def test_access_unauthorized(self): - """ - Test that users who never subscribed and anonymous users - cannot see the page + """Test that users who never subscribed and anonymous users + cannot see the page. """ response = self.client.post(self.members_url) assert response.status_code == 403 @@ -215,8 +202,7 @@ class ClubModelTest(ClubTest): assert response.status_code == 403 def test_display(self): - """ - Test that a GET request return a page where the requested + """Test that a GET request return a page where the requested information are displayed. """ self.client.force_login(self.skia) @@ -251,9 +237,7 @@ class ClubModelTest(ClubTest): self.assertInHTML(expected_html, response.content.decode()) def test_root_add_one_club_member(self): - """ - Test that root users can add members to clubs, one at a time - """ + """Test that root users can add members to clubs, one at a time.""" self.client.force_login(self.root) response = self.client.post( self.members_url, @@ -264,9 +248,7 @@ class ClubModelTest(ClubTest): self.assert_membership_started_today(self.subscriber, role=3) def test_root_add_multiple_club_member(self): - """ - Test that root users can add multiple members at once to clubs - """ + """Test that root users can add multiple members at once to clubs.""" self.client.force_login(self.root) response = self.client.post( self.members_url, @@ -281,8 +263,7 @@ class ClubModelTest(ClubTest): self.assert_membership_started_today(self.krophil, role=3) def test_add_unauthorized_members(self): - """ - Test that users who are not currently subscribed + """Test that users who are not currently subscribed cannot be members of clubs. """ self.client.force_login(self.root) @@ -302,9 +283,8 @@ class ClubModelTest(ClubTest): assert '