From 02678b7ccdae2cd173d9723ca4149d09ca844000 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sat, 25 Apr 2020 03:36:27 +0200 Subject: [PATCH] First step of docstring translation --- re2o/base.py | 4 +- re2o/context_processors.py | 19 +++-- re2o/field_permissions.py | 8 +- re2o/login.py | 48 ++++++++++- re2o/mail_utils.py | 2 +- re2o/mixins.py | 81 ++++++++++++------ re2o/script_utils.py | 25 ++++-- re2o/utils.py | 166 +++++++++++++++++++++++++++++++------ re2o/views.py | 22 ++++- 9 files changed, 300 insertions(+), 75 deletions(-) diff --git a/re2o/base.py b/re2o/base.py index d9e3efa5..c2863643 100644 --- a/re2o/base.py +++ b/re2o/base.py @@ -21,9 +21,7 @@ # -*- coding: utf-8 -*- """ -Regroupe les fonctions transversales utiles - -Et non corrélées/dépendantes des autres applications +Global independant usefull functions """ import smtplib diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 4bda6712..b6c54e22 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -19,7 +19,7 @@ # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -"""Fonction de context, variables renvoyées à toutes les vues""" +"""Context functions, runs and results sends globaly to all templates""" from __future__ import unicode_literals @@ -34,8 +34,12 @@ from re2o.settings_local import OPTIONNAL_APPS_RE2O def context_user(request): - """Fonction de context lorsqu'un user est logué (ou non), - renvoie les infos sur l'user, la liste de ses droits, ses machines""" + """Global Context function + + Returns: + dict:Containing user's interfaces and himself if logged, else None + + """ user = request.user if get_language() == "fr": global_message = GeneralOption.get_cached_value("general_message_fr") @@ -61,8 +65,13 @@ def context_user(request): def context_optionnal_apps(request): - """Fonction de context pour générer la navbar en fonction des - apps optionnels""" + """Context functions. Called to add optionnal apps buttons in navbari + + Returns: + dict:Containing optionnal template list of functions for navbar found + in optional apps + + """ optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_templates_navbar_user_list = [ app.views.navbar_user() diff --git a/re2o/field_permissions.py b/re2o/field_permissions.py index 90a904be..b55248b3 100644 --- a/re2o/field_permissions.py +++ b/re2o/field_permissions.py @@ -85,7 +85,13 @@ class FieldPermissionModelMixin: class FieldPermissionFormMixin: """ - Construit le formulaire et retire les champs interdits + Build a form, and remove all forbiden fields + + Parameters: + user:Build-in with a Django Form instance, and parameter user in kwargs, + representing calling user for this form. Then test if a field is forbiden + or not with has_field_paremeter model function + """ def __init__(self, *args, **kwargs): diff --git a/re2o/login.py b/re2o/login.py index e7b385b1..1dae9073 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -45,7 +45,14 @@ DIGEST_LEN = 20 def makeSecret(password): - """ Build a hashed and salted version of the password """ + """ Build a hashed and salted version of the password with SSHA + + Parameters: + password (string): Password to hash + + Returns: + string: Hashed password + """ salt = os.urandom(4) h = hashlib.sha1(password.encode()) h.update(salt) @@ -53,13 +60,30 @@ def makeSecret(password): def hashNT(password): - """ Build a md4 hash of the password to use as the NT-password """ + """ Build a md4 hash of the password to use as the NT-password + + Parameters: + password (string): Password to hash + + Returns: + string: Hashed password + + """ hash_str = hashlib.new("md4", password.encode("utf-16le")).digest() return binascii.hexlify(hash_str).upper() def checkPassword(challenge_password, password): - """ Check if a given password match the hash of a stored password """ + """Check if a given password match the hash of a stored password + + Parameters: + challenge_password (string): Password to verify with hash + password (string): Hashed password to verify + + Returns: + boolean: True if challenge_password and password match + + """ challenge_bytes = decodestring(challenge_password[ALGO_LEN:].encode()) digest = challenge_bytes[:DIGEST_LEN] salt = challenge_bytes[DIGEST_LEN:] @@ -69,7 +93,15 @@ def checkPassword(challenge_password, password): def hash_password_salt(hashed_password): - """ Extract the salt from a given hashed password """ + """ Extract the salt from a given hashed password + + Parameters: + hashed_password (string): Hashed password to extract salt + + Returns: + string: Salt of the password + + """ if hashed_password.upper().startswith("{CRYPT}"): hashed_password = hashed_password[7:] if hashed_password.startswith("$"): @@ -243,6 +275,14 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher): class RecryptBackend(ModelBackend): + """Function for legacy users. During auth, if their hash password is different from SSHA or ntlm + password is empty, rehash in SSHA or NTLM + + Returns: + model user instance: Instance of the user logged + + """ + def authenticate(self, username=None, password=None): # we obtain from the classical auth backend the user user = super(RecryptBackend, self).authenticate(None, username, password) diff --git a/re2o/mail_utils.py b/re2o/mail_utils.py index 69d0cfff..2e104ec5 100644 --- a/re2o/mail_utils.py +++ b/re2o/mail_utils.py @@ -22,7 +22,7 @@ # -*- coding: utf-8 -*- # Jean-Romain Garnier """ -Regroupe les fonctions en lien avec les mails +All functions linked with emails here. Non model or app dependant """ from django.utils.translation import ugettext_lazy as _ diff --git a/re2o/mixins.py b/re2o/mixins.py index 77382933..c091a6d9 100644 --- a/re2o/mixins.py +++ b/re2o/mixins.py @@ -93,16 +93,27 @@ class AclMixin(object): @classmethod def get_instance(cls, object_id, *_args, **kwargs): - """Récupère une instance - :return: Une instance de la classe évidemment""" + """Get an instance from its id. + + Parameters: + object_id (int): Id of the instance to find + + Returns: + Django instance: Instance of this class + """ return cls.objects.get(pk=object_id) @classmethod def can_create(cls, user_request, *_args, **_kwargs): - """Verifie que l'user a les bons droits pour créer - un object - :param user_request: instance utilisateur qui fait la requête - :return: soit True, soit False avec la raison de l'échec""" + """Check if a user has the right to create an object + + Parameters: + user_request: User calling for this action + + Returns: + Boolean: True if user_request has the right access to do it, else + false with reason for reject authorization + """ permission = cls.get_modulename() + ".add_" + cls.get_classname() can = user_request.has_perm(permission) return ( @@ -114,11 +125,16 @@ class AclMixin(object): ) def can_edit(self, user_request, *_args, **_kwargs): - """Verifie que l'user a les bons droits pour editer - cette instance - :param self: Instance à editer - :param user_request: Utilisateur qui fait la requête - :return: soit True, soit False avec la raison de l'échec""" + """Check if a user has the right to edit an instance + + Parameters: + user_request: User calling for this action + self: Instance to edit + + Returns: + Boolean: True if user_request has the right access to do it, else + false with reason for reject authorization + """ permission = self.get_modulename() + ".change_" + self.get_classname() can = user_request.has_perm(permission) return ( @@ -130,11 +146,16 @@ class AclMixin(object): ) def can_delete(self, user_request, *_args, **_kwargs): - """Verifie que l'user a les bons droits pour delete - cette instance - :param self: Instance à delete - :param user_request: Utilisateur qui fait la requête - :return: soit True, soit False avec la raison de l'échec""" + """Check if a user has the right to delete an instance + + Parameters: + user_request: User calling for this action + self: Instance to delete + + Returns: + Boolean: True if user_request has the right access to do it, else + false with reason for reject authorization + """ permission = self.get_modulename() + ".delete_" + self.get_classname() can = user_request.has_perm(permission) return ( @@ -147,10 +168,15 @@ class AclMixin(object): @classmethod def can_view_all(cls, user_request, *_args, **_kwargs): - """Vérifie qu'on peut bien afficher l'ensemble des objets, - droit particulier view objet correspondant - :param user_request: instance user qui fait l'edition - :return: True ou False avec la raison de l'échec le cas échéant""" + """Check if a user can view all instances of an object + + Parameters: + user_request: User calling for this action + + Returns: + Boolean: True if user_request has the right access to do it, else + false with reason for reject authorization + """ permission = cls.get_modulename() + ".view_" + cls.get_classname() can = user_request.has_perm(permission) return ( @@ -162,11 +188,16 @@ class AclMixin(object): ) def can_view(self, user_request, *_args, **_kwargs): - """Vérifie qu'on peut bien voir cette instance particulière avec - droit view objet - :param self: instance à voir - :param user_request: instance user qui fait l'edition - :return: True ou False avec la raison de l'échec le cas échéant""" + """Check if a user can view an instance of an object + + Parameters: + user_request: User calling for this action + self: Instance to view + + Returns: + Boolean: True if user_request has the right access to do it, else + false with reason for reject authorization + """ permission = self.get_modulename() + ".view_" + self.get_classname() can = user_request.has_perm(permission) return ( diff --git a/re2o/script_utils.py b/re2o/script_utils.py index c6adbeab..667e38d3 100644 --- a/re2o/script_utils.py +++ b/re2o/script_utils.py @@ -47,7 +47,15 @@ application = get_wsgi_application() def get_user(pseudo): - """Cherche un utilisateur re2o à partir de son pseudo""" + """Find a user from its pseudo + + Parameters: + pseudo (string): pseudo of this user + + Returns: + user instance:Instance of user + + """ user = User.objects.filter(pseudo=pseudo) if len(user) == 0: raise CommandError("Invalid user.") @@ -59,17 +67,20 @@ def get_user(pseudo): def get_system_user(): - """Retourne l'utilisateur système ayant lancé la commande""" + """Find the system user login who used the command + """ return pwd.getpwuid(int(os.getenv("SUDO_UID") or os.getuid())).pw_name def form_cli(Form, user, action, *args, **kwargs): """ - Remplit un formulaire à partir de la ligne de commande - Form : le formulaire (sous forme de classe) à remplir - user : l'utilisateur re2o faisant la modification - action : l'action réalisée par le formulaire (pour les logs) - Les arguments suivants sont transmis tels quels au formulaire. + Fill-in a django form from cli + + Parameters + Form : a django class form to fill-in + user : a re2o user doign the modification + action: the action done with that form, for logs purpose + """ data = {} dumb_form = Form(user=user, *args, **kwargs) diff --git a/re2o/utils.py b/re2o/utils.py index d41bcf9d..7d43e883 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -24,12 +24,12 @@ # -*- coding: utf-8 -*- # David Sinquin, Gabriel Détraz, Lara Kermarec """ -Regroupe les fonctions transversales utiles +A group of very usefull functions for re2o core -Fonction : - - récupérer tous les utilisateurs actifs - - récupérer toutes les machines - - récupérer tous les bans +Functions: + - find all active users + - find all active interfaces + - find all bans etc """ @@ -47,7 +47,14 @@ from preferences.models import AssoOption def get_group_having_permission(*permission_name): - """Returns every group having the permission `permission_name` + """Return all django groups having this permission + + Parameters: + permission name (string): Permission name + + Returns: + re2o groups: Groups having this permission + """ groups = set() for name in permission_name: @@ -60,10 +67,19 @@ def get_group_having_permission(*permission_name): def all_adherent(search_time=None, including_asso=True): - """ Fonction renvoyant tous les users adherents. Optimisee pour n'est - qu'une seule requete sql - Inspecte les factures de l'user et ses cotisation, regarde si elles - sont posterieur à now (end_time)""" + """Return all people who have a valid membership at org. Optimised to make only one + sql query. Build a filter and then apply it to User. Check for each user if a valid + membership is registered at the desired search_time. + + Parameters: + search_time (django datetime): Datetime to perform this search, + if not provided, search_time will be set à timezone.now() + including_asso (boolean): Decide if org itself is included in results + + Returns: + django queryset: Django queryset containing all users with valid membership + + """ if search_time is None: search_time = timezone.now() filter_user = Q( @@ -86,7 +102,18 @@ def all_adherent(search_time=None, including_asso=True): def all_baned(search_time=None): - """ Fonction renvoyant tous les users bannis """ + """Return all people who are banned at org. Optimised to make only one + sql query. Build a filter and then apply it to User. Check for each user + banned at the desired search_time. + + Parameters: + search_time (django datetime): Datetime to perform this search, + if not provided, search_time will be set à timezone.now() + + Returns: + django queryset: Django queryset containing all users banned + + """ if search_time is None: search_time = timezone.now() return User.objects.filter( @@ -97,7 +124,18 @@ def all_baned(search_time=None): def all_whitelisted(search_time=None): - """ Fonction renvoyant tous les users whitelistes """ + """Return all people who have a free access at org. Optimised to make only one + sql query. Build a filter and then apply it to User. Check for each user with a + whitelisted free access at the desired search_time. + + Parameters: + search_time (django datetime): Datetime to perform this search, + if not provided, search_time will be set à timezone.now() + + Returns: + django queryset: Django queryset containing all users whitelisted + + """ if search_time is None: search_time = timezone.now() return User.objects.filter( @@ -108,11 +146,19 @@ def all_whitelisted(search_time=None): def all_has_access(search_time=None, including_asso=True): - """ Return all connected users : active users and whitelisted + - asso_user defined in AssoOption pannel - ---- - Renvoie tous les users beneficiant d'une connexion - : user adherent et whiteliste non banni plus l'utilisateur asso""" + """Return all people who have an valid internet access at org. Optimised to make + only one sql query. Build a filter and then apply it to User. Return users + with a whitelist, or a valid paid access, except banned users. + + Parameters: + search_time (django datetime): Datetime to perform this search, + if not provided, search_time will be set à timezone.now() + including_asso (boolean): Decide if org itself is included in results + + Returns: + django queryset: Django queryset containing all valid connection users + + """ if search_time is None: search_time = timezone.now() filter_user = ( @@ -153,7 +199,20 @@ def all_has_access(search_time=None, including_asso=True): def filter_active_interfaces(interface_set): - """Filtre les machines autorisées à sortir sur internet dans une requête""" + """Return a filter for filtering all interfaces of people who have an valid + internet access at org. + Call all_active_interfaces and then apply filter of theses active users on an + interfaces_set + + Parameters: + interface_set (django queryset): A queryset of interfaces to perform filter + + Returns: + django filter: Django filter to apply to an interfaces queryset, + will return when applied all active interfaces, related with + a user with valid membership + + """ return ( interface_set.filter( machine__in=Machine.objects.filter(user__in=all_has_access()).filter( @@ -171,12 +230,38 @@ def filter_active_interfaces(interface_set): def filter_complete_interfaces(interface_set): - """Appel la fonction précédente avec un prefetch_related ipv6 en plus""" + """Return a filter for filtering all interfaces of people who have an valid + internet access at org. + Call all_active_interfaces and then apply filter of theses active users on an + interfaces_set. Less efficient than filter_active_interfaces, with a prefetch_related + on ipv6 + + Parameters: + interface_set (django queryset): A queryset of interfaces to perform filter + + Returns: + django filter: Django filter to apply to an interfaces queryset, + will return when applied all active interfaces, related with + a user with valid membership + + """ return filter_active_interfaces(interface_set).prefetch_related("ipv6list") def all_active_interfaces(full=False): - """Renvoie l'ensemble des machines autorisées à sortir sur internet """ + """Return a filter for filtering all interfaces of people who have an valid + internet access at org. + Call filter_active_interfaces or filter_complete_interfaces. + + Parameters: + full (boolean): A queryset of interfaces to perform filter. If true, will perform + a complete filter with filter_complete_interfaces + + Returns: + django queryset: Django queryset containing all active interfaces, related with + a user with valid membership + + """ if full: return filter_complete_interfaces(Interface.objects) else: @@ -184,13 +269,30 @@ def all_active_interfaces(full=False): def all_active_assigned_interfaces(full=False): - """ Renvoie l'ensemble des machines qui ont une ipv4 assignées et - disposant de l'accès internet""" + """Return all interfaces of people who have an valid internet access at org, + and with valid ipv4. + Call filter_active_interfaces or filter_complete_interfaces, with parameter full. + + Parameters: + full (boolean): A queryset of interfaces to perform filter. If true, will perform + a complete filter with filter_complete_interfaces + + Returns: + django queryset: Django queryset containing all active interfaces, related with + a user with valid membership, and with valid assigned ipv4 address + + """ return all_active_interfaces(full=full).filter(ipv4__isnull=False) def all_active_interfaces_count(): - """ Version light seulement pour compter""" + """Counts all interfaces of people who have an valid internet access at org. + + Returns: + int: Number of all active interfaces, related with + a user with valid membership. + + """ return Interface.objects.filter( machine__in=Machine.objects.filter(user__in=all_has_access()).filter( active=True @@ -199,12 +301,26 @@ def all_active_interfaces_count(): def all_active_assigned_interfaces_count(): - """ Version light seulement pour compter""" + """Counts all interfaces of people who have an valid internet access at org, + and with valid ipv4. + + Returns: + int: Number of all active interfaces, related with + a user with valid membership, and with valid assigned ipv4 address + + """ return all_active_interfaces_count().filter(ipv4__isnull=False) def remove_user_room(room, force=True): - """ Déménage de force l'ancien locataire de la chambre """ + """Remove the previous user of that room. If force, will not perform a check + of membership on him before doing it + + Parameters: + room (Room instance): Room to make free of user + force (boolean): If true, bypass membership check + + """ try: user = Adherent.objects.get(room=room) except Adherent.DoesNotExist: diff --git a/re2o/views.py b/re2o/views.py index 1a4caf15..6a65bcec 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -21,8 +21,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ -Fonctions de la page d'accueil et diverses fonctions utiles pour tous -les views +Welcom main page view, and several template widely used in re2o views """ from __future__ import unicode_literals @@ -50,14 +49,29 @@ from re2o.settings_local import OPTIONNAL_APPS_RE2O def form(ctx, template, request): - """Form générique, raccourci importé par les fonctions views du site""" + """Global template function, used in all re2o views, for building a render with context, + template and request. Adding csrf. + + Parameters: + ctx (dict): Dict of values to transfer to template + template (django template): The django template of this view + request (django request) + + Returns: + Django render: Django render complete view with template, context and request + """ context = ctx context.update(csrf(request)) return render(request, template, context) def index(request): - """Affiche la liste des services sur la page d'accueil de re2o""" + """Display all services provided on main page + + Returns: a form with all services linked and description, and social media + link if provided. + + """ services = [[], [], []] for indice, serv in enumerate(Service.objects.all()): services[indice % 3].append(serv)