Added type hints to the Mia core application.
This commit is contained in:
		| @@ -25,11 +25,30 @@ class UserConverter: | ||||
|     """The path converter for the user accounts.""" | ||||
|     regex = ".*" | ||||
|  | ||||
|     def to_python(self, value): | ||||
|     def to_python(self, value: str) -> User: | ||||
|         """Returns the user by her log in ID. | ||||
|  | ||||
|         Args: | ||||
|             value: The log in ID. | ||||
|  | ||||
|         Returns: | ||||
|             The user. | ||||
|  | ||||
|         Raises: | ||||
|             ValueError: When the value is invalid | ||||
|         """ | ||||
|         try: | ||||
|             return User.objects.get(login_id=value) | ||||
|         except User.DoesNotExist: | ||||
|             raise ValueError | ||||
|  | ||||
|     def to_url(self, value): | ||||
|     def to_url(self, value: User) -> str: | ||||
|         """Returns the log in ID of a user. | ||||
|  | ||||
|         Args: | ||||
|             value: The user. | ||||
|  | ||||
|         Returns: | ||||
|             The log in ID. | ||||
|         """ | ||||
|         return value.login_id | ||||
|   | ||||
| @@ -22,6 +22,7 @@ application. | ||||
| import ipaddress | ||||
| import socket | ||||
| from functools import wraps | ||||
| from typing import Optional | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.db.models import F | ||||
| @@ -35,23 +36,23 @@ from .models import User, Country | ||||
| class AccountBackend: | ||||
|     """The account backend for the django-digest module.""" | ||||
|  | ||||
|     def get_partial_digest(self, username): | ||||
|     def get_partial_digest(self, username: str) -> Optional[str]: | ||||
|         """Returns the HTTP digest authentication password digest hash | ||||
|         of a user. | ||||
|  | ||||
|         Args: | ||||
|             username (str): The log in user name. | ||||
|             username: The log in user name. | ||||
|  | ||||
|         Return: | ||||
|             str: The HTTP digest authentication password hash of | ||||
|             the user, or None if the user does not exist. | ||||
|             The HTTP digest authentication password hash of the user, or None | ||||
|             if the user does not exist. | ||||
|         """ | ||||
|         user = User.objects.filter(login_id=username).first() | ||||
|         if user is None: | ||||
|             return None | ||||
|         return user.password | ||||
|  | ||||
|     def get_user(self, username): | ||||
|     def get_user(self, username: str) -> Optional[User]: | ||||
|         """Returns the user by her log in user name. | ||||
|  | ||||
|         Args: | ||||
| @@ -86,7 +87,7 @@ def login_required(function=None): | ||||
|     return decorator | ||||
|  | ||||
|  | ||||
| def _log_visit(request): | ||||
| def _log_visit(request: HttpRequest) -> None: | ||||
|     """Logs the visit information for the logged-in user. | ||||
|  | ||||
|     Args: | ||||
| @@ -106,21 +107,29 @@ def _log_visit(request): | ||||
|     request.session["visit_logged"] = True | ||||
|  | ||||
|  | ||||
| def _get_remote_ip(request): | ||||
| def _get_remote_ip(request: HttpRequest) -> str: | ||||
|     """Returns the IP of the remote client. | ||||
|  | ||||
|     Args: | ||||
|         request: The request. | ||||
|  | ||||
|     Returns: | ||||
|         The IP of the remote client. | ||||
|     """ | ||||
|     x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") | ||||
|     if x_forwarded_for: | ||||
|         return x_forwarded_for.split(",")[0] | ||||
|     return request.META.get('REMOTE_ADDR') | ||||
|  | ||||
|  | ||||
| def _get_host(ip): | ||||
| def _get_host(ip: str) -> Optional[str]: | ||||
|     """Look-up the host name by its IP. | ||||
|  | ||||
|     Args: | ||||
|         ip (str): The IP | ||||
|         ip: The IP | ||||
|  | ||||
|     Returns: | ||||
|         str: The host name, or None if the look-up fails. | ||||
|         The host name, or None if the look-up fails. | ||||
|     """ | ||||
|     try: | ||||
|         return socket.gethostbyaddr(ip)[0] | ||||
| @@ -128,31 +137,30 @@ def _get_host(ip): | ||||
|         return None | ||||
|  | ||||
|  | ||||
| def _get_country(ip): | ||||
| def _get_country(ip: str) -> Optional[Country]: | ||||
|     """Look-up the country by its IP. | ||||
|  | ||||
|     Args: | ||||
|         ip (str): The IP | ||||
|         ip: The IP | ||||
|  | ||||
|     Returns: | ||||
|         Country: The country. | ||||
|         The country. | ||||
|     """ | ||||
|     code = _get_country_code(ip) | ||||
|     try: | ||||
|         return Country.objects.get(code=code) | ||||
|     except Country.DoesNotExist: | ||||
|         pass | ||||
|     return None | ||||
|         return None | ||||
|  | ||||
|  | ||||
| def _get_country_code(ip): | ||||
| def _get_country_code(ip: str) -> Optional[str]: | ||||
|     """Look-up the country code by its IP. | ||||
|  | ||||
|     Args: | ||||
|         ip (str): The IP | ||||
|         ip: The IP | ||||
|  | ||||
|     Returns: | ||||
|         str: The country code, or None if the look-up fails. | ||||
|         The country code, or None if the look-up fails. | ||||
|     """ | ||||
|     try: | ||||
|         return geolite2.lookup(ip).country | ||||
|   | ||||
| @@ -75,7 +75,7 @@ class UserForm(forms.Form): | ||||
|         if errors: | ||||
|             raise forms.ValidationError(errors) | ||||
|  | ||||
|     def _validate_login_id_unique(self): | ||||
|     def _validate_login_id_unique(self) -> None: | ||||
|         """Validates whether the log in ID is unique. | ||||
|  | ||||
|         Raises: | ||||
| @@ -93,7 +93,7 @@ class UserForm(forms.Form): | ||||
|         self.add_error("login_id", error) | ||||
|         raise error | ||||
|  | ||||
|     def _validate_password_new_required(self): | ||||
|     def _validate_password_new_required(self) -> None: | ||||
|         """Validates whether the password is entered for newly-created users. | ||||
|  | ||||
|         Raises: | ||||
| @@ -108,7 +108,7 @@ class UserForm(forms.Form): | ||||
|         self.add_error("password", error) | ||||
|         raise error | ||||
|  | ||||
|     def _validate_password_login_id_changed_required(self): | ||||
|     def _validate_password_login_id_changed_required(self) -> None: | ||||
|         """Validates whether the password is entered for users whose login ID | ||||
|         changed. | ||||
|  | ||||
| @@ -129,7 +129,7 @@ class UserForm(forms.Form): | ||||
|         self.add_error("password", error) | ||||
|         raise error | ||||
|  | ||||
|     def _validate_password2_required(self): | ||||
|     def _validate_password2_required(self) -> None: | ||||
|         """Validates whether the second password is entered. | ||||
|  | ||||
|         Raises: | ||||
| @@ -145,7 +145,7 @@ class UserForm(forms.Form): | ||||
|         self.add_error("password2", error) | ||||
|         raise error | ||||
|  | ||||
|     def _validate_passwords_equal(self): | ||||
|     def _validate_passwords_equal(self) -> None: | ||||
|         """Validates whether the two passwords are equa. | ||||
|  | ||||
|         Raises: | ||||
| @@ -162,7 +162,7 @@ class UserForm(forms.Form): | ||||
|         self.add_error("password2", error) | ||||
|         raise error | ||||
|  | ||||
|     def _validate_is_disabled_not_oneself(self): | ||||
|     def _validate_is_disabled_not_oneself(self) -> None: | ||||
|         """Validates whether the user tries to disable herself | ||||
|  | ||||
|         Raises: | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| """The data models of the Mia core application. | ||||
|  | ||||
| """ | ||||
| import datetime | ||||
| import hashlib | ||||
|  | ||||
| from dirtyfields import DirtyFieldsMixin | ||||
| @@ -57,11 +56,12 @@ class Country(DirtyFieldsMixin, models.Model): | ||||
|         return self.code.__str__() + " " + self.name.__str__() | ||||
|  | ||||
|     @property | ||||
|     def name(self): | ||||
|     def name(self) -> str: | ||||
|         """The country name in the current language.""" | ||||
|         return get_multi_lingual_attr(self, "name", "en") | ||||
|  | ||||
|     @name.setter | ||||
|     def name(self, value): | ||||
|     def name(self, value: str) -> None: | ||||
|         set_multi_lingual_attr(self, "name", value) | ||||
|  | ||||
|     class Meta: | ||||
| @@ -101,11 +101,11 @@ class User(DirtyFieldsMixin, models.Model): | ||||
|     USERNAME_FIELD = "login_id" | ||||
|  | ||||
|     @property | ||||
|     def is_anonymous(self): | ||||
|     def is_anonymous(self) -> bool: | ||||
|         return False | ||||
|  | ||||
|     @property | ||||
|     def is_authenticated(self): | ||||
|     def is_authenticated(self) -> bool: | ||||
|         return True | ||||
|  | ||||
|     def set_password(self): | ||||
| @@ -142,16 +142,16 @@ class User(DirtyFieldsMixin, models.Model): | ||||
|             F"{login_id}:{settings.DIGEST_REALM}:{password}") | ||||
|  | ||||
|     @staticmethod | ||||
|     def md5(value): | ||||
|     def md5(value: str) -> str: | ||||
|         m = hashlib.md5() | ||||
|         m.update(value.encode("utf-8")) | ||||
|         return m.hexdigest() | ||||
|  | ||||
|     def is_in_use(self): | ||||
|     def is_in_use(self) -> bool: | ||||
|         """Returns whether this user is in use. | ||||
|  | ||||
|         Returns: | ||||
|             bool: True if this user is in use, or False otherwise. | ||||
|             True if this user is in use, or False otherwise. | ||||
|         """ | ||||
|         for table in connection.introspection.table_names(): | ||||
|             if self._is_in_use_with(F"SELECT * FROM {table}" | ||||
| @@ -163,14 +163,14 @@ class User(DirtyFieldsMixin, models.Model): | ||||
|                 return True | ||||
|         return False | ||||
|  | ||||
|     def _is_in_use_with(self, sql): | ||||
|     def _is_in_use_with(self, sql: str) -> bool: | ||||
|         """Returns whether this user is in use with a specific SQL statement. | ||||
|  | ||||
|         Args: | ||||
|             sql (str): The SQL query statement | ||||
|             sql: The SQL query statement | ||||
|  | ||||
|         Returns: | ||||
|             bool: True if this user is in use, or False otherwise. | ||||
|             True if this user is in use, or False otherwise. | ||||
|         """ | ||||
|         with connection.cursor() as cursor: | ||||
|             try: | ||||
|   | ||||
| @@ -20,6 +20,8 @@ | ||||
| """ | ||||
| import datetime | ||||
| import re | ||||
| from datetime import date | ||||
| from typing import Optional, List, Any, Union | ||||
|  | ||||
| from django.core.serializers.json import DjangoJSONEncoder | ||||
| from django.template import defaultfilters | ||||
| @@ -33,72 +35,73 @@ class Period: | ||||
|     """The template helper for the period chooser. | ||||
|  | ||||
|     Args: | ||||
|         spec (str): The current period specification | ||||
|         data_start (datetime.date): The available first day of the data. | ||||
|         data_end (datetime.date): The available last day of the data. | ||||
|         spec: The current period specification | ||||
|         data_start: The available first day of the data. | ||||
|         data_end: The available last day of the data. | ||||
|  | ||||
|     Raises: | ||||
|         ValueError: When the period specification is invalid. | ||||
|     """ | ||||
|     def __init__(self, spec=None, data_start=None, data_end=None): | ||||
|     def __init__(self, spec: str = None, data_start: datetime.date = None, | ||||
|                  data_end: datetime.date = None): | ||||
|         # Raises ValueError | ||||
|         self._period = self.Parser(spec) | ||||
|         self._data_start = data_start | ||||
|         self._data_end = data_end | ||||
|  | ||||
|     @property | ||||
|     def spec(self): | ||||
|     def spec(self) -> str: | ||||
|         """Returns the period specification. | ||||
|  | ||||
|         Returns: | ||||
|             str: The period specification. | ||||
|             The period specification. | ||||
|         """ | ||||
|         return self._period.spec | ||||
|  | ||||
|     @property | ||||
|     def start(self): | ||||
|     def start(self) -> datetime.date: | ||||
|         """Returns the start day of the currently-specified period. | ||||
|  | ||||
|         Returns: | ||||
|             datetime.date: The start day of the currently-specified period. | ||||
|             The start day of the currently-specified period. | ||||
|         """ | ||||
|         return self._period.start | ||||
|  | ||||
|     @property | ||||
|     def end(self): | ||||
|     def end(self) -> datetime.date: | ||||
|         """Returns the end day of the currently-specified period. | ||||
|  | ||||
|         Returns: | ||||
|             datetime.date: The end day of the currently-specified period. | ||||
|             The end day of the currently-specified period. | ||||
|         """ | ||||
|         return self._period.end | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
|     def description(self) -> str: | ||||
|         """Returns the text description of the currently-specified period. | ||||
|  | ||||
|         Returns: | ||||
|             str: The text description of the currently-specified period | ||||
|             The text description of the currently-specified period | ||||
|         """ | ||||
|         return self._period.description | ||||
|  | ||||
|     @property | ||||
|     def prep_desc(self): | ||||
|     def prep_desc(self) -> str: | ||||
|         """Returns the text description with preposition of the | ||||
|         currently-specified period. | ||||
|  | ||||
|         Returns: | ||||
|             str: The text description with preposition of the | ||||
|                 currently-specified period | ||||
|             The text description with preposition of the currently-specified | ||||
|             period. | ||||
|         """ | ||||
|         return self._period.prep_desc | ||||
|  | ||||
|     @staticmethod | ||||
|     def _get_last_month_start(): | ||||
|     def _get_last_month_start() -> datetime.date: | ||||
|         """Returns the first day of the last month. | ||||
|  | ||||
|         Returns: | ||||
|             datetime.date: The first day of the last month. | ||||
|             The first day of the last month. | ||||
|         """ | ||||
|         today = timezone.localdate() | ||||
|         month = today.month - 1 | ||||
| @@ -109,11 +112,11 @@ class Period: | ||||
|         return datetime.date(year, month, 1) | ||||
|  | ||||
|     @staticmethod | ||||
|     def _get_next_month_start(): | ||||
|     def _get_next_month_start() -> datetime.date: | ||||
|         """Returns the first day of the next month. | ||||
|  | ||||
|         Returns: | ||||
|             datetime.date: The first day of the next month. | ||||
|             The first day of the next month. | ||||
|         """ | ||||
|         today = timezone.localdate() | ||||
|         month = today.month + 1 | ||||
| @@ -123,12 +126,12 @@ class Period: | ||||
|             year = year + 1 | ||||
|         return datetime.date(year, month, 1) | ||||
|  | ||||
|     def this_month(self): | ||||
|     def this_month(self) -> Optional[str]: | ||||
|         """Returns the specification of this month. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification of this month, or None if there is no | ||||
|                 data in or before this month. | ||||
|             The specification of this month, or None if there is no data in or | ||||
|             before this month. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -139,12 +142,12 @@ class Period: | ||||
|             return None | ||||
|         return dateformat.format(today, "Y-m") | ||||
|  | ||||
|     def last_month(self): | ||||
|     def last_month(self) -> Optional[str]: | ||||
|         """Returns the specification of last month. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification of last month, or None if there is no | ||||
|                 data in or before last month. | ||||
|             The specification of last month, or None if there is no data in or | ||||
|             before last month. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -155,25 +158,25 @@ class Period: | ||||
|             return None | ||||
|         return dateformat.format(last_month_start, "Y-m") | ||||
|  | ||||
|     def since_last_month(self): | ||||
|     def since_last_month(self) -> Optional[str]: | ||||
|         """Returns the specification since last month. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification since last month, or None if there is | ||||
|                 no data in or before last month. | ||||
|             The specification since last month, or None if there is no data in | ||||
|             or before last month. | ||||
|         """ | ||||
|         last_month = self.last_month() | ||||
|         if last_month is None: | ||||
|             return None | ||||
|         return last_month + "-" | ||||
|  | ||||
|     def has_months_to_choose(self): | ||||
|     def has_months_to_choose(self) -> bool: | ||||
|         """Returns whether there are months to choose besides this month and | ||||
|         last month. | ||||
|  | ||||
|         Returns: | ||||
|             bool: True if there are months to choose besides this month and | ||||
|                 last month, or False otherwise. | ||||
|             True if there are months to choose besides this month and last | ||||
|             month, or False otherwise. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return False | ||||
| @@ -183,14 +186,13 @@ class Period: | ||||
|             return True | ||||
|         return False | ||||
|  | ||||
|     def chosen_month(self): | ||||
|     def chosen_month(self) -> Optional[str]: | ||||
|         """Returns the specification of the chosen month, or None if the | ||||
|         current period is not a month or is out of available data range. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification of the chosen month, or None if the | ||||
|                 current period is not a month or is out of available data | ||||
|                 range. | ||||
|             The specification of the chosen month, or None if the current | ||||
|             period is not a month or is out of available data range. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -203,12 +205,12 @@ class Period: | ||||
|             return None | ||||
|         return self._period.spec | ||||
|  | ||||
|     def this_year(self): | ||||
|     def this_year(self) -> Optional[str]: | ||||
|         """Returns the specification of this year. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification of this year, or None if there is no | ||||
|                 data in or before this year. | ||||
|             The specification of this year, or None if there is no data in or | ||||
|             before this year. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -217,12 +219,12 @@ class Period: | ||||
|             return None | ||||
|         return str(this_year) | ||||
|  | ||||
|     def last_year(self): | ||||
|     def last_year(self) -> Optional[str]: | ||||
|         """Returns the specification of last year. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification of last year, or None if there is no | ||||
|                 data in or before last year. | ||||
|             The specification of last year, or None if there is no data in or | ||||
|             before last year. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -231,13 +233,13 @@ class Period: | ||||
|             return None | ||||
|         return str(last_year) | ||||
|  | ||||
|     def has_years_to_choose(self): | ||||
|     def has_years_to_choose(self) -> bool: | ||||
|         """Returns whether there are years to choose besides this year and | ||||
|         last year. | ||||
|  | ||||
|         Returns: | ||||
|             bool: True if there are years to choose besides this year and | ||||
|                 last year, or False otherwise. | ||||
|             True if there are years to choose besides this year and last year, | ||||
|             or False otherwise. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return False | ||||
| @@ -248,11 +250,12 @@ class Period: | ||||
|             return True | ||||
|         return False | ||||
|  | ||||
|     def years_to_choose(self): | ||||
|     def years_to_choose(self) -> Optional[List[str]]: | ||||
|         """Returns the years to choose besides this year and last year. | ||||
|  | ||||
|         Returns: | ||||
|             list[str]: The years to choose besides this year and last year. | ||||
|             The years to choose besides this year and last year, or None if | ||||
|             there is no data. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -263,12 +266,12 @@ class Period: | ||||
|             self._data_end.year, this_year, -1)] | ||||
|         return after + before[::-1] | ||||
|  | ||||
|     def today(self): | ||||
|     def today(self) -> Optional[None]: | ||||
|         """Returns the specification of today. | ||||
|  | ||||
|         Returns: | ||||
|             (str): The specification of today, or None if there is no data | ||||
|                 in or before today. | ||||
|             The specification of today, or None if there is no data in or | ||||
|             before today. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -277,12 +280,12 @@ class Period: | ||||
|             return None | ||||
|         return dateformat.format(today, "Y-m-d") | ||||
|  | ||||
|     def yesterday(self): | ||||
|     def yesterday(self) -> Optional[str]: | ||||
|         """Returns the specification of yesterday. | ||||
|  | ||||
|         Returns: | ||||
|             (str): The specification of yesterday, or None if there is no data | ||||
|                 in or before yesterday. | ||||
|             The specification of yesterday, or None if there is no data in or | ||||
|             before yesterday. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -291,21 +294,21 @@ class Period: | ||||
|             return None | ||||
|         return dateformat.format(yesterday, "Y-m-d") | ||||
|  | ||||
|     def chosen_day(self): | ||||
|     def chosen_day(self) -> str: | ||||
|         """Returns the specification of the chosen day. | ||||
|  | ||||
|         Returns: | ||||
|             (str): The specification of the chosen day, or the start day | ||||
|                 of the period if the current period is not a day. | ||||
|             The specification of the chosen day, or the start day of the period | ||||
|             if the current period is not a day. | ||||
|         """ | ||||
|         return dateformat.format(self._period.start, "Y-m-d") | ||||
|  | ||||
|     def has_days_to_choose(self): | ||||
|     def has_days_to_choose(self) -> bool: | ||||
|         """Returns whether there are more than one day to choose from. | ||||
|  | ||||
|         Returns: | ||||
|             bool: True if there are more than one day to choose from, | ||||
|                 or False otherwise. | ||||
|             True if there are more than one day to choose from, or False | ||||
|             otherwise. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return False | ||||
| @@ -313,33 +316,35 @@ class Period: | ||||
|             return False | ||||
|         return True | ||||
|  | ||||
|     def first_day(self): | ||||
|     def first_day(self) -> Optional[str]: | ||||
|         """Returns the specification of the available first day. | ||||
|  | ||||
|         Returns: | ||||
|             str: The specification of the available first day. | ||||
|             The specification of the available first day, or None if there is | ||||
|             no data. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
|         return dateformat.format(self._data_start, "Y-m-d") | ||||
|  | ||||
|     def last_day(self): | ||||
|     def last_day(self) -> Optional[str]: | ||||
|         """Returns the specification of the available last day. | ||||
|  | ||||
|         Returns: | ||||
|             str: The specification of the available last day. | ||||
|             The specification of the available last day, or None if there is no | ||||
|             data. | ||||
|         """ | ||||
|         if self._data_end is None: | ||||
|             return None | ||||
|         return dateformat.format(self._data_end, "Y-m-d") | ||||
|  | ||||
|     def chosen_start(self): | ||||
|     def chosen_start(self) -> Optional[str]: | ||||
|         """Returns the specification of of the first day of the | ||||
|         specified period. | ||||
|  | ||||
|         Returns: | ||||
|             str: The specification of of the first day of the | ||||
|                 specified period. | ||||
|             The specification of of the first day of the specified period, or | ||||
|             None if there is no data. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -348,13 +353,13 @@ class Period: | ||||
|             else self._data_start | ||||
|         return dateformat.format(day, "Y-m-d") | ||||
|  | ||||
|     def chosen_end(self): | ||||
|     def chosen_end(self) -> Optional[str]: | ||||
|         """Returns the specification of of the last day of the | ||||
|         specified period. | ||||
|  | ||||
|         Returns: | ||||
|             str: The specification of of the last day of the | ||||
|                 specified period. | ||||
|             The specification of of the last day of the specified period, or | ||||
|             None if there is data. | ||||
|         """ | ||||
|         if self._data_end is None: | ||||
|             return None | ||||
| @@ -363,12 +368,12 @@ class Period: | ||||
|             else self._data_end | ||||
|         return dateformat.format(day, "Y-m-d") | ||||
|  | ||||
|     def period_before(self): | ||||
|     def period_before(self) -> Optional[str]: | ||||
|         """Returns the specification of the period before the current period. | ||||
|  | ||||
|         Returns: | ||||
|             str|None: The specification of the period before the current | ||||
|                 period, or None if there is no data before the current period. | ||||
|             The specification of the period before the current period, or None | ||||
|             if there is no data before the current period. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -381,11 +386,12 @@ class Period: | ||||
|             return dateformat.format(previous_day, "-Y-m") | ||||
|         return dateformat.format(previous_day, "-Y-m-d") | ||||
|  | ||||
|     def month_picker_params(self): | ||||
|     def month_picker_params(self) -> Optional[str]: | ||||
|         """Returns the parameters for the month-picker, as a JSON text string. | ||||
|  | ||||
|         Returns: | ||||
|             str: The parameters for the month-picker, as a JSON text string. | ||||
|             The parameters for the month-picker, as a JSON text string, or None | ||||
|             if there is no data. | ||||
|         """ | ||||
|         if self._data_start is None: | ||||
|             return None | ||||
| @@ -398,7 +404,7 @@ class Period: | ||||
|         }) | ||||
|  | ||||
|     @staticmethod | ||||
|     def default_spec(): | ||||
|     def default_spec() -> str: | ||||
|         """Returns the specification for the default period. | ||||
|  | ||||
|         Returns: | ||||
| @@ -422,9 +428,9 @@ class Period: | ||||
|             description (str): The text description of the period. | ||||
|             prep_desc (str): The text description with preposition. | ||||
|         """ | ||||
|         VERY_START = datetime.date(1990, 1, 1) | ||||
|         VERY_START: datetime.date = datetime.date(1990, 1, 1) | ||||
|  | ||||
|         def __init__(self, spec): | ||||
|         def __init__(self, spec: str): | ||||
|             self.spec = None | ||||
|             self.start = None | ||||
|             self.end = None | ||||
| @@ -574,7 +580,7 @@ class Period: | ||||
|             # Wrong period format | ||||
|             raise ValueError | ||||
|  | ||||
|         def _set_this_month(self): | ||||
|         def _set_this_month(self) -> None: | ||||
|             """Sets the period to this month.""" | ||||
|             today = timezone.localdate() | ||||
|             self.spec = dateformat.format(today, "Y-m") | ||||
| @@ -583,14 +589,14 @@ class Period: | ||||
|             self.description = gettext("This Month") | ||||
|  | ||||
|         @staticmethod | ||||
|         def _month_last_day(day): | ||||
|         def _month_last_day(day: datetime.date) -> datetime.date: | ||||
|             """Calculates and returns the last day of a month. | ||||
|  | ||||
|             Args: | ||||
|                 day (datetime.date): A day in the month. | ||||
|                 day: A day in the month. | ||||
|  | ||||
|             Returns: | ||||
|                 date: The last day in the month | ||||
|                 The last day in the month | ||||
|             """ | ||||
|             next_month = day.month + 1 | ||||
|             next_year = day.year | ||||
| @@ -601,15 +607,15 @@ class Period: | ||||
|                 next_year, next_month, 1) - datetime.timedelta(days=1) | ||||
|  | ||||
|         @staticmethod | ||||
|         def _month_text(year, month): | ||||
|         def _month_text(year: int, month: int) -> str: | ||||
|             """Returns the text description of a month. | ||||
|  | ||||
|             Args: | ||||
|                 year (int): The year. | ||||
|                 month (int): The month. | ||||
|                 year: The year. | ||||
|                 month: The month. | ||||
|  | ||||
|             Returns: | ||||
|                 str: The description of the month. | ||||
|                 The description of the month. | ||||
|             """ | ||||
|             today = timezone.localdate() | ||||
|             if year == today.year and month == today.month: | ||||
| @@ -625,14 +631,14 @@ class Period: | ||||
|             return "%d/%d" % (year, month) | ||||
|  | ||||
|         @staticmethod | ||||
|         def _year_text(year): | ||||
|         def _year_text(year: int) -> str: | ||||
|             """Returns the text description of a year. | ||||
|  | ||||
|             Args: | ||||
|                 year (int): The year. | ||||
|                 year: The year. | ||||
|  | ||||
|             Returns: | ||||
|                 str: The description of the year. | ||||
|                 The description of the year. | ||||
|             """ | ||||
|             this_year = timezone.localdate().year | ||||
|             if year == this_year: | ||||
| @@ -642,14 +648,14 @@ class Period: | ||||
|             return str(year) | ||||
|  | ||||
|         @staticmethod | ||||
|         def _date_text(day): | ||||
|         def _date_text(day: datetime.date) -> str: | ||||
|             """Returns the text description of a day. | ||||
|  | ||||
|             Args: | ||||
|                 day (datetime.date): The date. | ||||
|                 day: The date. | ||||
|  | ||||
|             Returns: | ||||
|                 str: The description of the day. | ||||
|                 The description of the day. | ||||
|             """ | ||||
|             today = timezone.localdate() | ||||
|             if day == today: | ||||
|   | ||||
| @@ -19,16 +19,18 @@ | ||||
|  | ||||
| """ | ||||
| import random | ||||
| from typing import Dict, Mapping, Any, Optional | ||||
|  | ||||
| from django.http import HttpResponseRedirect | ||||
| from django.http import HttpResponseRedirect, HttpRequest | ||||
| from django.shortcuts import redirect | ||||
|  | ||||
| from .utils import UrlBuilder | ||||
|  | ||||
| STORAGE_KEY = "stored_post" | ||||
| STORAGE_KEY: str = "stored_post" | ||||
|  | ||||
|  | ||||
| def error_redirect(request, url, post): | ||||
| def error_redirect(request: HttpRequest, url: str, | ||||
|                    post: Dict[str, str]) -> HttpResponseRedirect: | ||||
|     """Redirects to a specific URL on error, with the POST data ID appended | ||||
|     as the query parameter "s".  The POST data can be loaded with the | ||||
|     get_previous_post() utility. | ||||
| @@ -45,7 +47,7 @@ def error_redirect(request, url, post): | ||||
|     return redirect(str(UrlBuilder(url).query(s=post_id))) | ||||
|  | ||||
|  | ||||
| def get_previous_post(request): | ||||
| def get_previous_post(request: HttpRequest) -> Optional[Dict[str, str]]: | ||||
|     """Retrieves the previously-stored POST data. | ||||
|  | ||||
|     Args: | ||||
| @@ -59,16 +61,16 @@ def get_previous_post(request): | ||||
|     return _retrieve(request, request.GET["s"]) | ||||
|  | ||||
|  | ||||
| def _store(request, post): | ||||
| def _store(request: HttpRequest, post: Dict[str, str]) -> str: | ||||
|     """Stores the POST data into the session, and returns the POST data ID that | ||||
|     can be used to retrieve it later with _retrieve(). | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         post (dict): The POST data. | ||||
|         request: The request. | ||||
|         post: The POST data. | ||||
|  | ||||
|     Returns: | ||||
|         str: The POST data ID | ||||
|         The POST data ID | ||||
|     """ | ||||
|     if STORAGE_KEY not in request.session: | ||||
|         request.session[STORAGE_KEY] = {} | ||||
| @@ -77,15 +79,15 @@ def _store(request, post): | ||||
|     return post_id | ||||
|  | ||||
|  | ||||
| def _retrieve(request, post_id): | ||||
| def _retrieve(request: HttpRequest, post_id: str) -> Optional[Dict[str, str]]: | ||||
|     """Retrieves the POST data from the storage. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         post_id (str): The POST data ID. | ||||
|         request: The request. | ||||
|         post_id: The POST data ID. | ||||
|  | ||||
|     Returns: | ||||
|         dict: The POST data, or None if the corresponding data does not exist. | ||||
|         The POST data, or None if the corresponding data does not exist. | ||||
|     """ | ||||
|     if STORAGE_KEY not in request.session: | ||||
|         return None | ||||
| @@ -94,7 +96,7 @@ def _retrieve(request, post_id): | ||||
|     return request.session[STORAGE_KEY][post_id] | ||||
|  | ||||
|  | ||||
| def _new_post_id(post_store): | ||||
| def _new_post_id(post_store: Mapping[int, Any]) -> str: | ||||
|     """Generates and returns a new POST ID that does not exist yet. | ||||
|  | ||||
|     Args: | ||||
|   | ||||
| @@ -18,12 +18,14 @@ | ||||
| """The template tags and filters of the Mia core application. | ||||
|  | ||||
| """ | ||||
| import datetime | ||||
| from datetime import date | ||||
| from typing import Any | ||||
|  | ||||
| import titlecase | ||||
| from django import template | ||||
| from django.http import HttpRequest | ||||
| from django.template import defaultfilters | ||||
| from django.template import defaultfilters, RequestContext | ||||
| from django.urls import reverse | ||||
| from django.utils import timezone | ||||
| from django.utils.safestring import SafeString | ||||
| @@ -35,31 +37,31 @@ register = template.Library() | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def setvar(context, key, value): | ||||
| def setvar(context: RequestContext, key: str, value: Any) -> str: | ||||
|     """Sets a variable in the template. | ||||
|  | ||||
|     Args: | ||||
|         context (Context): the context | ||||
|         key (str): The variable name | ||||
|         value (str): The variable value | ||||
|         context: the context | ||||
|         key: The variable name | ||||
|         value: The variable value | ||||
|  | ||||
|     Returns: | ||||
|         str: An empty string. | ||||
|         An empty string. | ||||
|     """ | ||||
|     context.dicts[0][key] = value | ||||
|     return "" | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def url_period(context, period_spec): | ||||
| def url_period(context: RequestContext, period_spec: str) -> str: | ||||
|     """Returns the current URL with a new period. | ||||
|  | ||||
|     Args: | ||||
|         context (RequestContext): The request context. | ||||
|         period_spec (str): The period specification. | ||||
|         context: The request context. | ||||
|         period_spec: The period specification. | ||||
|  | ||||
|     Returns: | ||||
|         str: The current URL with the new period. | ||||
|         The current URL with the new period. | ||||
|     """ | ||||
|     view_name = "%s:%s" % ( | ||||
|         context.request.resolver_match.app_name, | ||||
| @@ -70,47 +72,47 @@ def url_period(context, period_spec): | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def url_with_return(context, url): | ||||
| def url_with_return(context: RequestContext, url: str) -> str: | ||||
|     """Returns the URL with the current page added as the "r" query parameter, | ||||
|     so that returning to this page is possible. | ||||
|  | ||||
|     Args: | ||||
|         context (RequestContext): The request context. | ||||
|         url (str): The URL. | ||||
|         context: The request context. | ||||
|         url: The URL. | ||||
|  | ||||
|     Returns: | ||||
|         str: The URL with the current page added as the "r" query parameter. | ||||
|         The URL with the current page added as the "r" query parameter. | ||||
|     """ | ||||
|     return str(UrlBuilder(url).query( | ||||
|         r=str(UrlBuilder(context.request.get_full_path()).remove("s")))) | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def url_keep_return(context, url): | ||||
| def url_keep_return(context: RequestContext, url: str) -> str: | ||||
|     """Returns the URL with the current "r" query parameter set, so that the | ||||
|     next processor can still return to the same page. | ||||
|  | ||||
|     Args: | ||||
|         context (RequestContext): The request context. | ||||
|         url (str): The URL. | ||||
|         context: The request context. | ||||
|         url: The URL. | ||||
|  | ||||
|     Returns: | ||||
|         str: The URL with the current "r" query parameter set. | ||||
|         The URL with the current "r" query parameter set. | ||||
|     """ | ||||
|     return str(UrlBuilder(url).query(r=context.request.GET.get("r"))) | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def add_css(context, url): | ||||
| def add_css(context: RequestContext, url: str) -> str: | ||||
|     """Adds a local CSS file.  The file is added to the "css" template | ||||
|     list variable. | ||||
|  | ||||
|     Args: | ||||
|         context (RequestContext): The request context. | ||||
|         url (str): The URL or path of the CSS file. | ||||
|         context: The request context. | ||||
|         url: The URL or path of the CSS file. | ||||
|  | ||||
|     Returns: | ||||
|         str: An empty string | ||||
|         An empty string | ||||
|     """ | ||||
|     if "css" not in context.dicts[0]: | ||||
|         context.dicts[0]["css"] = [] | ||||
| @@ -119,16 +121,16 @@ def add_css(context, url): | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def add_js(context, url): | ||||
| def add_js(context: RequestContext, url: str) -> str: | ||||
|     """Adds a local JavaScript file.  The file is added to the "js" template | ||||
|     list variable. | ||||
|  | ||||
|     Args: | ||||
|         context (RequestContext): The request context. | ||||
|         url (str): The URL or path of the JavaScript file. | ||||
|         context: The request context. | ||||
|         url: The URL or path of the JavaScript file. | ||||
|  | ||||
|     Returns: | ||||
|         str: An empty string | ||||
|         An empty string | ||||
|     """ | ||||
|     if "js" not in context.dicts[0]: | ||||
|         context.dicts[0]["js"] = [] | ||||
| @@ -137,14 +139,14 @@ def add_js(context, url): | ||||
|  | ||||
|  | ||||
| @register.filter | ||||
| def smart_date(value): | ||||
| def smart_date(value: datetime.date) -> str: | ||||
|     """Formats the date for human friendliness. | ||||
|  | ||||
|     Args: | ||||
|         value (datetime.date): The date. | ||||
|         value: The date. | ||||
|  | ||||
|     Returns: | ||||
|         str: The human-friendly format of the date. | ||||
|         The human-friendly format of the date. | ||||
|     """ | ||||
|     if value == date.today(): | ||||
|         return gettext("Today") | ||||
| @@ -156,14 +158,14 @@ def smart_date(value): | ||||
|  | ||||
|  | ||||
| @register.filter | ||||
| def smart_month(value): | ||||
| def smart_month(value: datetime.date) -> str: | ||||
|     """Formats the month for human friendliness. | ||||
|  | ||||
|     Args: | ||||
|         value (datetime.date): The month. | ||||
|         value: The month. | ||||
|  | ||||
|     Returns: | ||||
|         str: The human-friendly format of the month. | ||||
|         The human-friendly format of the month. | ||||
|     """ | ||||
|     today = timezone.localdate() | ||||
|     if value.year == today.year and value.month == today.month: | ||||
| @@ -179,14 +181,14 @@ def smart_month(value): | ||||
|  | ||||
|  | ||||
| @register.filter | ||||
| def title_case(value): | ||||
| def title_case(value: str) -> str: | ||||
|     """Formats the title in a proper American-English case. | ||||
|  | ||||
|     Args: | ||||
|         value (str): The title. | ||||
|         value: The title. | ||||
|  | ||||
|     Returns: | ||||
|         str: The title in a proper American-English case. | ||||
|         The title in a proper American-English case. | ||||
|     """ | ||||
|     value = str(value) | ||||
|     if isinstance(value, SafeString): | ||||
| @@ -195,16 +197,15 @@ def title_case(value): | ||||
|  | ||||
|  | ||||
| @register.filter | ||||
| def is_in_section(request, section_name): | ||||
| def is_in_section(request: HttpRequest, section_name: str) -> bool: | ||||
|     """Returns whether the request is currently in a section. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         section_name (str): The view name of this section. | ||||
|         request: The request. | ||||
|         section_name: The view name of this section. | ||||
|  | ||||
|     Returns: | ||||
|         bool: True if the request is currently in this section, or False | ||||
|             otherwise | ||||
|         True if the request is currently in this section, or False otherwise. | ||||
|     """ | ||||
|     if request is None: | ||||
|         return False | ||||
|   | ||||
| @@ -20,20 +20,22 @@ | ||||
| """ | ||||
| import random | ||||
| import urllib.parse | ||||
| from typing import Dict, List, Any, Type | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.db.models import Model, Q | ||||
| from django.http import HttpRequest | ||||
| from django.utils.translation import pgettext, get_language | ||||
|  | ||||
|  | ||||
| def new_pk(cls): | ||||
| def new_pk(cls: Type[Model]) -> int: | ||||
|     """Finds a random ID that does not conflict with the existing data records. | ||||
|  | ||||
|     Args: | ||||
|         cls (class): The Django model class. | ||||
|         cls: The Django model class. | ||||
|  | ||||
|     Returns: | ||||
|          int: The new random ID. | ||||
|          The new random ID. | ||||
|     """ | ||||
|     while True: | ||||
|         pk = random.randint(100000000, 999999999) | ||||
| @@ -43,7 +45,7 @@ def new_pk(cls): | ||||
|             return pk | ||||
|  | ||||
|  | ||||
| def strip_post(post): | ||||
| def strip_post(post: Dict[str, str]) -> None: | ||||
|     """Strips the values of the POSTed data.  Empty strings are removed. | ||||
|  | ||||
|     Args: | ||||
| @@ -59,7 +61,7 @@ class Language: | ||||
|     """A language. | ||||
|  | ||||
|     Args: | ||||
|         language (str): The Django language code. | ||||
|         language: The Django language code. | ||||
|  | ||||
|     Attributes: | ||||
|         id (str): The language ID | ||||
| @@ -67,7 +69,7 @@ class Language: | ||||
|         locale (str); The locale name of this language. | ||||
|         is_default (bool): Whether this is the default language. | ||||
|     """ | ||||
|     def __init__(self, language): | ||||
|     def __init__(self, language: str): | ||||
|         self.id = language | ||||
|         self.db = "_" + language.lower().replace("-", "_") | ||||
|         if language == "zh-hant": | ||||
| @@ -87,17 +89,18 @@ class Language: | ||||
|         return Language(get_language()) | ||||
|  | ||||
|  | ||||
| def get_multi_lingual_attr(model, name, default=None): | ||||
| def get_multi_lingual_attr(model: Model, name: str, | ||||
|                            default: str = None) -> str: | ||||
|     """Returns a multi-lingual attribute of a data model. | ||||
|  | ||||
|     Args: | ||||
|         model (object): The data model. | ||||
|         name (str): The attribute name. | ||||
|         default (str): The default language. | ||||
|         model: The data model. | ||||
|         name: The attribute name. | ||||
|         default: The default language. | ||||
|  | ||||
|     Returns: | ||||
|         (any): The attribute in this language, or in the default | ||||
|             language if there is no content in the current language. | ||||
|         The attribute in this language, or in the default language if there is | ||||
|         no content in the current language. | ||||
|     """ | ||||
|     language = Language.current() | ||||
|     title = getattr(model, name + language.db) | ||||
| @@ -110,27 +113,27 @@ def get_multi_lingual_attr(model, name, default=None): | ||||
|     return getattr(model, name + Language.default().db) | ||||
|  | ||||
|  | ||||
| def set_multi_lingual_attr(model, name, value): | ||||
| def set_multi_lingual_attr(model: Model, name: str, value: str) -> None: | ||||
|     """Sets a multi-lingual attribute of a data model. | ||||
|  | ||||
|     Args: | ||||
|         model (object): The data model. | ||||
|         name (str): The attribute name. | ||||
|         value (any): The new value | ||||
|         model: The data model. | ||||
|         name: The attribute name. | ||||
|         value: The new value | ||||
|     """ | ||||
|     language = Language.current() | ||||
|     setattr(model, name + language.db, value) | ||||
|  | ||||
|  | ||||
| def get_multi_lingual_search(attr, query): | ||||
| def get_multi_lingual_search(attr: str, query: str) -> Q: | ||||
|     """Returns the query condition on a multi-lingual attribute. | ||||
|  | ||||
|     Args: | ||||
|         attr (str): The base name of the multi-lingual attribute. | ||||
|         query (str): The query. | ||||
|         attr: The base name of the multi-lingual attribute. | ||||
|         query: The query. | ||||
|  | ||||
|     Returns: | ||||
|         Q: The query condition | ||||
|         The query condition | ||||
|     """ | ||||
|     language = Language.current() | ||||
|     if language.is_default: | ||||
| @@ -147,10 +150,10 @@ class UrlBuilder: | ||||
|     """The URL builder. | ||||
|  | ||||
|     Attributes: | ||||
|         base_path (str): the base path | ||||
|         path (str): the base path | ||||
|         params (list[Param]): The query parameters | ||||
|     """ | ||||
|     def __init__(self, start_url): | ||||
|     def __init__(self, start_url: str): | ||||
|         """Constructs a new URL builder. | ||||
|  | ||||
|         Args: | ||||
| @@ -158,10 +161,10 @@ class UrlBuilder: | ||||
|         """ | ||||
|         pos = start_url.find("?") | ||||
|         if pos == -1: | ||||
|             self.base_path = start_url | ||||
|             self.path = start_url | ||||
|             self.params = [] | ||||
|             return | ||||
|         self.base_path = start_url[:pos] | ||||
|         self.path = start_url[:pos] | ||||
|         self.params = [] | ||||
|         for piece in start_url[pos + 1:].split("&"): | ||||
|             pos = piece.find("=") | ||||
| @@ -219,25 +222,25 @@ class UrlBuilder: | ||||
|         Returns: | ||||
|             UrlBuilder: A copy of this URL builder. | ||||
|         """ | ||||
|         another = UrlBuilder(self.base_path) | ||||
|         another = UrlBuilder(self.path) | ||||
|         another.params = [ | ||||
|             self.Param(x.name, x.value) for x in self.params] | ||||
|         return another | ||||
|  | ||||
|     def __str__(self): | ||||
|     def __str__(self) -> str: | ||||
|         if len(self.params) == 0: | ||||
|             return self.base_path | ||||
|         return self.base_path + "?" + "&".join([ | ||||
|             return self.path | ||||
|         return self.path + "?" + "&".join([ | ||||
|             str(x) for x in self.params]) | ||||
|  | ||||
|     class Param: | ||||
|         """A query parameter. | ||||
|  | ||||
|         Attributes: | ||||
|             name (str): The parameter name | ||||
|             value (str): The parameter value | ||||
|             name: The parameter name | ||||
|             value: The parameter value | ||||
|         """ | ||||
|         def __init__(self, name, value): | ||||
|         def __init__(self, name: str, value: str): | ||||
|             """Constructs a new query parameter | ||||
|  | ||||
|             Args: | ||||
| @@ -247,7 +250,7 @@ class UrlBuilder: | ||||
|             self.name = name | ||||
|             self.value = value | ||||
|  | ||||
|         def __str__(self): | ||||
|         def __str__(self) -> str: | ||||
|             """Returns the string representation of this query | ||||
|             parameter. | ||||
|  | ||||
| @@ -264,9 +267,9 @@ class Pagination: | ||||
|     """The pagination. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         items (list): All the items. | ||||
|         is_reversed (bool): Whether we should display the last page first. | ||||
|         request: The request. | ||||
|         items: All the items. | ||||
|         is_reversed: Whether we should display the last page first. | ||||
|  | ||||
|     Raises: | ||||
|         PaginationException: With invalid pagination parameters | ||||
| @@ -282,7 +285,8 @@ class Pagination: | ||||
|     """ | ||||
|     DEFAULT_PAGE_SIZE = 10 | ||||
|  | ||||
|     def __init__(self, request, items, is_reversed=False): | ||||
|     def __init__(self, request: HttpRequest, items: List[Any], | ||||
|                  is_reversed: bool = False): | ||||
|         self.current_url = UrlBuilder(request.get_full_path()) | ||||
|         self.is_reversed = is_reversed | ||||
|         self.page_size = self.DEFAULT_PAGE_SIZE | ||||
| @@ -334,7 +338,7 @@ class Pagination: | ||||
|         """Returns the navigation links of the pagination bar. | ||||
|  | ||||
|         Returns: | ||||
|             list[Link]: The navigation links of the pagination bar. | ||||
|             List[Link]: The navigation links of the pagination bar. | ||||
|         """ | ||||
|         base_url = self.current_url.clone().remove("page").remove("s") | ||||
|         links = [] | ||||
| @@ -443,14 +447,14 @@ class Pagination: | ||||
|         """Returns the page size options. | ||||
|  | ||||
|         Returns: | ||||
|             list[PageSizeOption]: The page size options. | ||||
|             List[PageSizeOption]: The page size options. | ||||
|         """ | ||||
|         base_url = self.current_url.remove("page").remove("page-size") | ||||
|         return [self.PageSizeOption(x, self._page_size_url(base_url, x)) | ||||
|                 for x in [10, 100, 200]] | ||||
|  | ||||
|     @staticmethod | ||||
|     def _page_size_url(base_url, size): | ||||
|     def _page_size_url(base_url: UrlBuilder, size: int) -> str: | ||||
|         """Returns the URL for a new page size. | ||||
|  | ||||
|         Args: | ||||
| @@ -468,14 +472,14 @@ class Pagination: | ||||
|         """A page size option. | ||||
|  | ||||
|         Args: | ||||
|             size (int): The page size. | ||||
|             url (str): The URL of this page size. | ||||
|             size: The page size. | ||||
|             url: The URL of this page size. | ||||
|  | ||||
|         Attributes: | ||||
|             size (int): The page size. | ||||
|             url (str): The URL for this page size. | ||||
|         """ | ||||
|         def __init__(self, size, url): | ||||
|         def __init__(self, size: int, url: str): | ||||
|             self.size = size | ||||
|             self.url = url | ||||
|  | ||||
| @@ -484,10 +488,10 @@ class PaginationException(Exception): | ||||
|     """The exception thrown with invalid pagination parameters. | ||||
|  | ||||
|     Args: | ||||
|         url_builder (UrlBuilder): The canonical URL to redirect to. | ||||
|         url_builder: The canonical URL to redirect to. | ||||
|  | ||||
|     Attributes: | ||||
|         url (str): The canonical URL to redirect to. | ||||
|     """ | ||||
|     def __init__(self, url_builder): | ||||
|     def __init__(self, url_builder: UrlBuilder): | ||||
|         self.url = str(url_builder) | ||||
|   | ||||
| @@ -21,7 +21,8 @@ | ||||
| from django.contrib import messages | ||||
| from django.contrib.auth import logout as logout_user | ||||
| from django.contrib.messages.views import SuccessMessageMixin | ||||
| from django.http import HttpResponse, JsonResponse | ||||
| from django.http import HttpResponse, JsonResponse, HttpRequest, \ | ||||
|     HttpResponseRedirect | ||||
| from django.shortcuts import redirect, render | ||||
| from django.urls import reverse | ||||
| from django.utils.decorators import method_decorator | ||||
| @@ -47,14 +48,14 @@ class DeleteView(SuccessMessageMixin, CoreDeleteView): | ||||
|  | ||||
|  | ||||
| @require_POST | ||||
| def logout(request): | ||||
| def logout(request: HttpRequest) -> HttpResponseRedirect: | ||||
|     """The view to log out a user. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         request: The request. | ||||
|  | ||||
|     Returns: | ||||
|         HttpRedirectResponse: The redirect response. | ||||
|         The redirect response. | ||||
|     """ | ||||
|     logout_user(request) | ||||
|     if "next" in request.POST: | ||||
| @@ -80,15 +81,15 @@ class UserView(DetailView): | ||||
|  | ||||
| @require_GET | ||||
| @login_required | ||||
| def user_form(request, user=None): | ||||
| def user_form(request: HttpRequest, user: User = None) -> HttpResponse: | ||||
|     """The view to edit an accounting transaction. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         user (User): The account. | ||||
|         request: The request. | ||||
|         user: The account. | ||||
|  | ||||
|     Returns: | ||||
|         HttpResponse: The response. | ||||
|         The response. | ||||
|     """ | ||||
|     previous_post = stored_post.get_previous_post(request) | ||||
|     if previous_post is not None: | ||||
| @@ -108,15 +109,16 @@ def user_form(request, user=None): | ||||
|     }) | ||||
|  | ||||
|  | ||||
| def user_store(request, user=None): | ||||
| def user_store(request: HttpRequest, | ||||
|                user: User = None) -> HttpResponseRedirect: | ||||
|     """The view to store a user. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         user (Account): The user. | ||||
|         request: The request. | ||||
|         user: The user. | ||||
|  | ||||
|     Returns: | ||||
|         HttpResponseRedirect: The response. | ||||
|         The response. | ||||
|     """ | ||||
|     post = request.POST.dict() | ||||
|     strip_post(post) | ||||
| @@ -148,15 +150,15 @@ def user_store(request, user=None): | ||||
|  | ||||
| @require_POST | ||||
| @login_required | ||||
| def user_delete(request, user): | ||||
| def user_delete(request: HttpRequest, user: User) -> HttpResponseRedirect: | ||||
|     """The view to delete an user. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         user (User): The user. | ||||
|         request: The request. | ||||
|         user: The user. | ||||
|  | ||||
|     Returns: | ||||
|         HttpResponseRedirect: The response. | ||||
|         The response. | ||||
|     """ | ||||
|     message = None | ||||
|     if user.pk == request.user.pk: | ||||
| @@ -177,14 +179,14 @@ def user_delete(request, user): | ||||
|  | ||||
| @require_GET | ||||
| @login_required | ||||
| def my_account_form(request): | ||||
| def my_account_form(request: HttpRequest) -> HttpResponse: | ||||
|     """The view to edit my account. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         request: The request. | ||||
|  | ||||
|     Returns: | ||||
|         HttpResponse: The response. | ||||
|         The response. | ||||
|     """ | ||||
|     previous_post = stored_post.get_previous_post(request) | ||||
|     if previous_post is not None: | ||||
| @@ -201,14 +203,14 @@ def my_account_form(request): | ||||
|     }) | ||||
|  | ||||
|  | ||||
| def my_account_store(request): | ||||
| def my_account_store(request: HttpRequest) -> HttpResponseRedirect: | ||||
|     """The view to store my account. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         request: The request. | ||||
|  | ||||
|     Returns: | ||||
|         HttpResponseRedirect: The response. | ||||
|         The response. | ||||
|     """ | ||||
|     post = request.POST.dict() | ||||
|     strip_post(post) | ||||
| @@ -232,15 +234,15 @@ def my_account_store(request): | ||||
|     return redirect("mia_core:my-account") | ||||
|  | ||||
|  | ||||
| def api_users_exists(request, login_id): | ||||
| def api_users_exists(request: HttpRequest, login_id: str) -> JsonResponse: | ||||
|     """The view to check whether a user with a log in ID exists. | ||||
|  | ||||
|     Args: | ||||
|         request (HttpRequest): The request. | ||||
|         login_id (str): The log in ID. | ||||
|         request: The request. | ||||
|         login_id: The log in ID. | ||||
|  | ||||
|     Returns: | ||||
|         JsonResponse: The response. | ||||
|         The response. | ||||
|     """ | ||||
|     try: | ||||
|         User.objects.get(login_id=login_id) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user