Compare commits

...

4 commits

Author SHA1 Message Date
9e06b199b5 Better linter score on preference
All checks were successful
/ test (push) Successful in 47s
/ lint (push) Successful in 1m11s
2025-07-06 13:47:03 +02:00
9f06547759 Better linter score on topologie 2025-07-06 13:47:03 +02:00
21f774a4da Better linter score on logs 2025-07-06 13:47:03 +02:00
8ecf006137 Better linter score on re2o 2025-07-06 13:47:03 +02:00
40 changed files with 360 additions and 410 deletions

View file

@ -36,6 +36,6 @@ from re2o.views import AutocompleteViewMixin
from .models import Banque
# pylint disable=too-many-ancestors
# pylint: disable=too-many-ancestors
class BanqueAutocomplete(AutocompleteViewMixin):
obj_type = Banque

View file

@ -41,6 +41,6 @@ def can_view(user, *args, **kwargs):
can = user.has_module_perms("admin")
return (
can,
None if can else _("You don't have the right to view this" " application."),
None if can else _("You don't have the right to view this application."),
("logs",),
)

View file

@ -30,7 +30,6 @@ from django.utils.translation import ugettext_lazy as _
# Import all models in which there are classes to be filtered on
import cotisations.models
import machines.models
import preferences.models
import topologie.models
import users.models
from re2o.base import get_input_formats_help_text
@ -79,31 +78,24 @@ def classes_for_action_type(action_type):
A list containing the class names corresponding to the action type
filter.
"""
if action_type == "users":
return [
action_type_map = {
"users": [
users.models.User.__name__,
users.models.Adherent.__name__,
users.models.Club.__name__,
users.models.EMailAddress.__name__,
]
],
"machines": [
machines.models.Machine.__name__,
machines.models.Interface.__name__,
],
"subscriptions": [all_classes(cotisations.models)],
"whitelists": [users.models.Whitelist.__name__],
"bans": [users.models.Ban.__name__],
"topology": all_classes(topologie.models),
}
if action_type == "machines":
return [machines.models.Machine.__name__, machines.models.Interface.__name__]
if action_type == "subscriptions":
return all_classes(cotisations.models)
if action_type == "whitelists":
return [users.models.Whitelist.__name__]
if action_type == "bans":
return [users.models.Ban.__name__]
if action_type == "topology":
return all_classes(topologie.models)
# "all" is a special case, just return None
return None
return action_type_map.get(action_type, None)
class ActionsSearchForm(Form):
@ -126,7 +118,7 @@ class ActionsSearchForm(Form):
end_date = forms.DateField(required=False, label=_("End date"))
def __init__(self, *args, **kwargs):
super(ActionsSearchForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields["start_date"].help_text = get_input_formats_help_text(
self.fields["start_date"].input_formats
)
@ -146,7 +138,7 @@ class MachineHistorySearchForm(Form):
e = forms.DateField(required=False, label=_("End date"))
def __init__(self, *args, **kwargs):
super(MachineHistorySearchForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields["s"].help_text = get_input_formats_help_text(
self.fields["s"].input_formats
)

View file

@ -46,13 +46,13 @@ def make_version_filter(key, value):
"""
# The lookup is done in a json string, so it has to be formated
# based on the value's type (to add " or not)
if type(value) is str:
formatted_value = '"{}"'.format(value)
if isinstance(value, str):
formatted_value = f'"{value}"'
else:
formatted_value = str(value)
return Q(serialized_data__contains='"{}": {},'.format(key, formatted_value)) | Q(
serialized_data__contains='"{}": {}}}'.format(key, formatted_value)
return Q(serialized_data__contains=f'"{key}": {formatted_value},') | Q(
serialized_data__contains=f'"{key}": {formatted_value}}}'
)
@ -101,20 +101,15 @@ class MachineHistorySearchEvent:
)
def __repr__(self):
return "{} ({} - ): from {} to {} ({})".format(
self.machine,
self.mac,
self.ipv4,
self.start_date,
self.end_date,
self.comment or "No comment",
)
return f'{self.machine} ({self.mac} - {self.ipv4}): from {self.start_date} to {self.end_date} ({self.comment or "No comment"})'
class MachineHistorySearch:
def __init__(self):
self.events = []
self._last_evt = None
self.start = None
self.end = None
def get(self, search, params):
"""Get the events in machine histories related to the search.
@ -309,7 +304,7 @@ class RelatedHistory:
self.name = version.object_repr
if self.model_name:
self.name = "{}: {}".format(self.model_name.title(), self.name)
self.name = f"{self.model_name.title()}: {self.name}"
def __eq__(self, other):
return self.model_name == other.model_name and self.object_id == other.object_id
@ -336,7 +331,7 @@ class HistoryEvent:
self.performed_by = version.revision.user
self.comment = version.revision.get_comment() or None
def _repr(self, name, value):
def _repr(self, _name, value):
"""Get the appropriate representation of the given field.
Args:
@ -352,16 +347,19 @@ class HistoryEvent:
return value
def edits(self, hide=["password", "pwd_ntlm"]):
def edits(self, hide=None):
"""Get the list of the changes performed during this event.
Args:
hide: the list of fields for which not to show details (default:
[]).
["password", "pwd_ntlm"]).
Returns:
The list of fields edited by the event to display.
"""
if hide is None:
hide = ["password", "pwd_ntlm"]
edits = []
for field in self.edited_fields:
@ -424,7 +422,7 @@ class History:
self.name = self._last_version.object_repr
return self.events[::-1]
def _compute_diff(self, v1, v2, ignoring=[]):
def _compute_diff(self, v1, v2, ignoring=None):
"""Find the edited fields between two versions.
Args:
@ -436,9 +434,12 @@ class History:
The list of field names in v1 that are different from the ones in
v2.
"""
if ignoring is None:
ignoring = []
fields = []
v1_keys = set([k for k in v1.field_dict.keys() if k not in ignoring])
v2_keys = set([k for k in v2.field_dict.keys() if k not in ignoring])
v1_keys = {k for k in v1.field_dict.keys() if k not in ignoring}
v2_keys = {k for k in v2.field_dict.keys() if k not in ignoring}
common_keys = v1_keys.intersection(v2_keys)
fields += list(v2_keys - v1_keys)
@ -478,6 +479,7 @@ class History:
class VersionAction(HistoryEvent):
def __init__(self, version):
super().__init__(version)
self.version = version
def name(self):
@ -495,7 +497,7 @@ class VersionAction(HistoryEvent):
def object_type(self):
return apps.get_model(self.application(), self.model_name())
def edits(self, hide=["password", "pwd_ntlm", "gpg_fingerprint"]):
def edits(self, hide=None):
"""Get the list of the changes performed during this event.
Args:
@ -505,13 +507,16 @@ class VersionAction(HistoryEvent):
Returns:
The list of fields edited by the event to display.
"""
if hide is None:
hide = ["password", "pwd_ntlm", "gpg_fingerprint"]
self.previous_version = self._previous_version()
if self.previous_version is None:
return None, None, None
self.edited_fields = self._compute_diff(self.version, self.previous_version)
return super(VersionAction, self).edits(hide)
return super().edits(hide)
def _previous_version(self):
"""Get the previous version of self.
@ -533,7 +538,7 @@ class VersionAction(HistoryEvent):
except Exception:
return None
def _compute_diff(self, v1, v2, ignoring=["pwd_ntlm"]):
def _compute_diff(self, v1, v2, ignoring=None):
"""Find the edited fields between two versions.
Args:
@ -545,9 +550,12 @@ class VersionAction(HistoryEvent):
The list of field names in v1 that are different from the ones in
v2.
"""
if ignoring is None:
ignoring = ["pwd_ntlm"]
fields = []
v1_keys = set([k for k in v1.field_dict.keys() if k not in ignoring])
v2_keys = set([k for k in v2.field_dict.keys() if k not in ignoring])
v1_keys = {k for k in v1.field_dict.keys() if k not in ignoring}
v2_keys = {k for k in v2.field_dict.keys() if k not in ignoring}
common_keys = v1_keys.intersection(v2_keys)
fields += list(v2_keys - v1_keys)
@ -662,27 +670,25 @@ class UserHistoryEvent(HistoryEvent):
groups.append(Group.objects.get(id=gid).name)
except Group.DoesNotExist:
# TODO: Find the group name in the versions?
groups.append("{} ({})".format(_("Deleted"), gid))
groups.append(f'{_("Deleted")} ({gid})')
return ", ".join(groups)
elif name == "state":
if name == "state":
if value is not None:
return User.STATES[value][1]
else:
return _("Unknown")
elif name == "email_state":
return _("Unknown")
if name == "email_state":
if value is not None:
return User.EMAIL_STATES[value][1]
else:
return _("Unknown")
elif name == "room_id" and value is not None:
return _("Unknown")
if name == "room_id" and value is not None:
# Try to get the room name, if it's not deleted
try:
return Room.objects.get(id=value)
except Room.DoesNotExist:
# TODO: Find the room name in the versions?
return "{} ({})".format(_("Deleted"), value)
elif name == "members" or name == "administrators":
return f'{_("Deleted")} ({value})'
if name in ("members", "administrators"):
if len(value) == 0:
# Removed all the club's members
return _("None")
@ -695,13 +701,13 @@ class UserHistoryEvent(HistoryEvent):
users.append(User.objects.get(id=uid).pseudo)
except User.DoesNotExist:
# TODO: Find the user's name in the versions?
users.append("{} ({})".format(_("Deleted"), uid))
users.append(f'{_("Deleted")} ({uid})')
return ", ".join(users)
return super(UserHistoryEvent, self)._repr(name, value)
return super()._repr(name, value)
def edits(self, hide=["password", "pwd_ntlm", "gpg_fingerprint"]):
def edits(self, hide=None):
"""Get the list of the changes performed during this event.
Args:
@ -711,7 +717,10 @@ class UserHistoryEvent(HistoryEvent):
Returns:
The list of fields edited by the event to display.
"""
return super(UserHistoryEvent, self).edits(hide)
if hide is None:
hide = ["password", "pwd_ntlm", "gpg_fingerprint"]
return super().edits(hide)
def __eq__(self, other):
return (
@ -727,29 +736,26 @@ class UserHistoryEvent(HistoryEvent):
)
def __repr__(self):
return "{} edited fields {} ({})".format(
self.performed_by,
self.edited_fields or "nothing",
self.comment or "No comment",
)
return f'{self.performed_by} edited fields {self.edited_fields or "nothing"} ({self.comment or "No comment"})'
class UserHistory(History):
def __init__(self):
super(UserHistory, self).__init__()
super().__init__()
self.event_type = UserHistoryEvent
def get(self, user_id, model):
def get(self, instance_id, model):
"""Get the the list of UserHistoryEvent related to the object.
Args:
user_id: int, the id of the user to lookup.
instance_id: int, the id of the user to lookup.
Returns:
The list of UserHistoryEvent, in reverse chronological order,
related to the object, or None if nothing was found.
"""
self.events = []
user_id = instance_id
# Try to find an Adherent object
# If it exists, its id will be the same as the user's
@ -858,21 +864,21 @@ class MachineHistoryEvent(HistoryEvent):
try:
return User.objects.get(id=value).pseudo
except User.DoesNotExist:
return "{} ({})".format(_("Deleted"), value)
return f'{_("Deleted")} ({value}))'
return super(MachineHistoryEvent, self)._repr(name, value)
return super()._repr(name, value)
class MachineHistory(History):
def __init__(self):
super(MachineHistory, self).__init__()
super().__init__()
self.event_type = MachineHistoryEvent
def get(self, machine_id, model):
def get(self, instance_id, model):
"""Get the the list of MachineHistoryEvent related to the object.
Args:
machine_id: int, the id of the machine to lookup.
instance_id: int, the id of the machine to lookup.
Returns:
The list of MachineHistoryEvent, in reverse chronological order,
@ -880,7 +886,7 @@ class MachineHistory(History):
"""
self.related = (
Version.objects.get_for_model(Interface)
.filter(make_version_filter("machine", machine_id))
.filter(make_version_filter("machine", instance_id))
.order_by("content_type__model")
)
@ -888,7 +894,7 @@ class MachineHistory(History):
self.related = [RelatedHistory(v) for v in self.related]
self.related = list(dict.fromkeys(self.related))
return super(MachineHistory, self).get(machine_id, Machine)
return super().get(instance_id, Machine)
class InterfaceHistoryEvent(HistoryEvent):
@ -907,17 +913,17 @@ class InterfaceHistoryEvent(HistoryEvent):
try:
return IpList.objects.get(id=value)
except IpList.DoesNotExist:
return "{} ({})".format(_("Deleted"), value)
return f'{_("Deleted")} ({value})'
elif name == "machine_type_id":
try:
return MachineType.objects.get(id=value).name
except MachineType.DoesNotExist:
return "{} ({})".format(_("Deleted"), value)
return f'{_("Deleted")} ({value})'
elif name == "machine_id":
try:
return Machine.objects.get(id=value).get_name() or _("No name")
except Machine.DoesNotExist:
return "{} ({})".format(_("Deleted"), value)
return f'{_("Deleted")} ({value})'
elif name == "port_lists":
if len(value) == 0:
return _("None")
@ -927,27 +933,27 @@ class InterfaceHistoryEvent(HistoryEvent):
try:
ports.append(Port.objects.get(id=pid).pretty_name())
except Group.DoesNotExist:
ports.append("{} ({})".format(_("Deleted"), pid))
ports.append(f'{_("Deleted")} ({pid})')
return super(InterfaceHistoryEvent, self)._repr(name, value)
return super()._repr(name, value)
class InterfaceHistory(History):
def __init__(self):
super(InterfaceHistory, self).__init__()
super().__init__()
self.event_type = InterfaceHistoryEvent
def get(self, interface_id, model):
def get(self, instance_id, model):
"""Get the the list of InterfaceHistoryEvent related to the object.
Args:
interface_id: int, the id of the interface to lookup.
instance_id: int, the id of the interface to lookup.
Returns:
The list of InterfaceHistoryEvent, in reverse chronological order,
related to the object.
"""
return super(InterfaceHistory, self).get(interface_id, Interface)
return super().get(instance_id, Interface)
############################

View file

@ -69,7 +69,6 @@ from preferences.models import GeneralOption
from re2o.acl import (
acl_error_message,
can_edit_history,
can_view,
can_view_all,
can_view_app,
)
@ -134,10 +133,10 @@ def index(request):
# Items to remove later because invalid
to_remove = []
# Parse every item (max = pagination_number)
for i in range(len(versions.object_list)):
if versions.object_list[i].object:
version = versions.object_list[i]
versions.object_list[i] = {
for i, item in enumerate(versions.object_list):
if item.object:
version = item
item = {
"rev_id": version.revision.id,
"comment": version.revision.comment,
"datetime": version.revision.date_created,
@ -212,7 +211,7 @@ def stats_general(request):
disabled, archived etc.) and IP addresses (ranges, number of assigned
addresses etc.).
"""
ip_dict = dict()
ip_dict = {}
for ip_range in IpType.objects.select_related("vlan").all():
all_ip = IpList.objects.filter(ip_type=ip_range)
used_ip = Interface.objects.filter(ipv4__in=all_ip).count()
@ -519,8 +518,8 @@ def stats_search_machine_history(request):
"""
history_form = MachineHistorySearchForm(request.GET or None)
if history_form.is_valid():
history = MachineHistorySearch()
events = history.get(
hist = MachineHistorySearch()
events = hist.get(
history_form.cleaned_data.get("q", ""), history_form.cleaned_data
)
max_result = GeneralOption.get_cached_value("pagination_number")
@ -536,7 +535,7 @@ def stats_search_machine_history(request):
)
def get_history_object(request, model, object_name, object_id):
def get_history_object(request, model, _object_name, object_id):
"""Get the objet of type model with the given object_id
Handles permissions and DoesNotExist errors
"""
@ -588,15 +587,15 @@ def history(request, application, object_name, object_id):
"""
try:
model = apps.get_model(application, object_name)
except LookupError:
raise Http404(_("No model found."))
except LookupError as e:
raise Http404(_("No model found.")) from e
authorized, instance = get_history_object(request, model, object_name, object_id)
if not authorized:
return instance
history = get_history_class(model)
events = history.get(int(object_id), model)
hist = get_history_class(model)
events = hist.get(int(object_id), model)
# Events is None if object wasn't found
if events is None:
@ -610,7 +609,7 @@ def history(request, application, object_name, object_id):
events = re2o_paginator(request, events, max_result)
# Add a default title in case the object was deleted
title = instance or "{} ({})".format(history.name, _("Deleted"))
title = instance or f'{history.name} ({_("Deleted")})'
return render(
request,

View file

@ -41,6 +41,6 @@ def can_view(user, *args, **kwargs):
can = user.has_module_perms("preferences")
return (
can,
None if can else _("You don't have the right to view this" " application."),
None if can else _("You don't have the right to view this application."),
("preferences",),
)

View file

@ -49,86 +49,58 @@ from .models import (
class OptionalUserAdmin(VersionAdmin):
"""Admin class for user options."""
pass
class OptionalTopologieAdmin(VersionAdmin):
"""Admin class for topology options."""
pass
class OptionalMachineAdmin(VersionAdmin):
"""Admin class for machines options."""
pass
class GeneralOptionAdmin(VersionAdmin):
"""Admin class for general options."""
pass
class ServiceAdmin(VersionAdmin):
"""Admin class for services (on the homepage)."""
pass
class MailContactAdmin(VersionAdmin):
"""Admin class for contact email addresses."""
pass
class AssoOptionAdmin(VersionAdmin):
"""Admin class for organisation options."""
pass
class MailMessageOptionAdmin(VersionAdmin):
"""Admin class for email messages options."""
pass
class HomeOptionAdmin(VersionAdmin):
"""Admin class for home options."""
pass
class RadiusKeyAdmin(VersionAdmin):
"""Admin class for RADIUS keys options."""
pass
class SwitchManagementCredAdmin(VersionAdmin):
"""Admin class for switch management credentials options."""
pass
class ReminderAdmin(VersionAdmin):
"""Admin class for reminder options."""
pass
class DocumentTemplateAdmin(VersionAdmin):
"""Admin class for document templates."""
pass
class MandateAdmin(VersionAdmin):
"""Admin class for mandates."""
pass
admin.site.register(OptionalUser, OptionalUserAdmin)
admin.site.register(OptionalMachine, OptionalMachineAdmin)

View file

@ -22,7 +22,7 @@
from rest_framework import serializers
import preferences.models as preferences
from api.serializers import NamespacedHIField, NamespacedHMSerializer, NamespacedHRField
from api.serializers import NamespacedHMSerializer
class OptionalUserSerializer(NamespacedHMSerializer):

View file

@ -33,6 +33,7 @@ from django.utils.translation import ugettext_lazy as _
from re2o.mixins import FormRevMixin
from re2o.widgets import AutocompleteModelWidget, AutocompleteMultipleModelWidget
from topologie.models import Switch
from cotisations.models import Banque
from .models import (
AssoOption,
@ -64,7 +65,7 @@ class EditOptionalUserForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOptionalUserForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["is_tel_mandatory"].label = _("Telephone number required")
self.fields["gpg_fingerprint"].label = _("GPG fingerprint")
self.fields["all_can_create_club"].label = _("All can create a club")
@ -101,7 +102,7 @@ class EditOptionalMachineForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["password_machine"].label = _(
"Possibility to set a password per machine"
)
@ -135,7 +136,7 @@ class EditOptionalTopologieForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOptionalTopologieForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.initial["automatic_provision_switchs"] = Switch.objects.filter(
automatic_provision=True
@ -159,7 +160,7 @@ class EditGeneralOptionForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditGeneralOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["general_message_fr"].label = _("General message in French")
self.fields["general_message_en"].label = _("General message in English")
self.fields["search_display_page"].label = _(
@ -194,7 +195,7 @@ class EditAssoOptionForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditAssoOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["name"].label = _("Organisation name")
self.fields["siret"].label = _("SIRET number")
self.fields["adresse1"].label = _("Address (line 1)")
@ -217,7 +218,7 @@ class EditMailMessageOptionForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["welcome_mail_fr"].label = _("Message for the French welcome email")
self.fields["welcome_mail_en"].label = _(
"Message for the English welcome email"
@ -235,7 +236,7 @@ class EditHomeOptionForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditHomeOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["facebook_url"].label = _("Facebook URL")
self.fields["twitter_url"].label = _("Twitter URL")
self.fields["twitter_account_name"].label = _("Twitter account name")
@ -283,7 +284,7 @@ class MandateForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(MandateForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
def clean_start_date(self):
date = self.cleaned_data.get("start_date")
@ -293,7 +294,8 @@ class MandateForm(ModelForm):
if existing_mandates:
raise forms.ValidationError(
_(
"There is already a mandate taking place at the specified start date."
"There is already a mandate taking place at the specified "
"start date."
)
)
return date
@ -312,7 +314,7 @@ class MandateForm(ModelForm):
return date
def clean(self):
cleaned_data = super(MandateForm, self).clean()
cleaned_data = super().clean()
start_date, end_date = cleaned_data["start_date"], cleaned_data["end_date"]
if end_date:
included_mandates = Mandate.objects.filter(
@ -330,7 +332,7 @@ class MandateForm(ModelForm):
"""Warning, side effect : if a mandate with a null end_date
exists, its end_date will be set to instance.start_date, no matter the
value of commit."""
instance = super(MandateForm, self).save(commit=False)
instance = super().save(commit=False)
if instance.end_date is None:
try:
previous_mandate = Mandate.objects.get(end_date__isnull=True)
@ -352,7 +354,7 @@ class ServiceForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["name"].label = _("Name")
self.fields["url"].label = _("URL")
self.fields["description"].label = _("Description")
@ -370,7 +372,7 @@ class DelServiceForm(Form):
def __init__(self, *args, **kwargs):
instances = kwargs.pop("instances", None)
super(DelServiceForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if instances:
self.fields["services"].queryset = instances
else:
@ -386,7 +388,7 @@ class ReminderForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(ReminderForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class RadiusKeyForm(FormRevMixin, ModelForm):
@ -404,7 +406,7 @@ class RadiusKeyForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(RadiusKeyForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
instance = kwargs.get("instance", None)
if instance:
self.initial["members"] = Switch.objects.filter(radius_key=instance)
@ -430,7 +432,7 @@ class SwitchManagementCredForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(SwitchManagementCredForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
instance = kwargs.get("instance", None)
if instance:
self.initial["members"] = Switch.objects.filter(management_creds=instance)
@ -450,7 +452,7 @@ class MailContactForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(MailContactForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class DelMailContactForm(Form):
@ -464,7 +466,7 @@ class DelMailContactForm(Form):
def __init__(self, *args, **kwargs):
instances = kwargs.pop("instances", None)
super(DelMailContactForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if instances:
self.fields["mailcontacts"].queryset = instances
else:
@ -480,7 +482,7 @@ class DocumentTemplateForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(DocumentTemplateForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class DelDocumentTemplateForm(FormRevMixin, Form):
@ -494,7 +496,7 @@ class DelDocumentTemplateForm(FormRevMixin, Form):
def __init__(self, *args, **kwargs):
instances = kwargs.pop("instances", None)
super(DelDocumentTemplateForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if instances:
self.fields["document_templates"].queryset = instances
else:
@ -510,7 +512,7 @@ class RadiusAttributeForm(ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(RadiusAttributeForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class DelRadiusAttributeForm(Form):
@ -524,8 +526,8 @@ class DelRadiusAttributeForm(Form):
def __init__(self, *args, **kwargs):
instances = kwargs.pop("instances", None)
super(DelServiceForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if instances:
self.fields["attributes"].queryset = instances
else:
self.fields["attributes"].queryset = Attributes.objects.all()
self.fields["attributes"].queryset = Attribute.objects.all()

View file

@ -109,7 +109,8 @@ class OptionalUser(AclMixin, PreferencesModel):
(
ONLY_INACTIVE,
_(
"Users can only select a room occupied by a user with a disabled connection."
"Users can only select a room occupied by a user with "
"a disabled connection."
),
),
(ALL_ROOM, _("Users can select all rooms")),
@ -157,7 +158,8 @@ class OptionalUser(AclMixin, PreferencesModel):
disable_emailnotyetconfirmed = models.IntegerField(
default=2,
help_text=_(
"Users with an email address not yet confirmed will be disabled after this number of days."
"Users with an email address not yet confirmed will be disabled after "
"this number of days."
),
)
self_adhesion = models.BooleanField(
@ -338,8 +340,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
.filter(machine_type__ip_type=self.switchs_ip_type)
.first()
)
else:
return None
return None
@cached_property
def switchs_management_interface_ip(self):
@ -355,15 +356,14 @@ class OptionalTopologie(AclMixin, PreferencesModel):
"""Get the switch credentials for SFTP provisioning."""
if self.sftp_login and self.sftp_pass:
return {"login": self.sftp_login, "pass": self.sftp_pass}
else:
return None
return None
@cached_property
def switchs_management_utils(self):
"""Get the dictionary of IP addresses for the configuration of
switches.
"""
from machines.models import Interface, Ipv6List, Role
from machines.models import Ipv6List, Role
def return_ips_dict(interfaces):
return {
@ -622,7 +622,7 @@ class MailContact(AclMixin, models.Model):
@cached_property
def get_name(self):
return self.address.split("@")[0]
return self.address.split("@", maxsplit=1)[0]
class Meta:
verbose_name = _("contact email address")
@ -676,7 +676,8 @@ class Mandate(RevMixin, AclMixin, models.Model):
if not mandate:
raise cls.DoesNotExist(
_(
"No mandates have been created. Please go to the preferences page to create one."
"No mandates have been created. Please go to the preferences page "
"to create one."
)
)
return mandate
@ -977,7 +978,9 @@ class RadiusOption(AclMixin, PreferencesModel):
)
@classmethod
def get_attributes(cls, name, attribute_kwargs={}):
def get_attributes(cls, name, attribute_kwargs=None):
if attribute_kwargs is None:
attribute_kwargs = {}
return (
(str(attribute.attribute), str(attribute.value % attribute_kwargs))
for attribute in cls.get_cached_value(name).all()
@ -1082,3 +1085,4 @@ def auto_delete_file_on_change(sender, instance, **kwargs):
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
return True

View file

@ -56,7 +56,6 @@ from . import forms, models
from .forms import (
DelDocumentTemplateForm,
DelMailContactForm,
DelRadiusAttributeForm,
DocumentTemplateForm,
MailContactForm,
MandateForm,
@ -108,8 +107,7 @@ def edit_options_template_function(request, section, forms, models):
options.save()
reversion.set_user(request.user)
reversion.set_comment(
"Field(s) edited: %s"
% ", ".join(field for field in options.changed_data)
f'Field(s) edited: {", ".join(field for field in options.changed_data)}'
)
messages.success(request, _("The preferences were edited."))
return redirect(reverse("preferences:display-options"))

View file

@ -32,7 +32,6 @@ import sys
from itertools import chain
from django.contrib import messages
from django.db.models import Model
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import ugettext as _
@ -51,12 +50,11 @@ def acl_error_message(msg, permissions):
return (
message + _("You need to be a member of one of these groups: %s.") % groups
)
else:
return message + _("No group has the %s permission(s)!") % " or ".join(
[",".join(permissions[:-1]), permissions[-1]]
if len(permissions) > 2
else permissions
)
return message + _("No group has the %s permission(s)!") % " or ".join(
[",".join(permissions[:-1]), permissions[-1]]
if len(permissions) > 2
else permissions
)
# This is the function of main interest of this file. Almost all the decorators
@ -269,14 +267,13 @@ ModelC)
"users:profil", kwargs={"userid": str(request.user.id)}
)
)
else:
return Response(
data={
"errors": error_messages,
"warning": warning_messages,
},
status=403,
)
return Response(
data={
"errors": error_messages,
"warning": warning_messages,
},
status=403,
)
else:
return redirect(reverse("index"))
return view(request, *chain(instances, args), **kwargs)
@ -382,7 +379,7 @@ def can_list(*targets):
def can_view_app(*apps_name):
"""Decorator to check if an user can view the applications."""
for app_name in apps_name:
assert app_name in sys.modules.keys()
assert app_name in sys.modules
return acl_base_decorator(
"can_view",
*chain(sys.modules[app_name] for app_name in apps_name),

View file

@ -37,8 +37,8 @@ from django import forms
from django.conf import settings
from django.db import models
EOD_asbyte = b"`%EofD%`" # This should be something that will not occur in strings
EOD = EOD_asbyte.decode("utf-8")
EOD_ASBYTE = b"`%EofD%`" # This should be something that will not occur in strings
EOD = EOD_ASBYTE.decode("utf-8")
def genstring(length=16, chars=string.printable):
@ -63,7 +63,7 @@ def decrypt(key, secret):
"""AES Decrypt a secret with the key `key`"""
obj = AES.new(key, AES.MODE_ECB)
uncrypted_secret = obj.decrypt(secret)
return uncrypted_secret.split(EOD_asbyte)[0]
return uncrypted_secret.split(EOD_ASBYTE)[0]
class AESEncryptedFormField(forms.CharField):
@ -88,9 +88,9 @@ class AESEncryptedField(models.CharField):
return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode("utf-8")
except UnicodeDecodeError as e:
raise ValueError(
"Could not decode your field %s, your settings.AES_KEY "
"is probably wrong." % self.name
)
f"Could not decode your field {self.name}, your settings.AES_KEY "
"is probably wrong."
) from e
def from_db_value(self, value, *args, **kwargs):
if value is None:
@ -99,9 +99,9 @@ class AESEncryptedField(models.CharField):
return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode("utf-8")
except UnicodeDecodeError as e:
raise ValueError(
"Could not decode your field %s, your settings.AES_KEY "
"is probably wrong." % self.name
)
f"Could not decode your field {self.name}, your settings.AES_KEY "
"is probably wrong."
) from e
def get_prep_value(self, value):
if value is None:

View file

@ -76,16 +76,16 @@ def smtp_check(local_part):
return False, None
def convert_datetime_format(format):
def convert_datetime_format(date_format):
i = 0
new_format = ""
while i < len(format):
if format[i] == "%":
char = format[i : i + 2]
while i < len(date_format):
if date_format[i] == "%":
char = date_format[i : i + 2]
new_format += datetime_mapping.get(char, char)
i += 2
else:
new_format += format[i]
new_format += date_format[i]
i += 1
return new_format
@ -235,8 +235,7 @@ class SortTable:
request = request.order_by(*fields)
if values.get(col, None) and order == "desc":
return request.reverse()
else:
return request
return request
def re2o_paginator(request, query_set, pagination_number, page_arg="page"):

View file

@ -64,7 +64,7 @@ class FieldPermissionModelMixin:
checks.append(perm_label)
# No requirements means no restrictions.
if not len(checks):
if not checks:
return self.FIELD_PERMISSION_MISSING_DEFAULT
# Try to find a user setting that qualifies them for permission.
@ -97,7 +97,7 @@ class FieldPermissionFormMixin:
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(FieldPermissionFormMixin, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
to_be_deleted = []
for name in self.fields:
if not self.instance.has_field_perm(user, field=name):

View file

@ -44,7 +44,7 @@ ALGO_LEN = len(ALGO_NAME + "$")
DIGEST_LEN = 20
def makeSecret(password):
def make_secret(password):
"""Build a hashed and salted version of the password with SSHA
Parameters:
@ -59,7 +59,7 @@ def makeSecret(password):
return ALGO_NAME + "$" + encodebytes(h.digest() + salt).decode()[:-1]
def hashNT(password):
def hash_nt(password):
"""Build a md4 hash of the password to use as the NT-password
Parameters:
@ -73,7 +73,7 @@ def hashNT(password):
return binascii.hexlify(hash_str).upper().decode("utf-8")
def checkPassword(challenge_password, password):
def check_password(challenge_password, password):
"""Check if a given password match the hash of a stored password
Parameters:
@ -106,28 +106,26 @@ def hash_password_salt(hashed_password):
hashed_password = hashed_password[7:]
if hashed_password.startswith("$"):
return "$".join(hashed_password.split("$")[:-1])
else:
return hashed_password[:2]
elif hashed_password.upper().startswith("{SSHA}"):
return hashed_password[:2]
if hashed_password.upper().startswith("{SSHA}"):
try:
digest = b64decode(hashed_password[6:])
except TypeError as error:
raise ValueError("b64 error for `hashed_password`: %s." % error)
raise ValueError(f"b64 error for `hashed_password`: {error}.") from error
if len(digest) < 20:
raise ValueError("`hashed_password` too short.")
return digest[20:]
elif hashed_password.upper().startswith("{SMD5}"):
if hashed_password.upper().startswith("{SMD5}"):
try:
digest = b64decode(hashed_password[7:])
except TypeError as error:
raise ValueError("b64 error for `hashed_password`: %s." % error)
raise ValueError(f"b64 error for `hashed_password`: {error}.") from error
if len(digest) < 16:
raise ValueError("`hashed_password` too short.")
return digest[16:]
else:
raise ValueError(
"`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'."
)
raise ValueError(
"`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'."
)
class CryptPasswordHasher(hashers.BasePasswordHasher):
@ -174,7 +172,6 @@ class CryptPasswordHasher(hashers.BasePasswordHasher):
As we are not using multiple iterations the method is pretty useless
"""
pass
class MD5PasswordHasher(hashers.BasePasswordHasher):
@ -223,7 +220,6 @@ class MD5PasswordHasher(hashers.BasePasswordHasher):
As we are not using multiple iterations the method is pretty useless
"""
pass
class SSHAPasswordHasher(hashers.BasePasswordHasher):
@ -240,14 +236,14 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher):
salt is overridden
"""
assert password is not None
return makeSecret(password)
return make_secret(password)
def verify(self, password, encoded):
"""
Check password against encoded using SSHA algorithm
"""
assert encoded.startswith(self.algorithm)
return checkPassword(encoded, password)
return check_password(encoded, password)
def safe_summary(self, encoded):
"""
@ -271,12 +267,11 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher):
As we are not using multiple iterations the method is pretty useless
"""
pass
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
"""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
@ -285,16 +280,14 @@ class RecryptBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
# we obtain from the classical auth backend the user
user = super(RecryptBackend, self).authenticate(
request, username, password, **kwargs
)
user = super().authenticate(request, username, password, **kwargs)
if user:
if not (user.pwd_ntlm):
if not user.pwd_ntlm:
# if we dont have NT hash, we create it
user.pwd_ntlm = hashNT(password)
user.pwd_ntlm = hash_nt(password)
user.save()
if not ("SSHA" in user.password):
if not "SSHA" in user.password:
# if the hash is too old, we update it
user.password = makeSecret(password)
user.password = make_secret(password)
user.save()
return user

View file

@ -54,7 +54,7 @@ class Command(BaseCommand):
# Put it back together
name_text = " ".join(names)
buffer += " '{}',\n".format(name_text)
buffer += f" '{name_text}',\n"
buffer += "]"
return buffer

View file

@ -29,7 +29,7 @@ from django.utils.translation import ugettext as _
from reversion import revisions as reversion
class RevMixin(object):
class RevMixin:
"""A mixin to subclass the save and delete function of a model
to enforce the versioning of the object before those actions
really happen"""
@ -39,17 +39,17 @@ class RevMixin(object):
if self.pk is None:
with transaction.atomic(), reversion.create_revision():
reversion.set_comment("Creation")
return super(RevMixin, self).save(*args, **kwargs)
return super(RevMixin, self).save(*args, **kwargs)
return super().save(*args, **kwargs)
return super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
"""Creates a version of this object and delete it from database"""
with transaction.atomic(), reversion.create_revision():
reversion.set_comment("Deletion")
return super(RevMixin, self).delete(*args, **kwargs)
return super().delete(*args, **kwargs)
class FormRevMixin(object):
class FormRevMixin:
"""A mixin to subclass the save function of a form
to enforce the versionning of the object before it is really edited"""
@ -57,17 +57,16 @@ class FormRevMixin(object):
"""Create a version of this object and save it to database"""
if reversion.get_comment() != "" and self.changed_data != []:
reversion.set_comment(
reversion.get_comment()
+ ",%s" % ", ".join(field for field in self.changed_data)
f'{reversion.get_comment()},{", ".join(field for field in self.changed_data)}'
)
elif self.changed_data:
reversion.set_comment(
"Field(s) edited: %s" % ", ".join(field for field in self.changed_data)
f'Field(s) edited: {", ".join(field for field in self.changed_data)}'
)
return super(FormRevMixin, self).save(*args, **kwargs)
return super().save(*args, **kwargs)
class AclMixin(object):
class AclMixin:
"""This mixin is used in nearly every class/models defined in re2o apps.
It is used by acl, in models (decorators can_...) and in templates tags
:get_instance: Applied on a class, take an id argument, return an instance
@ -92,7 +91,7 @@ class AclMixin(object):
@classmethod
def get_modulename(cls):
"""Returns the name of the module where this mixin is used"""
return str(cls.__module__).split(".")[0].lower()
return str(cls.__module__).split(".", maxsplit=1)[0].lower()
@classmethod
def get_instance(cls, object_id, *_args, **kwargs):

View file

@ -68,32 +68,32 @@ def get_system_user():
return pwd.getpwuid(int(os.getenv("SUDO_UID") or os.getuid())).pw_name
def form_cli(Form, user, action, *args, **kwargs):
def form_cli(form, user, action, *args, **kwargs):
"""
Fill-in a django form from cli
Parameters
Form : a django class form to fill-in
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)
dumb_form = form(user=user, *args, **kwargs)
for key in dumb_form.fields:
if not dumb_form.fields[key].widget.input_type == "hidden":
if dumb_form.fields[key].widget.input_type == "password":
data[key] = getpass("%s : " % dumb_form.fields[key].label)
data[key] = getpass(f"{dumb_form.fields[key].label} : ")
else:
data[key] = input("%s : " % dumb_form.fields[key].label)
data[key] = input(f"{dumb_form.fields[key].label} : ")
form = Form(data, user=user, *args, **kwargs)
form = form(data, user=user, *args, **kwargs)
if not form.is_valid():
sys.stderr.write("Errors: \n")
for err in form.errors:
# Oui, oui, on gère du HTML là où d'autres ont eu la
# lumineuse idée de le mettre
sys.stderr.write("\t%s : %s\n" % (err, strip_tags(form.errors[err])))
sys.stderr.write(f"\t{err} : {strip_tags(form.errors[err])}\n")
raise CommandError("Invalid form.")
with transaction.atomic(), reversion.create_revision():
@ -101,4 +101,4 @@ def form_cli(Form, user, action, *args, **kwargs):
reversion.set_user(user)
reversion.set_comment(action)
sys.stdout.write("%s: done. The edit may take several minutes to apply.\n" % action)
sys.stdout.write("{action}: done. The edit may take several minutes to apply.\n")

View file

@ -36,7 +36,6 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
from __future__ import unicode_literals
import os
import importlib
from decouple import config
from django.utils.translation import ugettext_lazy as _

View file

@ -59,7 +59,8 @@ DEFAULT_GID = 500
# If you want to add a database routers, please fill in above and add your databse.
# Then, add a file "local_routers.py" in folder app re2o, and add your router path in
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers.
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter".
# You can also add extra routers.
LOCAL_ROUTERS = []
# Some optionnal Re2o Apps

View file

@ -108,7 +108,8 @@ DEFAULT_GID = 500
# If you want to add a database routers, please fill in above and add your databse.
# Then, add a file "local_routers.py" in folder app re2o, and add your router path in
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers.
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter".
# You can also add extra routers.
# To use ldap you need to add "ldapdb.router.Router"
LOCAL_ROUTERS = []
@ -118,12 +119,16 @@ OPTIONNAL_APPS_RE2O = ()
# Some Django apps you want to add in you local project
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + ()
# Some optinnal link for the navbar in a tuple (link,icon class,text,position (left or right))
# Some optinnal link for the navbar in a tuple
# (link, icon class, text, position (left or right))
NAVBAR_LINKS = ()
# Add statiffiles dir that were installed using system packaging
# Example to reproduce re2o2.9 behavior
# SYSTEM_STATICFILES_DIRS = ("/usr/share/fonts-font-awesome/", "/usr/share/javascript/")
# SYSTEM_STATICFILES_DIRS = (
# "/usr/share/fonts-font-awesome/",
# "/usr/share/javascript/"
# )
SYSTEM_STATICFILES_DIRS = ()
# Wether to use CDN to retrieve bootstrap, font-aweseome and jquery files

View file

@ -81,7 +81,10 @@ EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
# Add statiffiles dir that were installed using system packaging
# Example to reproduce re2o2.9 behavior
# SYSTEM_STATICFILES_DIRS = ("/usr/share/fonts-font-awesome/", "/usr/share/javascript/")
# SYSTEM_STATICFILES_DIRS = (
# "/usr/share/fonts-font-awesome/",
# "/usr/share/javascript/"
# )
SYSTEM_STATICFILES_DIRS = ()
# Wether to use CDN to retrieve bootstrap, font-aweseome and jquery files
@ -107,7 +110,8 @@ OPTIONNAL_APPS_RE2O = (
# Some Django apps you want to add in you local project
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + ()
# Some optinnal link for the navbar in a tuple (link,icon class,text,position (left or right))
# Some optinnal link for the navbar in a tuple
# (link, icon class, text, position (left or right))
NAVBAR_LINKS = ()
# LDAP = {

View file

@ -85,10 +85,10 @@ def get_model(model_name):
if len(splitted) > 1:
try:
app_label, name = splitted
except ValueError:
except ValueError as e:
raise template.TemplateSyntaxError(
"%r is an inconsistent model name." % model_name
)
f"{model_name} is an inconsistent model name."
) from e
else:
app_label, name = None, splitted[0]
try:
@ -98,14 +98,14 @@ def get_model(model_name):
)
else:
content_type = ContentType.objects.get(model=name.lower())
except ContentType.DoesNotExist:
except ContentType.DoesNotExist as e:
raise template.TemplateSyntaxError(
"%r is not a valid model for an acl tag." % model_name
)
except ContentType.MultipleObjectsReturned:
f"{model_name} is not a valid model for an acl tag."
) from e
except ContentType.MultipleObjectsReturned as e:
raise template.TemplateSyntaxError(
"More than one model found for %r. Try with `app.model`." % model_name
)
f"More than one model found for {model_name}. Try with `app.model`."
) from e
return content_type.model_class()
@ -179,7 +179,7 @@ def get_callback(tag_name, obj=None):
True,
)
raise template.TemplateSyntaxError("%r tag is not a valid can_xxx tag." % tag_name)
raise template.TemplateSyntaxError(f"{tag_name} tag is not a valid can_xxx tag.")
def acl_fct(callback, reverse):
@ -227,14 +227,14 @@ def acl_app_filter(parser, token):
contents = token.split_contents()
tag_name = contents[0]
app_name = contents[1:]
except ValueError:
except ValueError as e:
raise template.TemplateSyntaxError(
"%r tag require 1 argument: an application" % token.contents.split()[0]
)
f"{token.contents.split()[0]} tag require 1 argument: an application"
) from e
for name in app_name:
if name not in sys.modules.keys():
if name not in sys.modules:
raise template.TemplateSyntaxError(
"%r is not a registered application for acl." % name
f"{name} is not a registered application for acl."
)
callback = get_callback(tag_name, app_name)
@ -263,11 +263,11 @@ def acl_change_filter(parser, token):
model_name = tag_content[1]
field_name = tag_content[2]
args = tag_content[3:]
except ValueError:
except ValueError as e:
raise template.TemplateSyntaxError(
"%r tag require at least 2 argument: the model and the field."
% token.contents.split()[0]
)
f"{token.contents.split()[0]} tag require at least 2 argument: "
"the model and the field."
) from e
model = get_model(model_name)
callback = getattr(model, "can_change_" + field_name)
@ -306,10 +306,10 @@ def acl_model_filter(parser, token):
tag_name = tag_content[0]
model_name = tag_content[1]
args = tag_content[2:]
except ValueError:
except ValueError as e:
raise template.TemplateSyntaxError(
"%r tag require at least 1 argument: the model." % token.contents.split()[0]
)
f"{token.contents.split()[0]} tag require at least 1 argument: the model."
) from e
model = get_model(model_name)
callback = get_callback(tag_name, model)
@ -345,11 +345,11 @@ def acl_instance_filter(parser, token):
tag_name = tag_content[0]
instance_name = tag_content[1]
args = tag_content[2:]
except ValueError:
except ValueError as e:
raise template.TemplateSyntaxError(
"%r tag require at least 1 argument: the instance."
% token.contents.split()[0]
)
f"{token.contents.split()[0]} tag require at least 1 argument: "
"the instance."
) from e
# {% can_create %}
oknodes = parser.parse(("acl_else", "acl_end"))
@ -390,7 +390,7 @@ class AclNode(Node):
return self.konodes.render(context)
def __repr__(self):
return "<AclNode %s>" % self.tag_name
return f"<AclNode {self.tag_name}>"
class AclInstanceNode(Node):
@ -415,4 +415,4 @@ class AclInstanceNode(Node):
return self.konodes.render(context)
def __repr__(self):
return "<AclInstanceNode %s>" % self.tag_name
return f"<AclInstanceNode {self.tag_name}>"

View file

@ -25,7 +25,7 @@ register = template.Library()
@register.simple_tag
def nav_link(position):
template = """
link_template = """
<li>
<a href="{}">
<i class="fa {}"></i> {}
@ -35,5 +35,5 @@ def nav_link(position):
res = ""
for link in settings.NAVBAR_LINKS:
if position == link[3]:
res += template.format(link[0], link[1], link[2])
res += link_template.format(link[0], link[1], link[2])
return res

View file

@ -20,7 +20,6 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from django import template
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
register = template.Library()
@ -30,11 +29,11 @@ register = template.Library()
def tick(valeur, autoescape=False):
if isinstance(valeur, bool):
if valeur == True:
if valeur is True:
result = '<i class="fa fa-check text-success"></i>'
else:
result = '<i class="fa fa-times text-danger"></i>'
return mark_safe(result)
else: # if the value is not a boolean, display it as if tick was not called
return valeur
# if the value is not a boolean, display it as if tick was not called
return valeur

View file

@ -18,5 +18,4 @@ def font_awesome_url():
"""
if settings.USE_CDN:
return "https://pro.fontawesome.com/releases/v5.10.0/css/all.css"
else:
return static("rest_framework/css/font-awesome-4.0.3.css")
return static("rest_framework/css/font-awesome-4.0.3.css")

View file

@ -89,7 +89,7 @@ def pagination_insert_page_and_id(url, page=1, id=None, **kwargs):
args = {"url": url, page_arg: page}
new_url = url_insert_param(**args)
if id != None:
if id is not None:
new_url += "#" + str(id)
return new_url

View file

@ -60,7 +60,7 @@ urlpatterns = [
urlpatterns += [
path("{}/".format(app), include("{}.urls".format(app), namespace=app))
path(f"{app}/", include(f"{app}.urls", namespace=app))
for app in OPTIONNAL_APPS_RE2O
]

View file

@ -40,7 +40,7 @@ from django.contrib.auth.models import Group, Permission
from django.db.models import Q
from django.utils import timezone
from cotisations.models import Cotisation, Facture, Vente
from cotisations.models import Cotisation, Facture
from machines.models import Interface, Machine
from preferences.models import AssoOption
from users.models import Adherent, Ban, User, Whitelist
@ -177,9 +177,9 @@ def all_whitelisted(search_time=None, dormitory=None, user_type="all"):
def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="all"):
"""Return all people who have a valid connection payment 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
connection is registered at the desired search_time.
"""Return all people who have a valid connection payment 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 connection is registered at the desired search_time.
Parameters:
search_time (django datetime): Datetime to perform this search,
@ -187,7 +187,8 @@ def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="a
including_asso (boolean): Decide if org itself is included in results
Returns:
django queryset: Django queryset containing all users with valid connection perdiod
django queryset: Django queryset containing all users with valid connection
perdiod
"""
if search_time is None:
@ -212,9 +213,9 @@ def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="a
def all_has_access(
search_time=None, including_asso=True, dormitory=None, user_type="all"
):
"""Return all people who have an valid internet access at org. Call previously buid filters.
Can't do that in one sql query unfortunatly. Apply each filters, and return users
with a whitelist, or a valid paid access, except banned users.
"""Return all people who have an valid internet access at org. Call previously
buid filters. Can't do that in one sql query unfortunatly. Apply each filters,
and return users with a whitelist, or a valid paid access, except banned users.
Parameters:
search_time (django datetime): Datetime to perform this search,
@ -306,8 +307,8 @@ def filter_complete_interfaces(interface_set):
"""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
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
@ -327,18 +328,17 @@ def all_active_interfaces(full=False):
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
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
django queryset: Django queryset containing all active interfaces, related
with a user with valid membership
"""
if full:
return filter_complete_interfaces(Interface.objects)
else:
return filter_active_interfaces(Interface.objects)
return filter_active_interfaces(Interface.objects)
def all_active_assigned_interfaces(full=False):
@ -347,12 +347,12 @@ def all_active_assigned_interfaces(full=False):
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
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
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)
@ -409,7 +409,6 @@ def permission_tree(queryset=None):
permissions = queryset or Permission.objects.all()
for p in permissions:
key, app, model = p.natural_key()
name = p.name
if app not in r:
r[app] = {}
if model not in r[app]:

View file

@ -34,7 +34,6 @@ from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.template.context_processors import csrf
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from preferences.models import (
@ -51,8 +50,8 @@ from .contributors import CONTRIBUTORS
def form(ctx, template, request):
"""Global template function, used in all re2o views, for building a render with context,
template and request. Adding csrf.
"""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
@ -109,11 +108,11 @@ def about_page(request):
git_info_commit = last_commit.hexsha
git_info_commit_date = last_commit.committed_datetime
except:
NO_GIT_MSG = _("Unable to get the information.")
git_info_remote = NO_GIT_MSG
git_info_branch = NO_GIT_MSG
git_info_commit = NO_GIT_MSG
git_info_commit_date = NO_GIT_MSG
no_msg_git = _("Unable to get the information.")
git_info_remote = no_msg_git
git_info_branch = no_msg_git
git_info_commit = no_msg_git
git_info_commit_date = no_msg_git
dependencies = settings.INSTALLED_APPS + settings.MIDDLEWARE
@ -179,7 +178,9 @@ class AutocompleteLoggedOutViewMixin(autocomplete.Select2QuerySetView):
query_filter = "name__icontains" # Override this if necessary
def get_queryset(self):
can, reason, _permission, query_set = self.obj_type.can_list(self.request.user)
_can, _reason, _permission, query_set = self.obj_type.can_list(
self.request.user
)
if query_set:
self.query_set = query_set

View file

@ -30,6 +30,7 @@ from django.utils.translation import ugettext as _
class AutocompleteModelWidget(autocomplete.ModelSelect2):
# pylint: disable=line-too-long
"""A mixin subclassing django-autocomplete-light's Select2 model to pass default options
See https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#passing-options-to-select2
"""
@ -46,7 +47,8 @@ class AutocompleteModelWidget(autocomplete.ModelSelect2):
"""
# Display the "x" button to clear the input by default
attrs["data-allow-clear"] = attrs.get("data-allow-clear", "true")
# If there are less than 10 results, just show all of them (no need to autocomplete)
# If there are less than 10 results, just show all of them
# (no need to autocomplete)
attrs["data-minimum-results-for-search"] = attrs.get(
"data-minimum-results-for-search", 10
)
@ -54,6 +56,7 @@ class AutocompleteModelWidget(autocomplete.ModelSelect2):
class AutocompleteMultipleModelWidget(autocomplete.ModelSelect2Multiple):
# pylint: disable=line-too-long
"""A mixin subclassing django-autocomplete-light's Select2 model to pass default options
See https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#passing-options-to-select2
"""
@ -70,7 +73,8 @@ class AutocompleteMultipleModelWidget(autocomplete.ModelSelect2Multiple):
"""
# Display the "x" button to clear the input by default
attrs["data-allow-clear"] = attrs.get("data-allow-clear", "true")
# If there are less than 10 results, just show all of them (no need to autocomplete)
# If there are less than 10 results, just show all of them
# (no need to autocomplete)
attrs["data-minimum-results-for-search"] = attrs.get(
"data-minimum-results-for-search", 10
)

View file

@ -47,68 +47,46 @@ from .models import (
class StackAdmin(VersionAdmin):
"""Admin class of stacks (includes switches)."""
pass
class SwitchAdmin(VersionAdmin):
"""Admin class of switches."""
pass
class PortAdmin(VersionAdmin):
"""Admin class of switch ports."""
pass
class AccessPointAdmin(VersionAdmin):
"""Admin class of APs."""
pass
class RoomAdmin(VersionAdmin):
"""Admin class of rooms."""
pass
class ModelSwitchAdmin(VersionAdmin):
"""Admin class of switch models."""
pass
class ConstructorSwitchAdmin(VersionAdmin):
"""Admin class of switch constructors."""
pass
class SwitchBayAdmin(VersionAdmin):
"""Admin class of switch bays."""
pass
class BuildingAdmin(VersionAdmin):
"""Admin class of buildings."""
pass
class DormitoryAdmin(VersionAdmin):
"""Admin class of dormitories."""
pass
class PortProfileAdmin(VersionAdmin):
"""Admin class of port profiles."""
pass
admin.site.register(Port, PortAdmin)
admin.site.register(AccessPoint, AccessPointAdmin)

View file

@ -23,7 +23,7 @@ from rest_framework import serializers
import machines.models as machines
import topologie.models as topologie
from api.serializers import NamespacedHIField, NamespacedHMSerializer, NamespacedHRField
from api.serializers import NamespacedHMSerializer
from machines.api.serializers import Ipv6ListSerializer, VlanSerializer

View file

@ -77,14 +77,15 @@ class PortForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(PortForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class EditPortForm(FormRevMixin, ModelForm):
"""Form used to edit a switch's port: change in RADIUS or VLANs settings,
assignement to a room, port or machine.
A port is related to either a room, another port (uplink) or a machine (server or AP).
A port is related to either a room, another port (uplink)
or a machine (server or AP).
"""
class Meta(PortForm.Meta):
@ -99,7 +100,7 @@ class EditPortForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditPortForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["machine_interface"].queryset = (
Interface.objects.all().select_related("domain__extension")
)
@ -127,7 +128,7 @@ class AddPortForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(AddPortForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
self.fields["machine_interface"].queryset = (
Interface.objects.all().select_related("domain__extension")
)
@ -152,7 +153,7 @@ class StackForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(StackForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class AddAccessPointForm(NewMachineForm):
@ -204,7 +205,7 @@ class EditRoomForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditRoomForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class CreatePortsForm(forms.Form):
@ -229,7 +230,7 @@ class EditModelSwitchForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditModelSwitchForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
instance = kwargs.get("instance", None)
if instance:
self.initial["members"] = Switch.objects.filter(model=instance)
@ -249,7 +250,7 @@ class EditConstructorSwitchForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditConstructorSwitchForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class EditSwitchBayForm(FormRevMixin, ModelForm):
@ -270,7 +271,7 @@ class EditSwitchBayForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditSwitchBayForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
instance = kwargs.get("instance", None)
if instance:
self.initial["members"] = Switch.objects.filter(switchbay=instance)
@ -290,7 +291,7 @@ class EditBuildingForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditBuildingForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class EditDormitoryForm(FormRevMixin, ModelForm):
@ -302,7 +303,7 @@ class EditDormitoryForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditDormitoryForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class EditPortProfileForm(FormRevMixin, ModelForm):
@ -320,7 +321,7 @@ class EditPortProfileForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditPortProfileForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class EditModuleForm(FormRevMixin, ModelForm):
@ -332,7 +333,7 @@ class EditModuleForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditModuleForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)
class EditSwitchModuleForm(FormRevMixin, ModelForm):
@ -344,4 +345,4 @@ class EditSwitchModuleForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditSwitchModuleForm, self).__init__(*args, prefix=prefix, **kwargs)
super().__init__(*args, prefix=prefix, **kwargs)

View file

@ -34,11 +34,9 @@ The following models are defined:
from __future__ import unicode_literals
import itertools
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.db import IntegrityError, models, transaction
from django.db import models, transaction
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from django.utils.functional import cached_property
@ -78,7 +76,7 @@ class Stack(AclMixin, RevMixin, models.Model):
self.clean()
if not self.name:
self.name = self.stack_id
super(Stack, self).save(*args, **kwargs)
super().save(*args, **kwargs)
def clean(self):
"""Check if id_max < id_min."""
@ -143,7 +141,8 @@ class AccessPoint(Machine):
# We want to retrieve the default behaviour given by AclMixin rather
# than the one overwritten by Machine. If you are not familiar with
# the behaviour of `super`, please check https://docs.python.org/3/library/functions.html#super
# the behaviour of `super`, please check
# https://docs.python.org/3/library/functions.html#super
@classmethod
def get_instance(cls, *args, **kwargs):
@ -208,7 +207,8 @@ class Server(Machine):
# We want to retrieve the default behaviour given by AclMixin rather
# than the one overwritten by Machine. If you are not familiar with
# the behaviour of `super`, please check https://docs.python.org/3/library/functions.html#super
# the behaviour of `super`, please check
# https://docs.python.org/3/library/functions.html#super
@classmethod
def get_instance(cls, *args, **kwargs):
@ -285,7 +285,7 @@ class Switch(Machine):
"""Check if the stack member ID is in the range of the stack's IDs and
calls the clean of the parent class.
"""
super(Switch, self).clean()
super().clean()
if self.stack is not None:
if self.stack_member_id is not None:
if (self.stack_member_id > self.stack.member_id_max) or (
@ -356,8 +356,7 @@ class Switch(Machine):
"""
if self.get_radius_key:
return self.get_radius_key.radius_key
else:
return None
return None
@cached_property
def get_radius_servers_objects(self):
@ -409,8 +408,7 @@ class Switch(Machine):
"id": self.get_management_cred.management_id,
"pass": self.get_management_cred.management_pass,
}
else:
return None
return None
@cached_property
def rest_enabled(self):
@ -427,10 +425,9 @@ class Switch(Machine):
)
if sw_management_ssl:
return "ssl"
elif sw_management:
if sw_management:
return "plain"
else:
return self.automatic_provision
return self.automatic_provision
@cached_property
def ipv4(self):
@ -487,8 +484,7 @@ class Switch(Machine):
"""Get the dormitory in which the switch is located."""
if self.switchbay:
return self.switchbay.building.dormitory
else:
return None
return None
@classmethod
def nothing_profile(cls):
@ -540,7 +536,8 @@ class Switch(Machine):
# We want to retrieve the default behaviour given by AclMixin rather
# than the one overwritten by Machine. If you are not familiar with
# the behaviour of `super`, please check https://docs.python.org/3/library/functions.html#super
# the behaviour of `super`, please check
# https://docs.python.org/3/library/functions.html#super
@classmethod
def get_instance(cls, *args, **kwargs):
@ -592,8 +589,7 @@ class ModelSwitch(AclMixin, RevMixin, models.Model):
def __str__(self):
if self.commercial_name:
return str(self.constructor) + " " + str(self.commercial_name)
else:
return str(self.constructor) + " " + self.reference
return str(self.constructor) + " " + self.reference
class ModuleSwitch(AclMixin, RevMixin, models.Model):
@ -711,8 +707,7 @@ class Dormitory(AclMixin, RevMixin, models.Model):
multiple_dorms = cache.get("multiple_dorms")
if multiple_dorms:
return multiple_dorms
else:
return cache.get_or_set("multiple_dorms", cls.objects.count() > 1)
return cache.get_or_set("multiple_dorms", cls.objects.count() > 1)
@classmethod
def can_list(cls, user_request, *_args, **_kwargs):
@ -752,8 +747,7 @@ class Building(AclMixin, RevMixin, models.Model):
def get_name(self):
if Dormitory.is_multiple_dorms():
return self.dormitory.name + " : " + self.name
else:
return self.name
return self.name
@classmethod
def can_list(cls, user_request, *_args, **_kwargs):
@ -835,12 +829,11 @@ class Port(AclMixin, RevMixin, models.Model):
"""More elaborated name for label on switch configuration."""
if self.related:
return _("Uplink: ") + self.related.switch.short_name
elif self.machine_interface:
if self.machine_interface:
return _("Machine: ") + str(self.machine_interface.domain)
elif self.room:
if self.room:
return _("Room: ") + str(self.room)
else:
return _("Unknown")
return _("Unknown")
@cached_property
def get_port_profile(self):
@ -853,17 +846,15 @@ class Port(AclMixin, RevMixin, models.Model):
"""
if self.custom_profile:
return self.custom_profile
elif self.related:
if self.related:
return self.switch.default_uplink_profile
elif self.machine_interface:
if self.machine_interface:
if hasattr(self.machine_interface.machine, "accesspoint"):
return self.switch.default_access_point_profile
else:
return self.switch.default_asso_machine_profile
elif self.room:
return self.switch.default_asso_machine_profile
if self.room:
return self.switch.default_room_profile
else:
return Switch.nothing_profile()
return Switch.nothing_profile()
@classmethod
def get_instance(cls, port_id, *_args, **kwargs):
@ -922,8 +913,7 @@ class Port(AclMixin, RevMixin, models.Model):
" before creating the relation."
)
)
else:
self.make_port_related()
self.make_port_related()
elif hasattr(self, "related_port"):
self.clean_port_related()
@ -1117,7 +1107,7 @@ class PortProfile(AclMixin, RevMixin, models.Model):
def clean(self):
"""Check that there is only one generic profile default."""
super(PortProfile, self).clean()
super().clean()
if (
self.profil_default
and not self.on_dormitory
@ -1129,7 +1119,8 @@ class PortProfile(AclMixin, RevMixin, models.Model):
raise ValidationError(
{
"profil_default": _(
"A default profile for all dormitories of that type already exists."
"A default profile for all dormitories of that type "
"already exists."
)
}
)

View file

@ -1438,8 +1438,10 @@ def recursive_switchs(switch_start, switch_before, detected):
Args:
switch_start: the switch to begin the visit on.
switch_before: the switch that you come from. None if switch_start is the first one.
detected: list of all switches already visited. None if switch_start is the first one.
switch_before: the switch that you come from.
None if switch_start is the first one.
detected: list of all switches already visited.
None if switch_start is the first one.
Returns:
A list of all the links found and a list of all the switches visited.

View file

@ -42,9 +42,11 @@ from .models import Building, Dormitory, Port, PortProfile, Room, Switch, Switch
class RoomAutocomplete(AutocompleteLoggedOutViewMixin):
obj_type = Room
# Precision on search to add annotations so search behaves more like users expect it to
# Precision on search to add annotations so search behaves more like
# users expect it to
def filter_results(self):
# Suppose we have a dorm named Dorm, a building named B, and rooms from 001 - 999
# Suppose we have a dorm named Dorm, a building named B,
# and rooms from 001 - 999
# Comments explain what we try to match
self.query_set = self.query_set.annotate(
full_name=Concat(
@ -70,6 +72,7 @@ class RoomAutocomplete(AutocompleteLoggedOutViewMixin):
), # Match "Dorm : B 001" (see Room's full_name property)
).all()
# pylint: disable=unsupported-binary-operation
if self.q:
self.query_set = self.query_set.filter(
Q(full_name__icontains=self.q)
@ -109,7 +112,8 @@ class PortAutocomplete(AutocompleteViewMixin):
def filter_results(self):
# We want to enter the switch name, not just the port number
# Because we're concatenating a CharField and an Integer, we have to specify the output_field
# Because we're concatenating a CharField and an Integer,
# Zwe have to specify the output_field
self.query_set = self.query_set.annotate(
full_name=Concat(
"switch__name", Value(" "), "port", output_field=CharField()
@ -121,6 +125,7 @@ class PortAutocomplete(AutocompleteViewMixin):
).all()
if self.q:
# pylint: disable=unsupported-binary-operation
self.query_set = self.query_set.filter(
Q(full_name__icontains=self.q)
| Q(full_name_stuck__icontains=self.q)
@ -153,6 +158,7 @@ class SwitchBayAutocomplete(AutocompleteViewMixin):
).all()
if self.q:
# pylint: disable=unsupported-binary-operation
self.query_set = self.query_set.filter(
Q(full_name__icontains=self.q)
| Q(dorm_name__icontains=self.q)

View file

@ -9,7 +9,7 @@ from django.db.models.functions import Concat
from reversion.models import Revision
from machines.models import Domain, Machine
from re2o.login import hashNT, makeSecret
from re2o.login import hash_nt, make_secret
from users.models import Adherent, Club, School, User
@ -104,8 +104,8 @@ class Command(BaseCommand):
)
)
u.update(pwd_ntlm=hashNT(password))
u.update(password=makeSecret(password))
u.update(pwd_ntlm=hash_nt(password))
u.update(password=make_secret(password))
self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write("Deletion of the history (this may take some time)...")

View file

@ -933,10 +933,10 @@ class User(
password (string): new password (cleatext) to set.
"""
from re2o.login import hashNT
from re2o.login import hash_nt
super().set_password(password)
self.pwd_ntlm = hashNT(password)
self.pwd_ntlm = hash_nt(password)
return
def confirm_mail(self):