mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-12-23 07:23:46 +00:00
Merge branch 'docstrings_in_english' into 'dev'
Docstring translation See merge request re2o/re2o!520
This commit is contained in:
commit
d51da9ddfa
45 changed files with 4553 additions and 1817 deletions
|
@ -34,7 +34,7 @@ from .models import CustomInvoice, CostEstimate
|
|||
|
||||
|
||||
class FactureAdmin(VersionAdmin):
|
||||
"""Class admin d'une facture, tous les champs"""
|
||||
"""Admin class for invoices."""
|
||||
|
||||
pass
|
||||
|
||||
|
@ -52,32 +52,31 @@ class CustomInvoiceAdmin(VersionAdmin):
|
|||
|
||||
|
||||
class VenteAdmin(VersionAdmin):
|
||||
"""Class admin d'une vente, tous les champs (facture related)"""
|
||||
"""Admin class for purchases."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ArticleAdmin(VersionAdmin):
|
||||
"""Class admin d'un article en vente"""
|
||||
"""Admin class for articles."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BanqueAdmin(VersionAdmin):
|
||||
"""Class admin de la liste des banques (facture related)"""
|
||||
"""Admin class for banks."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class PaiementAdmin(VersionAdmin):
|
||||
"""Class admin d'un moyen de paiement (facture related"""
|
||||
"""Admin class for payment methods."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CotisationAdmin(VersionAdmin):
|
||||
"""Class admin d'une cotisation (date de debut et de fin),
|
||||
Vente related"""
|
||||
"""Admin class for subscriptions."""
|
||||
|
||||
pass
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ def new_cost_estimate(request):
|
|||
"""
|
||||
# The template needs the list of articles (for the JS part)
|
||||
articles = Article.objects.all()
|
||||
# Building the invocie form and the article formset
|
||||
# Building the invoice form and the article formset
|
||||
cost_estimate_form = CostEstimateForm(request.POST or None)
|
||||
|
||||
articles_formset = formset_factory(SelectArticleForm)(
|
||||
|
@ -240,7 +240,7 @@ def new_custom_invoice(request):
|
|||
"""
|
||||
# The template needs the list of articles (for the JS part)
|
||||
articles = Article.objects.all()
|
||||
# Building the invocie form and the article formset
|
||||
# Building the invoice form and the article formset
|
||||
invoice_form = CustomInvoiceForm(request.POST or None)
|
||||
|
||||
articles_formset = formset_factory(SelectArticleForm)(
|
||||
|
@ -366,7 +366,7 @@ def edit_facture(request, facture, **_kwargs):
|
|||
@can_delete(Facture)
|
||||
def del_facture(request, facture, **_kwargs):
|
||||
"""
|
||||
View used to delete an existing invocie.
|
||||
View used to delete an existing invoice.
|
||||
"""
|
||||
if request.method == "POST":
|
||||
facture.delete()
|
||||
|
@ -382,7 +382,7 @@ def del_facture(request, facture, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(CostEstimate)
|
||||
def edit_cost_estimate(request, invoice, **kwargs):
|
||||
# Building the invocie form and the article formset
|
||||
# Building the invoice form and the article formset
|
||||
invoice_form = CostEstimateForm(request.POST or None, instance=invoice)
|
||||
purchases_objects = Vente.objects.filter(facture=invoice)
|
||||
purchase_form_set = modelformset_factory(
|
||||
|
@ -411,7 +411,7 @@ def edit_cost_estimate(request, invoice, **kwargs):
|
|||
@can_edit(CostEstimate)
|
||||
@can_create(CustomInvoice)
|
||||
def cost_estimate_to_invoice(request, cost_estimate, **_kwargs):
|
||||
"""Create a custom invoice from a cos estimate"""
|
||||
"""Create a custom invoice from a cost estimate."""
|
||||
cost_estimate.create_invoice()
|
||||
messages.success(
|
||||
request, _("An invoice was successfully created from your cost estimate.")
|
||||
|
@ -422,7 +422,7 @@ def cost_estimate_to_invoice(request, cost_estimate, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(CustomInvoice)
|
||||
def edit_custom_invoice(request, invoice, **kwargs):
|
||||
# Building the invocie form and the article formset
|
||||
# Building the invoice form and the article formset
|
||||
invoice_form = CustomInvoiceForm(request.POST or None, instance=invoice)
|
||||
purchases_objects = Vente.objects.filter(facture=invoice)
|
||||
purchase_form_set = modelformset_factory(
|
||||
|
@ -498,7 +498,7 @@ def cost_estimate_pdf(request, invoice, **_kwargs):
|
|||
@can_delete(CostEstimate)
|
||||
def del_cost_estimate(request, estimate, **_kwargs):
|
||||
"""
|
||||
View used to delete an existing invocie.
|
||||
View used to delete an existing invoice.
|
||||
"""
|
||||
if request.method == "POST":
|
||||
estimate.delete()
|
||||
|
@ -561,7 +561,7 @@ def custom_invoice_pdf(request, invoice, **_kwargs):
|
|||
@can_delete(CustomInvoice)
|
||||
def del_custom_invoice(request, invoice, **_kwargs):
|
||||
"""
|
||||
View used to delete an existing invocie.
|
||||
View used to delete an existing invoice.
|
||||
"""
|
||||
if request.method == "POST":
|
||||
invoice.delete()
|
||||
|
|
|
@ -53,6 +53,15 @@ CHOICES_TYPE = (
|
|||
|
||||
|
||||
def all_classes(module):
|
||||
"""Get the list of all class names of the module.
|
||||
|
||||
Args:
|
||||
module: the module in which to retrieve classes.
|
||||
|
||||
Returns:
|
||||
A list containing the names of all classes that are defined in
|
||||
the module.
|
||||
"""
|
||||
classes = []
|
||||
|
||||
for name, obj in inspect.getmembers(module):
|
||||
|
@ -63,8 +72,16 @@ def all_classes(module):
|
|||
|
||||
|
||||
def classes_for_action_type(action_type):
|
||||
"""Return the list of class names to be displayed for a
|
||||
given actions type filter"""
|
||||
"""Get the list of class names to be displayed for a given action type
|
||||
filter.
|
||||
|
||||
Args:
|
||||
action_type: the string used to filter the class names.
|
||||
|
||||
Returns:
|
||||
A list containing the class names corresponding to the action type
|
||||
filter.
|
||||
"""
|
||||
if action_type == "users":
|
||||
return [
|
||||
users.models.User.__name__,
|
||||
|
@ -96,7 +113,7 @@ def classes_for_action_type(action_type):
|
|||
|
||||
|
||||
class ActionsSearchForm(Form):
|
||||
"""The form for a simple search"""
|
||||
"""Form used to do an advanced search through the logs."""
|
||||
u = forms.ModelChoiceField(
|
||||
label=_("Performed by"),
|
||||
queryset=users.models.User.objects.all(),
|
||||
|
@ -123,7 +140,7 @@ class ActionsSearchForm(Form):
|
|||
|
||||
|
||||
class MachineHistorySearchForm(Form):
|
||||
"""The form for a simple search"""
|
||||
"""Form used to do a search through the machine histories."""
|
||||
q = forms.CharField(
|
||||
label=_("Search"),
|
||||
max_length=100,
|
||||
|
|
349
logs/models.py
349
logs/models.py
|
@ -69,12 +69,16 @@ def make_version_filter(key, value):
|
|||
|
||||
class MachineHistorySearchEvent:
|
||||
def __init__(self, user, machine, interface, start=None, end=None):
|
||||
"""
|
||||
:param user: User, The user owning the maching at the time of the event
|
||||
:param machine: Version, the machine version related to the interface
|
||||
:param interface: Version, the interface targeted by this event
|
||||
:param start: datetime, the date at which this version was created
|
||||
:param end: datetime, the date at which this version was replace by a new one
|
||||
"""Initialise an instance of MachineHistorySearchEvent.
|
||||
|
||||
Args:
|
||||
user: User, the user owning the machine at the time of the event.
|
||||
machine: Version, the machine version related to the interface.
|
||||
interface: Version, the interface targeted by this event.
|
||||
start: datetime, the date at which this version was created
|
||||
(default: None).
|
||||
end: datetime, the date at which this version was replace by a new
|
||||
one (default: None).
|
||||
"""
|
||||
self.user = user
|
||||
self.machine = machine
|
||||
|
@ -86,9 +90,13 @@ class MachineHistorySearchEvent:
|
|||
self.comment = interface.revision.get_comment() or None
|
||||
|
||||
def is_similar(self, elt2):
|
||||
"""
|
||||
Checks whether two events are similar enough to be merged
|
||||
:return: bool
|
||||
"""Check whether two events are similar enough to be merged.
|
||||
|
||||
Args:
|
||||
elt2: MachineHistorySearchEvent, the event to compare with self.
|
||||
|
||||
Returns:
|
||||
A boolean, True if the events can be merged and False otherwise.
|
||||
"""
|
||||
return (
|
||||
elt2 is not None
|
||||
|
@ -115,10 +123,14 @@ class MachineHistorySearch:
|
|||
self._last_evt = None
|
||||
|
||||
def get(self, search, params):
|
||||
"""
|
||||
:param search: ip or mac to lookup
|
||||
:param params: dict built by the search view
|
||||
:return: list or None, a list of MachineHistorySearchEvent in reverse chronological order
|
||||
"""Get the events in machine histories related to the search.
|
||||
|
||||
Args:
|
||||
search: the IP or MAC address used in the search.
|
||||
params: the dictionary built by the search view.
|
||||
|
||||
Returns:
|
||||
A list of MachineHistorySearchEvent in reverse chronological order.
|
||||
"""
|
||||
self.start = params.get("s", None)
|
||||
self.end = params.get("e", None)
|
||||
|
@ -140,11 +152,12 @@ class MachineHistorySearch:
|
|||
return []
|
||||
|
||||
def _add_revision(self, user, machine, interface):
|
||||
"""
|
||||
Add a new revision to the chronological order
|
||||
:param user: User, The user owning the maching at the time of the event
|
||||
:param machine: Version, the machine version related to the interface
|
||||
:param interface: Version, the interface targeted by this event
|
||||
"""Add a new revision to the chronological order.
|
||||
|
||||
Args:
|
||||
user: User, the user owning the maching at the time of the event.
|
||||
machine: Version, the machine version related to the interface.
|
||||
interface: Version, the interface targeted by this event.
|
||||
"""
|
||||
evt = MachineHistorySearchEvent(user, machine, interface)
|
||||
evt.start_date = interface.revision.date_created
|
||||
|
@ -171,10 +184,15 @@ class MachineHistorySearch:
|
|||
self._last_evt = evt
|
||||
|
||||
def _get_interfaces_for_ip(self, ip):
|
||||
"""
|
||||
:param ip: str
|
||||
:return: An iterable object with the Version objects
|
||||
of Interfaces with the given IP
|
||||
"""Get the Version objects of interfaces with the given IP
|
||||
address.
|
||||
|
||||
Args:
|
||||
ip: the string corresponding to the IP address.
|
||||
|
||||
Returns:
|
||||
An iterable object with the Version objects of interfaces with the
|
||||
given IP address.
|
||||
"""
|
||||
# TODO: What if ip list was deleted?
|
||||
try:
|
||||
|
@ -189,10 +207,15 @@ class MachineHistorySearch:
|
|||
)
|
||||
|
||||
def _get_interfaces_for_mac(self, mac):
|
||||
"""
|
||||
:param mac: str
|
||||
:return: An iterable object with the Version objects
|
||||
of Interfaces with the given MAC address
|
||||
"""Get the Version objects of interfaces with the given MAC
|
||||
address.
|
||||
|
||||
Args:
|
||||
mac: the string corresponding to the MAC address.
|
||||
|
||||
Returns:
|
||||
An iterable object with the Version objects of interfaces with the
|
||||
given MAC address.
|
||||
"""
|
||||
return (
|
||||
Version.objects.get_for_model(Interface)
|
||||
|
@ -201,10 +224,14 @@ class MachineHistorySearch:
|
|||
)
|
||||
|
||||
def _get_machines_for_interface(self, interface):
|
||||
"""
|
||||
:param interface: Version, the interface for which to find the machines
|
||||
:return: An iterable object with the Version objects of Machine to
|
||||
which the given interface was attributed
|
||||
"""Get the Version objects of machines with the given interface.
|
||||
|
||||
Args:
|
||||
interface: Version, the interface used to find machines.
|
||||
|
||||
Returns:
|
||||
An iterable object with the Version objects of machines to which
|
||||
the given interface was assigned.
|
||||
"""
|
||||
machine_id = interface.field_dict["machine_id"]
|
||||
return (
|
||||
|
@ -214,18 +241,27 @@ class MachineHistorySearch:
|
|||
)
|
||||
|
||||
def _get_user_for_machine(self, machine):
|
||||
"""
|
||||
:param machine: Version, the machine of which the owner must be found
|
||||
:return: The user to which the given machine belongs
|
||||
"""Get the User instance owning the given machine.
|
||||
|
||||
Args:
|
||||
machine: Version, the machine used to find its owner.
|
||||
|
||||
Returns:
|
||||
The User instance of the owner of the given machine.
|
||||
"""
|
||||
# TODO: What if user was deleted?
|
||||
user_id = machine.field_dict["user_id"]
|
||||
return User.objects.get(id=user_id)
|
||||
|
||||
def _get_by_ip(self, ip):
|
||||
"""
|
||||
:param ip: str, The IP to lookup
|
||||
:returns: list, a list of MachineHistorySearchEvent
|
||||
"""Get events related to the given IP address.
|
||||
|
||||
Args:
|
||||
ip: the string corresponding to the IP address.
|
||||
|
||||
Returns:
|
||||
A list of MachineHistorySearchEvent related to the given IP
|
||||
address.
|
||||
"""
|
||||
interfaces = self._get_interfaces_for_ip(ip)
|
||||
|
||||
|
@ -239,9 +275,14 @@ class MachineHistorySearch:
|
|||
return self.events
|
||||
|
||||
def _get_by_mac(self, mac):
|
||||
"""
|
||||
:param mac: str, The MAC address to lookup
|
||||
:returns: list, a list of MachineHistorySearchEvent
|
||||
"""Get events related to the given MAC address.
|
||||
|
||||
Args:
|
||||
mac: the string corresponding to the MAC address.
|
||||
|
||||
Returns:
|
||||
A list of MachineHistorySearchEvent related to the given MAC
|
||||
address.
|
||||
"""
|
||||
interfaces = self._get_interfaces_for_mac(mac)
|
||||
|
||||
|
@ -261,10 +302,10 @@ class MachineHistorySearch:
|
|||
|
||||
class RelatedHistory:
|
||||
def __init__(self, version):
|
||||
"""
|
||||
:param name: Name of this instance
|
||||
:param model_name: Name of the related model (e.g. "user")
|
||||
:param object_id: ID of the related object
|
||||
"""Initialise an instance of RelatedHistory.
|
||||
|
||||
Args:
|
||||
version: Version, the version related to the history.
|
||||
"""
|
||||
self.version = version
|
||||
self.app_name = version.content_type.app_label
|
||||
|
@ -287,10 +328,14 @@ class RelatedHistory:
|
|||
|
||||
class HistoryEvent:
|
||||
def __init__(self, version, previous_version=None, edited_fields=None):
|
||||
"""
|
||||
:param version: Version, the version of the object for this event
|
||||
:param previous_version: Version, the version of the object before this event
|
||||
:param edited_fields: list, The list of modified fields by this event
|
||||
"""Initialise an instance of HistoryEvent.
|
||||
|
||||
Args:
|
||||
version: Version, the version of the object for this event.
|
||||
previous_version: Version, the version of the object before this
|
||||
event (default: None).
|
||||
edited_fields: list, The list of modified fields by this event
|
||||
(default: None).
|
||||
"""
|
||||
self.version = version
|
||||
self.previous_version = previous_version
|
||||
|
@ -300,11 +345,15 @@ class HistoryEvent:
|
|||
self.comment = version.revision.get_comment() or None
|
||||
|
||||
def _repr(self, name, value):
|
||||
"""
|
||||
Returns the best representation of the given field
|
||||
:param name: the name of the field
|
||||
:param value: the value of the field
|
||||
:return: object
|
||||
"""Get the appropriate representation of the given field.
|
||||
|
||||
Args:
|
||||
name: the name of the field
|
||||
value: the value of the field
|
||||
|
||||
Returns:
|
||||
The string corresponding to the appropriate representation of the
|
||||
given field.
|
||||
"""
|
||||
if value is None:
|
||||
return _("None")
|
||||
|
@ -312,10 +361,14 @@ class HistoryEvent:
|
|||
return value
|
||||
|
||||
def edits(self, hide=[]):
|
||||
"""
|
||||
Build a list of the changes performed during this event
|
||||
:param hide: list, the list of fields for which not to show details
|
||||
:return: str
|
||||
"""Get the list of the changes performed during this event.
|
||||
|
||||
Args:
|
||||
hide: the list of fields for which not to show details (default:
|
||||
[]).
|
||||
|
||||
Returns:
|
||||
The list of fields edited by the event to display.
|
||||
"""
|
||||
edits = []
|
||||
|
||||
|
@ -342,10 +395,15 @@ class History:
|
|||
self.event_type = HistoryEvent
|
||||
|
||||
def get(self, instance_id, model):
|
||||
"""
|
||||
:param instance_id: int, The id of the instance to lookup
|
||||
:param model: class, The type of object to lookup
|
||||
:return: list or None, a list of HistoryEvent, in reverse chronological order
|
||||
"""Get the list of history events of the given object.
|
||||
|
||||
Args:
|
||||
instance_id: int, the id of the instance to lookup.
|
||||
model: class, the type of object to lookup.
|
||||
|
||||
Returns:
|
||||
A list of HistoryEvent, in reverse chronological order, related to
|
||||
the given object or None if no version was found.
|
||||
"""
|
||||
self.events = []
|
||||
|
||||
|
@ -368,12 +426,16 @@ class History:
|
|||
return self.events[::-1]
|
||||
|
||||
def _compute_diff(self, v1, v2, ignoring=[]):
|
||||
"""
|
||||
Find the edited field between two versions
|
||||
:param v1: Version
|
||||
:param v2: Version
|
||||
:param ignoring: List, a list of fields to ignore
|
||||
:return: List of field names
|
||||
"""Find the edited fields between two versions.
|
||||
|
||||
Args:
|
||||
v1: Version to compare.
|
||||
v2: Version to compare.
|
||||
ignoring: a list of fields to ignore.
|
||||
|
||||
Returns:
|
||||
The list of field names in v1 that are different from the ones in
|
||||
v2.
|
||||
"""
|
||||
fields = []
|
||||
|
||||
|
@ -384,9 +446,10 @@ class History:
|
|||
return fields
|
||||
|
||||
def _add_revision(self, version):
|
||||
"""
|
||||
Add a new revision to the chronological order
|
||||
:param version: Version, The version of the interface for this event
|
||||
"""Add a new revision to the chronological order.
|
||||
|
||||
Args:
|
||||
version: Version, the version of the interface for this event.
|
||||
"""
|
||||
diff = None
|
||||
if self._last_version is not None:
|
||||
|
@ -427,6 +490,15 @@ class VersionAction(HistoryEvent):
|
|||
return apps.get_model(self.application(), self.model_name())
|
||||
|
||||
def edits(self, hide=["password", "pwd_ntlm", "gpg_fingerprint"]):
|
||||
"""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", "gpg_fingerprint"]).
|
||||
|
||||
Returns:
|
||||
The list of fields edited by the event to display.
|
||||
"""
|
||||
self.previous_version = self._previous_version()
|
||||
|
||||
if self.previous_version is None:
|
||||
|
@ -436,6 +508,12 @@ class VersionAction(HistoryEvent):
|
|||
return super(VersionAction, self).edits(hide)
|
||||
|
||||
def _previous_version(self):
|
||||
"""Get the previous version of self.
|
||||
|
||||
Returns:
|
||||
The Version corresponding to the previous version of self, or None
|
||||
in case of exception.
|
||||
"""
|
||||
model = self.object_type()
|
||||
try:
|
||||
query = (
|
||||
|
@ -451,12 +529,16 @@ class VersionAction(HistoryEvent):
|
|||
return None
|
||||
|
||||
def _compute_diff(self, v1, v2, ignoring=["pwd_ntlm"]):
|
||||
"""
|
||||
Find the edited field between two versions
|
||||
:param v1: Version
|
||||
:param v2: Version
|
||||
:param ignoring: List, a list of fields to ignore
|
||||
:return: List of field names
|
||||
"""Find the edited fields between two versions.
|
||||
|
||||
Args:
|
||||
v1: Version to compare.
|
||||
v2: Version to compare.
|
||||
ignoring: a list of fields to ignore (default: ["pwd_ntlm"]).
|
||||
|
||||
Returns:
|
||||
The list of field names in v1 that are different from the ones in
|
||||
v2.
|
||||
"""
|
||||
fields = []
|
||||
|
||||
|
@ -468,7 +550,8 @@ class VersionAction(HistoryEvent):
|
|||
|
||||
|
||||
class RevisionAction:
|
||||
"""A Revision may group multiple Version objects together"""
|
||||
"""A Revision may group multiple Version objects together."""
|
||||
|
||||
def __init__(self, revision):
|
||||
self.performed_by = revision.user
|
||||
self.revision = revision
|
||||
|
@ -486,9 +569,13 @@ class RevisionAction:
|
|||
|
||||
class ActionsSearch:
|
||||
def get(self, params):
|
||||
"""
|
||||
:param params: dict built by the search view
|
||||
:return: QuerySet of Revision objects
|
||||
"""Get the Revision objects corresponding to the search.
|
||||
|
||||
Args:
|
||||
params: dictionary built by the search view.
|
||||
|
||||
Returns:
|
||||
The QuerySet of Revision objects corresponding to the search.
|
||||
"""
|
||||
user = params.get("u", None)
|
||||
start = params.get("s", None)
|
||||
|
@ -540,11 +627,15 @@ class ActionsSearch:
|
|||
|
||||
class UserHistoryEvent(HistoryEvent):
|
||||
def _repr(self, name, value):
|
||||
"""
|
||||
Returns the best representation of the given field
|
||||
:param name: the name of the field
|
||||
:param value: the value of the field
|
||||
:return: object
|
||||
"""Get the appropriate representation of the given field.
|
||||
|
||||
Args:
|
||||
name: the name of the field
|
||||
value: the value of the field
|
||||
|
||||
Returns:
|
||||
The string corresponding to the appropriate representation of the
|
||||
given field.
|
||||
"""
|
||||
if name == "groups":
|
||||
if len(value) == 0:
|
||||
|
@ -599,10 +690,14 @@ class UserHistoryEvent(HistoryEvent):
|
|||
return super(UserHistoryEvent, self)._repr(name, value)
|
||||
|
||||
def edits(self, hide=["password", "pwd_ntlm", "gpg_fingerprint"]):
|
||||
"""
|
||||
Build a list of the changes performed during this event
|
||||
:param hide: list, the list of fields for which not to show details
|
||||
:return: str
|
||||
"""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", "gpg_fingerprint"]).
|
||||
|
||||
Returns:
|
||||
The list of fields edited by the event to display.
|
||||
"""
|
||||
return super(UserHistoryEvent, self).edits(hide)
|
||||
|
||||
|
@ -631,9 +726,14 @@ class UserHistory(History):
|
|||
self.event_type = UserHistoryEvent
|
||||
|
||||
def get(self, user_id, model):
|
||||
"""
|
||||
:param user_id: int, the id of the user to lookup
|
||||
:return: list or None, a list of UserHistoryEvent, in reverse chronological order
|
||||
"""Get the the list of UserHistoryEvent related to the object.
|
||||
|
||||
Args:
|
||||
user_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 = []
|
||||
|
||||
|
@ -710,10 +810,10 @@ class UserHistory(History):
|
|||
)
|
||||
|
||||
def _add_revision(self, version):
|
||||
"""
|
||||
Add a new revision to the chronological order
|
||||
:param user: User, The user displayed in this history
|
||||
:param version: Version, The version of the user for this event
|
||||
"""Add a new revision to the chronological order.
|
||||
|
||||
Args:
|
||||
version: Version, the version of the user for this event.
|
||||
"""
|
||||
diff = None
|
||||
if self._last_version is not None:
|
||||
|
@ -736,11 +836,15 @@ class UserHistory(History):
|
|||
|
||||
class MachineHistoryEvent(HistoryEvent):
|
||||
def _repr(self, name, value):
|
||||
"""
|
||||
Returns the best representation of the given field
|
||||
:param name: the name of the field
|
||||
:param value: the value of the field
|
||||
:return: object
|
||||
"""Return the appropriate representation of the given field.
|
||||
|
||||
Args:
|
||||
name: the name of the field
|
||||
value: the value of the field
|
||||
|
||||
Returns:
|
||||
The string corresponding to the appropriate representation of the
|
||||
given field.
|
||||
"""
|
||||
if name == "user_id":
|
||||
try:
|
||||
|
@ -757,6 +861,15 @@ class MachineHistory(History):
|
|||
self.event_type = MachineHistoryEvent
|
||||
|
||||
def get(self, machine_id, model):
|
||||
"""Get the the list of MachineHistoryEvent related to the object.
|
||||
|
||||
Args:
|
||||
machine_id: int, the id of the machine to lookup.
|
||||
|
||||
Returns:
|
||||
The list of MachineHistoryEvent, in reverse chronological order,
|
||||
related to the object.
|
||||
"""
|
||||
self.related = (
|
||||
Version.objects.get_for_model(Interface)
|
||||
.filter(make_version_filter("machine", machine_id))
|
||||
|
@ -772,11 +885,15 @@ class MachineHistory(History):
|
|||
|
||||
class InterfaceHistoryEvent(HistoryEvent):
|
||||
def _repr(self, name, value):
|
||||
"""
|
||||
Returns the best representation of the given field
|
||||
:param name: the name of the field
|
||||
:param value: the value of the field
|
||||
:return: object
|
||||
"""Get the appropriate representation of the given field.
|
||||
|
||||
Args:
|
||||
name: the name of the field
|
||||
value: the value of the field
|
||||
|
||||
Returns:
|
||||
The string corresponding to the appropriate representation of the
|
||||
given field.
|
||||
"""
|
||||
if name == "ipv4_id" and value is not None:
|
||||
try:
|
||||
|
@ -813,6 +930,15 @@ class InterfaceHistory(History):
|
|||
self.event_type = InterfaceHistoryEvent
|
||||
|
||||
def get(self, interface_id, model):
|
||||
"""Get the the list of InterfaceHistoryEvent related to the object.
|
||||
|
||||
Args:
|
||||
interface_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)
|
||||
|
||||
|
||||
|
@ -829,10 +955,15 @@ HISTORY_CLASS_MAPPING = {
|
|||
|
||||
|
||||
def get_history_class(model):
|
||||
"""
|
||||
Find the mos appropriate History subclass to represent
|
||||
the given model's history
|
||||
:model: class
|
||||
"""Get the most appropriate History subclass to represent the given model's
|
||||
history.
|
||||
|
||||
Args:
|
||||
model: the class for which to get the history.
|
||||
|
||||
Returns:
|
||||
The most appropriate History subclass for the given model's history,
|
||||
or History if no other was found.
|
||||
"""
|
||||
try:
|
||||
return HISTORY_CLASS_MAPPING[model]()
|
||||
|
|
|
@ -19,9 +19,8 @@
|
|||
# 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.
|
||||
"""
|
||||
Urls de l'application logs, pointe vers les fonctions de views.
|
||||
Inclu dans le re2o.urls
|
||||
"""logs.urls
|
||||
The defined URLs for the logs app. Included in re2o.urls.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
|
|
@ -24,16 +24,16 @@
|
|||
# App de gestion des statistiques pour re2o
|
||||
# Gabriel Détraz
|
||||
# Gplv2
|
||||
"""
|
||||
Vues des logs et statistiques générales.
|
||||
"""logs.views
|
||||
Views of logs and general statistics.
|
||||
|
||||
La vue index générale affiche une selection des dernières actions,
|
||||
classées selon l'importance, avec date, et user formatés.
|
||||
The general indew view displays a list of the last actions, sorted by
|
||||
importance, with date and user formatted.
|
||||
|
||||
Stats_logs renvoie l'ensemble des logs.
|
||||
stats_logs returns all the logs.
|
||||
|
||||
Les autres vues sont thématiques, ensemble des statistiques et du
|
||||
nombre d'objets par models, nombre d'actions par user, etc
|
||||
The other views are related to specific topics, with statistics for number of
|
||||
objects for per model, number of actions per user etc.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -113,8 +113,7 @@ from .forms import ActionsSearchForm, MachineHistorySearchForm
|
|||
@login_required
|
||||
@can_view_app("logs")
|
||||
def index(request):
|
||||
"""Affiche les logs affinés, date reformatées, selectionne
|
||||
les event importants (ajout de droits, ajout de ban/whitelist)"""
|
||||
"""View used to display summary of events about users."""
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
# The types of content kept for display
|
||||
content_type_filter = ["ban", "whitelist", "vente", "interface", "user"]
|
||||
|
@ -155,8 +154,7 @@ def index(request):
|
|||
@login_required
|
||||
@can_view_all(GeneralOption)
|
||||
def stats_logs(request):
|
||||
"""Affiche l'ensemble des logs et des modifications sur les objets,
|
||||
classés par date croissante, en vrac"""
|
||||
"""View used to do an advanced search through the logs."""
|
||||
actions_form = ActionsSearchForm(request.GET or None)
|
||||
|
||||
if actions_form.is_valid():
|
||||
|
@ -185,7 +183,7 @@ def stats_logs(request):
|
|||
@login_required
|
||||
@can_edit_history
|
||||
def revert_action(request, revision_id):
|
||||
""" Annule l'action en question """
|
||||
"""View used to revert actions."""
|
||||
try:
|
||||
revision = Revision.objects.get(id=revision_id)
|
||||
except Revision.DoesNotExist:
|
||||
|
@ -204,9 +202,10 @@ def revert_action(request, revision_id):
|
|||
@login_required
|
||||
@can_view_all(IpList, Interface, User)
|
||||
def stats_general(request):
|
||||
"""Statistiques générales affinées sur les ip, activées, utilisées par
|
||||
range, et les statistiques générales sur les users : users actifs,
|
||||
cotisants, activés, archivés, etc"""
|
||||
"""View used to display general statistics about users (activated,
|
||||
disabled, archived etc.) and IP addresses (ranges, number of assigned
|
||||
addresses etc.).
|
||||
"""
|
||||
ip_dict = dict()
|
||||
for ip_range in IpType.objects.select_related("vlan").all():
|
||||
all_ip = IpList.objects.filter(ip_type=ip_range)
|
||||
|
@ -377,9 +376,9 @@ def stats_general(request):
|
|||
@login_required
|
||||
@can_view_app("users", "cotisations", "machines", "topologie")
|
||||
def stats_models(request):
|
||||
"""Statistiques générales, affiche les comptages par models:
|
||||
nombre d'users, d'écoles, de droits, de bannissements,
|
||||
de factures, de ventes, de banque, de machines, etc"""
|
||||
"""View used to display general statistics about the number of objects
|
||||
stored in the database, for each model.
|
||||
"""
|
||||
stats = {
|
||||
_("Users (members and clubs)"): {
|
||||
"users": [User._meta.verbose_name, User.objects.count()],
|
||||
|
@ -452,10 +451,9 @@ def stats_models(request):
|
|||
@login_required
|
||||
@can_view_app("users")
|
||||
def stats_users(request):
|
||||
"""Affiche les statistiques base de données aggrégées par user :
|
||||
nombre de machines par user, d'etablissements par user,
|
||||
de moyens de paiements par user, de banque par user,
|
||||
de bannissement par user, etc"""
|
||||
"""View used to display statistics aggregated by user (number of machines,
|
||||
bans, whitelists, rights etc.).
|
||||
"""
|
||||
stats = {
|
||||
User._meta.verbose_name: {
|
||||
Machine._meta.verbose_name_plural: User.objects.annotate(
|
||||
|
@ -496,9 +494,7 @@ def stats_users(request):
|
|||
@login_required
|
||||
@can_view_app("users")
|
||||
def stats_actions(request):
|
||||
"""Vue qui affiche les statistiques de modifications d'objets par
|
||||
utilisateurs.
|
||||
Affiche le nombre de modifications aggrégées par utilisateurs"""
|
||||
"""View used to display the number of actions, aggregated by user."""
|
||||
stats = {
|
||||
User._meta.verbose_name: {
|
||||
_("actions"): User.objects.annotate(num=Count("revision")).order_by("-num")[
|
||||
|
@ -512,8 +508,9 @@ def stats_actions(request):
|
|||
@login_required
|
||||
@can_view_app("users")
|
||||
def stats_search_machine_history(request):
|
||||
"""View which displays the history of machines with the given
|
||||
une IP or MAC adresse"""
|
||||
"""View used to display the history of machines with the given IP or MAC
|
||||
address.
|
||||
"""
|
||||
history_form = MachineHistorySearchForm(request.GET or None)
|
||||
if history_form.is_valid():
|
||||
history = MachineHistorySearch()
|
||||
|
|
|
@ -22,15 +22,15 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Formulaires d'ajout, edition et suppressions de :
|
||||
- machines
|
||||
- interfaces
|
||||
- domain (noms de machine)
|
||||
- alias (cname)
|
||||
- service (dhcp, dns..)
|
||||
- ns (serveur dns)
|
||||
- mx (serveur mail)
|
||||
- ports ouverts et profils d'ouverture par interface
|
||||
Forms to create, edit and delete:
|
||||
* machines
|
||||
* interfaces
|
||||
* domains (machine names)
|
||||
* aliases (CNAME)
|
||||
* services (DHCP, DNS...)
|
||||
* NS records (DNS server)
|
||||
* MX records (mail serveur)
|
||||
* open ports and ports opening for interfaces
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -66,7 +66,7 @@ from .models import (
|
|||
|
||||
|
||||
class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Formulaire d'édition d'une machine"""
|
||||
"""Form used to edit a machine."""
|
||||
|
||||
class Meta:
|
||||
model = Machine
|
||||
|
@ -79,14 +79,14 @@ class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class NewMachineForm(EditMachineForm):
|
||||
"""Creation d'une machine, ne renseigne que le nom"""
|
||||
"""Form used to create a machine."""
|
||||
|
||||
class Meta(EditMachineForm.Meta):
|
||||
fields = ["name"]
|
||||
|
||||
|
||||
class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Edition d'une interface. Edition complète"""
|
||||
"""Form used to edit an interface."""
|
||||
|
||||
class Meta:
|
||||
model = Interface
|
||||
|
@ -127,15 +127,14 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class AddInterfaceForm(EditInterfaceForm):
|
||||
"""Ajout d'une interface à une machine. En fonction des droits,
|
||||
affiche ou non l'ensemble des ip disponibles"""
|
||||
"""Form used to add an interface to a machine."""
|
||||
|
||||
class Meta(EditInterfaceForm.Meta):
|
||||
fields = ["machine_type", "ipv4", "mac_address", "details"]
|
||||
|
||||
|
||||
class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Ajout d'un alias (et edition), CNAME, contenant nom et extension"""
|
||||
"""Form used to add and edit an alias (CNAME)."""
|
||||
|
||||
class Meta:
|
||||
model = Domain
|
||||
|
@ -153,7 +152,9 @@ class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Ajout et edition d'un enregistrement de nom, relié à interface"""
|
||||
"""Form used to add and edit a domain record, related to an
|
||||
interface.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Domain
|
||||
|
@ -165,7 +166,7 @@ class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class DelAliasForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs objets alias"""
|
||||
"""Form used to delete one or several aliases."""
|
||||
|
||||
alias = forms.ModelMultipleChoiceField(
|
||||
queryset=Domain.objects.all(),
|
||||
|
@ -182,7 +183,7 @@ class DelAliasForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class MachineTypeForm(FormRevMixin, ModelForm):
|
||||
"""Ajout et edition d'un machinetype, relié à un iptype"""
|
||||
"""Form used to add and edit a machine type, related to an IP type."""
|
||||
|
||||
class Meta:
|
||||
model = MachineType
|
||||
|
@ -196,7 +197,7 @@ class MachineTypeForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelMachineTypeForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs machinetype"""
|
||||
"""Form used to delete one or several machines types."""
|
||||
|
||||
machinetypes = forms.ModelMultipleChoiceField(
|
||||
queryset=MachineType.objects.none(),
|
||||
|
@ -214,8 +215,9 @@ class DelMachineTypeForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class IpTypeForm(FormRevMixin, ModelForm):
|
||||
"""Formulaire d'ajout d'un iptype. Pas d'edition de l'ip de start et de
|
||||
stop après creation"""
|
||||
"""Form used to add an IP type. The start and stop IP addresses cannot
|
||||
be changed afterwards.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = IpType
|
||||
|
@ -228,8 +230,9 @@ class IpTypeForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditIpTypeForm(IpTypeForm):
|
||||
"""Edition d'un iptype. Pas d'edition du rangev4 possible, car il faudrait
|
||||
synchroniser les objets iplist"""
|
||||
"""Form used to edit an IP type. The start and stop IP addresses cannot
|
||||
be changed.
|
||||
"""
|
||||
|
||||
class Meta(IpTypeForm.Meta):
|
||||
fields = [
|
||||
|
@ -248,7 +251,7 @@ class EditIpTypeForm(IpTypeForm):
|
|||
|
||||
|
||||
class DelIpTypeForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs iptype"""
|
||||
"""Form used to delete one or several IP types."""
|
||||
|
||||
iptypes = forms.ModelMultipleChoiceField(
|
||||
queryset=IpType.objects.none(),
|
||||
|
@ -266,7 +269,7 @@ class DelIpTypeForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class ExtensionForm(FormRevMixin, ModelForm):
|
||||
"""Formulaire d'ajout et edition d'une extension"""
|
||||
"""Form used to add and edit extensions."""
|
||||
|
||||
class Meta:
|
||||
model = Extension
|
||||
|
@ -283,7 +286,7 @@ class ExtensionForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelExtensionForm(FormRevMixin, Form):
|
||||
"""Suppression d'une ou plusieurs extensions"""
|
||||
"""Form used to delete one or several extensions."""
|
||||
|
||||
extensions = forms.ModelMultipleChoiceField(
|
||||
queryset=Extension.objects.none(),
|
||||
|
@ -301,7 +304,7 @@ class DelExtensionForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Gestion des ipv6 d'une machine"""
|
||||
"""Form used to manage lists of IPv6 addresses."""
|
||||
|
||||
class Meta:
|
||||
model = Ipv6List
|
||||
|
@ -313,7 +316,7 @@ class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class SOAForm(FormRevMixin, ModelForm):
|
||||
"""Ajout et edition d'un SOA"""
|
||||
"""Form used to add and edit SOA records."""
|
||||
|
||||
class Meta:
|
||||
model = SOA
|
||||
|
@ -325,7 +328,7 @@ class SOAForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelSOAForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs SOA"""
|
||||
"""Form used to delete one or several SOA records."""
|
||||
|
||||
soa = forms.ModelMultipleChoiceField(
|
||||
queryset=SOA.objects.none(),
|
||||
|
@ -343,7 +346,7 @@ class DelSOAForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class MxForm(FormRevMixin, ModelForm):
|
||||
"""Ajout et edition d'un MX"""
|
||||
"""Form used to add and edit MX records."""
|
||||
|
||||
class Meta:
|
||||
model = Mx
|
||||
|
@ -358,7 +361,7 @@ class MxForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelMxForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs MX"""
|
||||
"""Form used to delete one or several MX records."""
|
||||
|
||||
mx = forms.ModelMultipleChoiceField(
|
||||
queryset=Mx.objects.none(),
|
||||
|
@ -376,9 +379,9 @@ class DelMxForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class NsForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un NS pour une zone
|
||||
On exclue les CNAME dans les objets domain (interdit par la rfc)
|
||||
donc on prend uniquemet """
|
||||
"""Form used to add and edit NS records. Only interface names are
|
||||
available because CNAME aliases should not be used in the records.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Ns
|
||||
|
@ -393,7 +396,7 @@ class NsForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelNsForm(FormRevMixin, Form):
|
||||
"""Suppresion d'un ou plusieurs NS"""
|
||||
"""Form used to delete one or several NS records."""
|
||||
|
||||
nss = forms.ModelMultipleChoiceField(
|
||||
queryset=Ns.objects.none(),
|
||||
|
@ -411,7 +414,7 @@ class DelNsForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class TxtForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un txt pour une zone"""
|
||||
"""Form used to add and edit TXT records."""
|
||||
|
||||
class Meta:
|
||||
model = Txt
|
||||
|
@ -423,7 +426,7 @@ class TxtForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelTxtForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs TXT"""
|
||||
"""Form used to delete one or several TXT records."""
|
||||
|
||||
txt = forms.ModelMultipleChoiceField(
|
||||
queryset=Txt.objects.none(),
|
||||
|
@ -441,7 +444,7 @@ class DelTxtForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class DNameForm(FormRevMixin, ModelForm):
|
||||
"""Add a DNAME entry for a zone"""
|
||||
"""Form used to add and edit DNAME records."""
|
||||
|
||||
class Meta:
|
||||
model = DName
|
||||
|
@ -453,7 +456,7 @@ class DNameForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelDNameForm(FormRevMixin, Form):
|
||||
"""Delete a set of DNAME entries"""
|
||||
"""Form used to delete one or several DNAME records."""
|
||||
|
||||
dnames = forms.ModelMultipleChoiceField(
|
||||
queryset=Txt.objects.none(),
|
||||
|
@ -471,7 +474,7 @@ class DelDNameForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class SrvForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un srv pour une zone"""
|
||||
"""Form used to add and edit SRV records."""
|
||||
|
||||
class Meta:
|
||||
model = Srv
|
||||
|
@ -483,7 +486,7 @@ class SrvForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelSrvForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs Srv"""
|
||||
"""Form used to delete one or several SRV records."""
|
||||
|
||||
srv = forms.ModelMultipleChoiceField(
|
||||
queryset=Srv.objects.none(),
|
||||
|
@ -501,8 +504,7 @@ class DelSrvForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class NasForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un type de nas (machine d'authentification,
|
||||
swicths, bornes...)"""
|
||||
"""Form used to create and edit NAS devices."""
|
||||
|
||||
class Meta:
|
||||
model = Nas
|
||||
|
@ -514,7 +516,7 @@ class NasForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelNasForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs nas"""
|
||||
"""Form used to delete one or several NAS devices."""
|
||||
|
||||
nas = forms.ModelMultipleChoiceField(
|
||||
queryset=Nas.objects.none(),
|
||||
|
@ -532,7 +534,7 @@ class DelNasForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class RoleForm(FormRevMixin, ModelForm):
|
||||
"""Add and edit role."""
|
||||
"""Form used to add and edit roles."""
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
|
@ -547,7 +549,7 @@ class RoleForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelRoleForm(FormRevMixin, Form):
|
||||
"""Deletion of one or several roles."""
|
||||
"""Form used to delete one or several roles."""
|
||||
|
||||
role = forms.ModelMultipleChoiceField(
|
||||
queryset=Role.objects.none(),
|
||||
|
@ -565,7 +567,7 @@ class DelRoleForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class ServiceForm(FormRevMixin, ModelForm):
|
||||
"""Ajout et edition d'une classe de service : dns, dhcp, etc"""
|
||||
"""Form to add and edit services (DHCP, DNS etc.)."""
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
|
@ -589,7 +591,7 @@ class ServiceForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelServiceForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs service"""
|
||||
"""Form used to delete one or several services."""
|
||||
|
||||
service = forms.ModelMultipleChoiceField(
|
||||
queryset=Service.objects.none(),
|
||||
|
@ -607,7 +609,7 @@ class DelServiceForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class VlanForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un vlan : id, nom"""
|
||||
"""Form used to add and edit VLANs."""
|
||||
|
||||
class Meta:
|
||||
model = Vlan
|
||||
|
@ -619,7 +621,7 @@ class VlanForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditOptionVlanForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un vlan : id, nom"""
|
||||
"""Form used to edit the options of a VLAN."""
|
||||
|
||||
class Meta:
|
||||
model = Vlan
|
||||
|
@ -631,7 +633,7 @@ class EditOptionVlanForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelVlanForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs vlans"""
|
||||
"""Form used to delete one or several VLANs."""
|
||||
|
||||
vlan = forms.ModelMultipleChoiceField(
|
||||
queryset=Vlan.objects.none(),
|
||||
|
@ -649,8 +651,7 @@ class DelVlanForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
|
||||
"""Edition de la liste des profils d'ouverture de ports
|
||||
pour l'interface"""
|
||||
"""Form to edit the ports opening list of an interface."""
|
||||
|
||||
class Meta:
|
||||
model = Interface
|
||||
|
@ -664,8 +665,7 @@ class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditOuverturePortListForm(FormRevMixin, ModelForm):
|
||||
"""Edition de la liste des ports et profils d'ouverture
|
||||
des ports"""
|
||||
"""Form used to add and edit ports opening lists."""
|
||||
|
||||
class Meta:
|
||||
model = OuverturePortList
|
||||
|
@ -677,7 +677,7 @@ class EditOuverturePortListForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class SshFpForm(FormRevMixin, ModelForm):
|
||||
"""Edits a SSHFP record."""
|
||||
"""Form used to add and edit SSHFP records."""
|
||||
|
||||
class Meta:
|
||||
model = SshFp
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -211,10 +211,11 @@ def generate_ipv4_mbf_param(form_obj, is_type_tt):
|
|||
@can_create(Machine)
|
||||
@can_edit(User)
|
||||
def new_machine(request, user, **_kwargs):
|
||||
""" Fonction de creation d'une machine. Cree l'objet machine,
|
||||
le sous objet interface et l'objet domain à partir de model forms.
|
||||
Trop complexe, devrait être simplifié"""
|
||||
"""View used to create machines.
|
||||
|
||||
Creates the object, the underlying interface and domain objects from model
|
||||
forms. Too complex, should be simplified.
|
||||
"""
|
||||
machine = NewMachineForm(request.POST or None, user=request.user)
|
||||
interface = AddInterfaceForm(request.POST or None, user=request.user)
|
||||
domain = DomainForm(request.POST or None, user=user, initial={'name': user.get_next_domain_name()})
|
||||
|
@ -249,10 +250,10 @@ def new_machine(request, user, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(Interface)
|
||||
def edit_interface(request, interface_instance, **_kwargs):
|
||||
""" Edition d'une interface. Distingue suivant les droits les valeurs
|
||||
de interfaces et machines que l'user peut modifier infra permet de
|
||||
modifier le propriétaire"""
|
||||
"""View used to edit interfaces.
|
||||
|
||||
The values a user can change depends on their rights.
|
||||
"""
|
||||
machine_form = EditMachineForm(
|
||||
request.POST or None, instance=interface_instance.machine, user=request.user
|
||||
)
|
||||
|
@ -295,7 +296,7 @@ def edit_interface(request, interface_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Machine)
|
||||
def del_machine(request, machine, **_kwargs):
|
||||
""" Supprime une machine, interfaces en mode cascade"""
|
||||
"""View used to delete machines, and the interfaces in cascade."""
|
||||
if request.method == "POST":
|
||||
machine.delete()
|
||||
messages.success(request, _("The machine was deleted."))
|
||||
|
@ -311,8 +312,9 @@ def del_machine(request, machine, **_kwargs):
|
|||
@can_create(Interface)
|
||||
@can_edit(Machine)
|
||||
def new_interface(request, machine, **_kwargs):
|
||||
""" Ajoute une interface et son domain associé à une machine existante"""
|
||||
|
||||
"""View used to create interfaces and the associated domains related to a
|
||||
machine.
|
||||
"""
|
||||
interface_form = AddInterfaceForm(request.POST or None, user=request.user)
|
||||
domain_form = DomainForm(request.POST or None, user=request.user, initial={'name': machine.user.get_next_domain_name()})
|
||||
if interface_form.is_valid():
|
||||
|
@ -344,7 +346,7 @@ def new_interface(request, machine, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Interface)
|
||||
def del_interface(request, interface, **_kwargs):
|
||||
""" Supprime une interface. Domain objet en mode cascade"""
|
||||
"""View used to delete interfaces, and the domains in cascade."""
|
||||
if request.method == "POST":
|
||||
machine = interface.machine
|
||||
interface.delete()
|
||||
|
@ -363,7 +365,7 @@ def del_interface(request, interface, **_kwargs):
|
|||
@can_create(Ipv6List)
|
||||
@can_edit(Interface)
|
||||
def new_ipv6list(request, interface, **_kwargs):
|
||||
"""Nouvelle ipv6"""
|
||||
"""View used to create IPv6 addresses lists."""
|
||||
ipv6list_instance = Ipv6List(interface=interface)
|
||||
ipv6 = Ipv6ListForm(
|
||||
request.POST or None, instance=ipv6list_instance, user=request.user
|
||||
|
@ -384,7 +386,7 @@ def new_ipv6list(request, interface, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(Ipv6List)
|
||||
def edit_ipv6list(request, ipv6list_instance, **_kwargs):
|
||||
"""Edition d'une ipv6"""
|
||||
"""View used to edit IPv6 addresses lists."""
|
||||
ipv6 = Ipv6ListForm(
|
||||
request.POST or None, instance=ipv6list_instance, user=request.user
|
||||
)
|
||||
|
@ -406,7 +408,7 @@ def edit_ipv6list(request, ipv6list_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Ipv6List)
|
||||
def del_ipv6list(request, ipv6list, **_kwargs):
|
||||
""" Supprime une ipv6"""
|
||||
"""View used to delete IPv6 addresses lists."""
|
||||
if request.method == "POST":
|
||||
interfaceid = ipv6list.interface.id
|
||||
ipv6list.delete()
|
||||
|
@ -423,7 +425,7 @@ def del_ipv6list(request, ipv6list, **_kwargs):
|
|||
@can_create(SshFp)
|
||||
@can_edit(Machine)
|
||||
def new_sshfp(request, machine, **_kwargs):
|
||||
"""Creates an SSHFP record associated with a machine"""
|
||||
"""View used to create SSHFP records associated with machines."""
|
||||
sshfp_instance = SshFp(machine=machine)
|
||||
sshfp = SshFpForm(request.POST or None, instance=sshfp_instance)
|
||||
if sshfp.is_valid():
|
||||
|
@ -442,7 +444,7 @@ def new_sshfp(request, machine, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(SshFp)
|
||||
def edit_sshfp(request, sshfp_instance, **_kwargs):
|
||||
"""Edits an SSHFP record"""
|
||||
"""View used to edit SSHFP records."""
|
||||
sshfp = SshFpForm(request.POST or None, instance=sshfp_instance)
|
||||
if sshfp.is_valid():
|
||||
if sshfp.changed_data:
|
||||
|
@ -462,7 +464,7 @@ def edit_sshfp(request, sshfp_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(SshFp)
|
||||
def del_sshfp(request, sshfp, **_kwargs):
|
||||
"""Deletes an SSHFP record"""
|
||||
"""View used to delete SSHFP records."""
|
||||
if request.method == "POST":
|
||||
machineid = sshfp.machine.id
|
||||
sshfp.delete()
|
||||
|
@ -478,9 +480,10 @@ def del_sshfp(request, sshfp, **_kwargs):
|
|||
@login_required
|
||||
@can_create(IpType)
|
||||
def add_iptype(request):
|
||||
""" Ajoute un range d'ip. Intelligence dans le models, fonction views
|
||||
minimaliste"""
|
||||
"""View used to create IP ranges.
|
||||
|
||||
The view function is simple, the intelligence is in the model.
|
||||
"""
|
||||
iptype = IpTypeForm(request.POST or None)
|
||||
if iptype.is_valid():
|
||||
iptype.save()
|
||||
|
@ -496,9 +499,10 @@ def add_iptype(request):
|
|||
@login_required
|
||||
@can_edit(IpType)
|
||||
def edit_iptype(request, iptype_instance, **_kwargs):
|
||||
""" Edition d'un range. Ne permet pas de le redimensionner pour éviter
|
||||
l'incohérence"""
|
||||
"""View used to edit IP ranges.
|
||||
|
||||
Changing the size of the range is not possible to prevent inconsistency.
|
||||
"""
|
||||
iptype = EditIpTypeForm(request.POST or None, instance=iptype_instance)
|
||||
if iptype.is_valid():
|
||||
if iptype.changed_data:
|
||||
|
@ -515,7 +519,10 @@ def edit_iptype(request, iptype_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(IpType)
|
||||
def del_iptype(request, instances):
|
||||
""" Suppression d'un range ip. Supprime les objets ip associés"""
|
||||
"""View used to delete IP ranges.
|
||||
|
||||
Deletes the related IP objects.
|
||||
"""
|
||||
iptype = DelIpTypeForm(request.POST or None, instances=instances)
|
||||
if iptype.is_valid():
|
||||
iptype_dels = iptype.cleaned_data["iptypes"]
|
||||
|
@ -545,7 +552,7 @@ def del_iptype(request, instances):
|
|||
@login_required
|
||||
@can_create(MachineType)
|
||||
def add_machinetype(request):
|
||||
""" View used to add a Machinetype object """
|
||||
"""View used to create machine types."""
|
||||
machinetype = MachineTypeForm(request.POST or None)
|
||||
if machinetype.is_valid():
|
||||
machinetype.save()
|
||||
|
@ -561,7 +568,7 @@ def add_machinetype(request):
|
|||
@login_required
|
||||
@can_edit(MachineType)
|
||||
def edit_machinetype(request, machinetype_instance, **_kwargs):
|
||||
""" View used to edit a MachineType object """
|
||||
"""View used to edit machine types."""
|
||||
machinetype = MachineTypeForm(request.POST or None, instance=machinetype_instance)
|
||||
if machinetype.is_valid():
|
||||
if machinetype.changed_data:
|
||||
|
@ -578,7 +585,7 @@ def edit_machinetype(request, machinetype_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(MachineType)
|
||||
def del_machinetype(request, instances):
|
||||
""" View used to delete a MachineType object """
|
||||
"""View used to delete machines types."""
|
||||
machinetype = DelMachineTypeForm(request.POST or None, instances=instances)
|
||||
if machinetype.is_valid():
|
||||
machinetype_dels = machinetype.cleaned_data["machinetypes"]
|
||||
|
@ -608,7 +615,7 @@ def del_machinetype(request, instances):
|
|||
@login_required
|
||||
@can_create(Extension)
|
||||
def add_extension(request):
|
||||
""" View used to add an Extension object """
|
||||
"""View used to create extensions."""
|
||||
extension = ExtensionForm(request.POST or None)
|
||||
if extension.is_valid():
|
||||
extension.save()
|
||||
|
@ -624,7 +631,7 @@ def add_extension(request):
|
|||
@login_required
|
||||
@can_edit(Extension)
|
||||
def edit_extension(request, extension_instance, **_kwargs):
|
||||
""" View used to edit an Extension object """
|
||||
"""View used to edit extensions."""
|
||||
extension = ExtensionForm(request.POST or None, instance=extension_instance)
|
||||
if extension.is_valid():
|
||||
if extension.changed_data:
|
||||
|
@ -641,7 +648,7 @@ def edit_extension(request, extension_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Extension)
|
||||
def del_extension(request, instances):
|
||||
""" View used to delete an Extension object """
|
||||
"""View used to delete extensions."""
|
||||
extension = DelExtensionForm(request.POST or None, instances=instances)
|
||||
if extension.is_valid():
|
||||
extension_dels = extension.cleaned_data["extensions"]
|
||||
|
@ -670,7 +677,7 @@ def del_extension(request, instances):
|
|||
@login_required
|
||||
@can_create(SOA)
|
||||
def add_soa(request):
|
||||
""" View used to add a SOA object """
|
||||
"""View used to create SOA records."""
|
||||
soa = SOAForm(request.POST or None)
|
||||
if soa.is_valid():
|
||||
soa.save()
|
||||
|
@ -686,7 +693,7 @@ def add_soa(request):
|
|||
@login_required
|
||||
@can_edit(SOA)
|
||||
def edit_soa(request, soa_instance, **_kwargs):
|
||||
""" View used to edit a SOA object """
|
||||
"""View used to edit SOA records."""
|
||||
soa = SOAForm(request.POST or None, instance=soa_instance)
|
||||
if soa.is_valid():
|
||||
if soa.changed_data:
|
||||
|
@ -701,7 +708,7 @@ def edit_soa(request, soa_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(SOA)
|
||||
def del_soa(request, instances):
|
||||
""" View used to delete a SOA object """
|
||||
"""View used to delete SOA records."""
|
||||
soa = DelSOAForm(request.POST or None, instances=instances)
|
||||
if soa.is_valid():
|
||||
soa_dels = soa.cleaned_data["soa"]
|
||||
|
@ -722,7 +729,7 @@ def del_soa(request, instances):
|
|||
@login_required
|
||||
@can_create(Mx)
|
||||
def add_mx(request):
|
||||
""" View used to add a MX object """
|
||||
"""View used to create MX records."""
|
||||
mx = MxForm(request.POST or None)
|
||||
if mx.is_valid():
|
||||
mx.save()
|
||||
|
@ -738,7 +745,7 @@ def add_mx(request):
|
|||
@login_required
|
||||
@can_edit(Mx)
|
||||
def edit_mx(request, mx_instance, **_kwargs):
|
||||
""" View used to edit a MX object """
|
||||
"""View used to edit MX records."""
|
||||
mx = MxForm(request.POST or None, instance=mx_instance)
|
||||
if mx.is_valid():
|
||||
if mx.changed_data:
|
||||
|
@ -753,7 +760,7 @@ def edit_mx(request, mx_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Mx)
|
||||
def del_mx(request, instances):
|
||||
""" View used to delete a MX object """
|
||||
"""View used to delete MX records."""
|
||||
mx = DelMxForm(request.POST or None, instances=instances)
|
||||
if mx.is_valid():
|
||||
mx_dels = mx.cleaned_data["mx"]
|
||||
|
@ -774,7 +781,7 @@ def del_mx(request, instances):
|
|||
@login_required
|
||||
@can_create(Ns)
|
||||
def add_ns(request):
|
||||
""" View used to add a NS object """
|
||||
"""View used to create NS records."""
|
||||
ns = NsForm(request.POST or None)
|
||||
if ns.is_valid():
|
||||
ns.save()
|
||||
|
@ -790,7 +797,7 @@ def add_ns(request):
|
|||
@login_required
|
||||
@can_edit(Ns)
|
||||
def edit_ns(request, ns_instance, **_kwargs):
|
||||
""" View used to edit a NS object """
|
||||
"""View used to edit NS records."""
|
||||
ns = NsForm(request.POST or None, instance=ns_instance)
|
||||
if ns.is_valid():
|
||||
if ns.changed_data:
|
||||
|
@ -805,7 +812,7 @@ def edit_ns(request, ns_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Ns)
|
||||
def del_ns(request, instances):
|
||||
""" View used to delete a NS object """
|
||||
"""View used to delete NS records."""
|
||||
nss = DelNsForm(request.POST or None, instances=instances)
|
||||
if nss.is_valid():
|
||||
ns_dels = nss.cleaned_data["nss"]
|
||||
|
@ -826,7 +833,7 @@ def del_ns(request, instances):
|
|||
@login_required
|
||||
@can_create(DName)
|
||||
def add_dname(request):
|
||||
""" View used to add a DName object """
|
||||
"""View used to create DNAME records."""
|
||||
dname = DNameForm(request.POST or None)
|
||||
if dname.is_valid():
|
||||
dname.save()
|
||||
|
@ -842,7 +849,7 @@ def add_dname(request):
|
|||
@login_required
|
||||
@can_edit(DName)
|
||||
def edit_dname(request, dname_instance, **_kwargs):
|
||||
""" View used to edit a DName object """
|
||||
"""View used to edit DNAME records."""
|
||||
dname = DNameForm(request.POST or None, instance=dname_instance)
|
||||
if dname.is_valid():
|
||||
if dname.changed_data:
|
||||
|
@ -857,7 +864,7 @@ def edit_dname(request, dname_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(DName)
|
||||
def del_dname(request, instances):
|
||||
""" View used to delete a DName object """
|
||||
"""View used to delete DNAME records."""
|
||||
dname = DelDNameForm(request.POST or None, instances=instances)
|
||||
if dname.is_valid():
|
||||
dname_dels = dname.cleaned_data["dname"]
|
||||
|
@ -881,7 +888,7 @@ def del_dname(request, instances):
|
|||
@login_required
|
||||
@can_create(Txt)
|
||||
def add_txt(request):
|
||||
""" View used to add a TXT object """
|
||||
"""View used to create TXT records."""
|
||||
txt = TxtForm(request.POST or None)
|
||||
if txt.is_valid():
|
||||
txt.save()
|
||||
|
@ -897,7 +904,7 @@ def add_txt(request):
|
|||
@login_required
|
||||
@can_edit(Txt)
|
||||
def edit_txt(request, txt_instance, **_kwargs):
|
||||
""" View used to edit a TXT object """
|
||||
"""View used to edit TXT records."""
|
||||
txt = TxtForm(request.POST or None, instance=txt_instance)
|
||||
if txt.is_valid():
|
||||
if txt.changed_data:
|
||||
|
@ -912,7 +919,7 @@ def edit_txt(request, txt_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Txt)
|
||||
def del_txt(request, instances):
|
||||
""" View used to delete a TXT object """
|
||||
"""View used to delete TXT records."""
|
||||
txt = DelTxtForm(request.POST or None, instances=instances)
|
||||
if txt.is_valid():
|
||||
txt_dels = txt.cleaned_data["txt"]
|
||||
|
@ -933,7 +940,7 @@ def del_txt(request, instances):
|
|||
@login_required
|
||||
@can_create(Srv)
|
||||
def add_srv(request):
|
||||
""" View used to add a SRV object """
|
||||
"""View used to create SRV records."""
|
||||
srv = SrvForm(request.POST or None)
|
||||
if srv.is_valid():
|
||||
srv.save()
|
||||
|
@ -949,7 +956,7 @@ def add_srv(request):
|
|||
@login_required
|
||||
@can_edit(Srv)
|
||||
def edit_srv(request, srv_instance, **_kwargs):
|
||||
""" View used to edit a SRV object """
|
||||
"""View used to edit SRV records."""
|
||||
srv = SrvForm(request.POST or None, instance=srv_instance)
|
||||
if srv.is_valid():
|
||||
if srv.changed_data:
|
||||
|
@ -964,7 +971,7 @@ def edit_srv(request, srv_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Srv)
|
||||
def del_srv(request, instances):
|
||||
""" View used to delete a SRV object """
|
||||
"""View used to delete SRV records."""
|
||||
srv = DelSrvForm(request.POST or None, instances=instances)
|
||||
if srv.is_valid():
|
||||
srv_dels = srv.cleaned_data["srv"]
|
||||
|
@ -986,7 +993,7 @@ def del_srv(request, instances):
|
|||
@can_create(Domain)
|
||||
@can_edit(Interface)
|
||||
def add_alias(request, interface, interfaceid):
|
||||
""" View used to add an Alias object """
|
||||
"""View used to create aliases."""
|
||||
alias = AliasForm(request.POST or None, user=request.user)
|
||||
if alias.is_valid():
|
||||
alias = alias.save(commit=False)
|
||||
|
@ -1006,7 +1013,7 @@ def add_alias(request, interface, interfaceid):
|
|||
@login_required
|
||||
@can_edit(Domain)
|
||||
def edit_alias(request, domain_instance, **_kwargs):
|
||||
""" View used to edit an Alias object """
|
||||
"""View used to edit aliases records."""
|
||||
alias = AliasForm(request.POST or None, instance=domain_instance, user=request.user)
|
||||
if alias.is_valid():
|
||||
if alias.changed_data:
|
||||
|
@ -1026,7 +1033,7 @@ def edit_alias(request, domain_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(Interface)
|
||||
def del_alias(request, interface, interfaceid):
|
||||
""" View used to delete an Alias object """
|
||||
"""View used to delete aliases records."""
|
||||
alias = DelAliasForm(request.POST or None, interface=interface)
|
||||
if alias.is_valid():
|
||||
alias_dels = alias.cleaned_data["alias"]
|
||||
|
@ -1051,7 +1058,7 @@ def del_alias(request, interface, interfaceid):
|
|||
@login_required
|
||||
@can_create(Role)
|
||||
def add_role(request):
|
||||
""" View used to add a Role object """
|
||||
"""View used to create roles."""
|
||||
role = RoleForm(request.POST or None)
|
||||
if role.is_valid():
|
||||
role.save()
|
||||
|
@ -1067,7 +1074,7 @@ def add_role(request):
|
|||
@login_required
|
||||
@can_edit(Role)
|
||||
def edit_role(request, role_instance, **_kwargs):
|
||||
""" View used to edit a Role object """
|
||||
"""View used to edit roles."""
|
||||
role = RoleForm(request.POST or None, instance=role_instance)
|
||||
if role.is_valid():
|
||||
if role.changed_data:
|
||||
|
@ -1082,7 +1089,7 @@ def edit_role(request, role_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Role)
|
||||
def del_role(request, instances):
|
||||
""" View used to delete a Service object """
|
||||
"""View used to delete roles."""
|
||||
role = DelRoleForm(request.POST or None, instances=instances)
|
||||
if role.is_valid():
|
||||
role_dels = role.cleaned_data["role"]
|
||||
|
@ -1103,7 +1110,7 @@ def del_role(request, instances):
|
|||
@login_required
|
||||
@can_create(Service)
|
||||
def add_service(request):
|
||||
""" View used to add a Service object """
|
||||
"""View used to create services."""
|
||||
service = ServiceForm(request.POST or None)
|
||||
if service.is_valid():
|
||||
service.save()
|
||||
|
@ -1119,7 +1126,7 @@ def add_service(request):
|
|||
@login_required
|
||||
@can_edit(Service)
|
||||
def edit_service(request, service_instance, **_kwargs):
|
||||
""" View used to edit a Service object """
|
||||
"""View used to edit services."""
|
||||
service = ServiceForm(request.POST or None, instance=service_instance)
|
||||
if service.is_valid():
|
||||
if service.changed_data:
|
||||
|
@ -1136,7 +1143,7 @@ def edit_service(request, service_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Service)
|
||||
def del_service(request, instances):
|
||||
""" View used to delete a Service object """
|
||||
"""View used to delete services."""
|
||||
service = DelServiceForm(request.POST or None, instances=instances)
|
||||
if service.is_valid():
|
||||
service_dels = service.cleaned_data["service"]
|
||||
|
@ -1169,7 +1176,7 @@ def regen_service(request, service, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Vlan)
|
||||
def add_vlan(request):
|
||||
""" View used to add a VLAN object """
|
||||
"""View used to create VLANs."""
|
||||
vlan = VlanForm(request.POST or None)
|
||||
if vlan.is_valid():
|
||||
vlan.save()
|
||||
|
@ -1185,7 +1192,7 @@ def add_vlan(request):
|
|||
@login_required
|
||||
@can_edit(Vlan)
|
||||
def edit_vlan(request, vlan_instance, **_kwargs):
|
||||
""" View used to edit a VLAN object """
|
||||
"""View used to edit VLANs."""
|
||||
vlan = VlanForm(request.POST or None, instance=vlan_instance)
|
||||
if vlan.is_valid():
|
||||
if vlan.changed_data:
|
||||
|
@ -1200,7 +1207,7 @@ def edit_vlan(request, vlan_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Vlan)
|
||||
def del_vlan(request, instances):
|
||||
""" View used to delete a VLAN object """
|
||||
"""View used to delete VLANs."""
|
||||
vlan = DelVlanForm(request.POST or None, instances=instances)
|
||||
if vlan.is_valid():
|
||||
vlan_dels = vlan.cleaned_data["vlan"]
|
||||
|
@ -1221,7 +1228,7 @@ def del_vlan(request, instances):
|
|||
@login_required
|
||||
@can_create(Nas)
|
||||
def add_nas(request):
|
||||
""" View used to add a NAS object """
|
||||
"""View used to create NAS devices."""
|
||||
nas = NasForm(request.POST or None)
|
||||
if nas.is_valid():
|
||||
nas.save()
|
||||
|
@ -1237,7 +1244,7 @@ def add_nas(request):
|
|||
@login_required
|
||||
@can_edit(Nas)
|
||||
def edit_nas(request, nas_instance, **_kwargs):
|
||||
""" View used to edit a NAS object """
|
||||
"""View used to edit NAS devices."""
|
||||
nas = NasForm(request.POST or None, instance=nas_instance)
|
||||
if nas.is_valid():
|
||||
if nas.changed_data:
|
||||
|
@ -1252,7 +1259,7 @@ def edit_nas(request, nas_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(Nas)
|
||||
def del_nas(request, instances):
|
||||
""" View used to delete a NAS object """
|
||||
"""View used to delete NAS devices."""
|
||||
nas = DelNasForm(request.POST or None, instances=instances)
|
||||
if nas.is_valid():
|
||||
nas_dels = nas.cleaned_data["nas"]
|
||||
|
@ -1273,8 +1280,8 @@ def del_nas(request, instances):
|
|||
@login_required
|
||||
@can_view_all(Machine)
|
||||
def index(request):
|
||||
""" The home view for this app. Displays the list of registered
|
||||
machines in Re2o """
|
||||
"""The home view for this app. Displays the list of registered
|
||||
machines in Re2o."""
|
||||
pagination_large_number = GeneralOption.get_cached_value("pagination_large_number")
|
||||
machines_list = (
|
||||
Machine.objects.select_related("user")
|
||||
|
@ -1297,7 +1304,7 @@ def index(request):
|
|||
@login_required
|
||||
@can_view_all(IpType)
|
||||
def index_iptype(request):
|
||||
""" View displaying the list of existing types of IP """
|
||||
"""View used to display the list of existing types of IP."""
|
||||
iptype_list = (
|
||||
IpType.objects.select_related("extension")
|
||||
.select_related("vlan")
|
||||
|
@ -1309,7 +1316,7 @@ def index_iptype(request):
|
|||
@login_required
|
||||
@can_view_all(Vlan)
|
||||
def index_vlan(request):
|
||||
""" View displaying the list of existing VLANs """
|
||||
"""View used to display the list of existing VLANs."""
|
||||
vlan_list = Vlan.objects.prefetch_related("iptype_set").order_by("vlan_id")
|
||||
return render(request, "machines/index_vlan.html", {"vlan_list": vlan_list})
|
||||
|
||||
|
@ -1317,7 +1324,7 @@ def index_vlan(request):
|
|||
@login_required
|
||||
@can_view_all(MachineType)
|
||||
def index_machinetype(request):
|
||||
""" View displaying the list of existing types of machines """
|
||||
"""View used to display the list of existing types of machines."""
|
||||
machinetype_list = MachineType.objects.select_related("ip_type").order_by("name")
|
||||
return render(
|
||||
request,
|
||||
|
@ -1329,7 +1336,7 @@ def index_machinetype(request):
|
|||
@login_required
|
||||
@can_view_all(Nas)
|
||||
def index_nas(request):
|
||||
""" View displaying the list of existing NAS """
|
||||
"""View used to display the list of existing NAS devices."""
|
||||
nas_list = (
|
||||
Nas.objects.select_related("machine_type")
|
||||
.select_related("nas_type")
|
||||
|
@ -1341,10 +1348,11 @@ def index_nas(request):
|
|||
@login_required
|
||||
@can_view_all(SOA, Mx, Ns, Txt, DName, Srv, Extension)
|
||||
def index_extension(request):
|
||||
""" View displaying the list of existing extensions, the list of
|
||||
"""View used to display the list of existing extensions, the list of
|
||||
existing SOA records, the list of existing MX records , the list of
|
||||
existing NS records, the list of existing TXT records and the list of
|
||||
existing SRV records """
|
||||
existing SRV records.
|
||||
"""
|
||||
extension_list = (
|
||||
Extension.objects.select_related("origin")
|
||||
.select_related("soa")
|
||||
|
@ -1386,7 +1394,7 @@ def index_extension(request):
|
|||
@login_required
|
||||
@can_edit(Interface)
|
||||
def index_alias(request, interface, interfaceid):
|
||||
""" View used to display the list of existing alias of an interface """
|
||||
"""View used to display the list of existing aliases of an interface."""
|
||||
alias_list = Domain.objects.filter(
|
||||
cname=Domain.objects.filter(interface_parent=interface)
|
||||
).order_by("name")
|
||||
|
@ -1401,7 +1409,7 @@ def index_alias(request, interface, interfaceid):
|
|||
@can_view(Machine)
|
||||
def index_sshfp(request, machine, machineid):
|
||||
"""View used to display the list of existing SSHFP records associated
|
||||
with a machine"""
|
||||
with a machine."""
|
||||
sshfp_list = SshFp.objects.filter(machine=machine)
|
||||
return render(
|
||||
request,
|
||||
|
@ -1413,7 +1421,7 @@ def index_sshfp(request, machine, machineid):
|
|||
@login_required
|
||||
@can_view(Interface)
|
||||
def index_ipv6(request, interface, interfaceid):
|
||||
""" View used to display the list of existing IPv6 of an interface """
|
||||
"""View used to display the list of existing IPv6 of an interface."""
|
||||
ipv6_list = Ipv6List.objects.filter(interface=interface)
|
||||
return render(
|
||||
request,
|
||||
|
@ -1425,7 +1433,7 @@ def index_ipv6(request, interface, interfaceid):
|
|||
@login_required
|
||||
@can_view_all(Role)
|
||||
def index_role(request):
|
||||
""" View used to display the list of existing roles """
|
||||
"""View used to display the list of existing roles."""
|
||||
role_list = Role.objects.prefetch_related("servers__domain__extension").all()
|
||||
return render(request, "machines/index_role.html", {"role_list": role_list})
|
||||
|
||||
|
@ -1433,7 +1441,7 @@ def index_role(request):
|
|||
@login_required
|
||||
@can_view_all(Service)
|
||||
def index_service(request):
|
||||
""" View used to display the list of existing services """
|
||||
"""View used to display the list of existing services."""
|
||||
service_list = Service.objects.prefetch_related(
|
||||
"service_link_set__server__domain__extension"
|
||||
).all()
|
||||
|
@ -1452,7 +1460,7 @@ def index_service(request):
|
|||
@login_required
|
||||
@can_view_all(OuverturePortList)
|
||||
def index_portlist(request):
|
||||
""" View used to display the list of existing port policies """
|
||||
"""View used to display the list of existing port policies."""
|
||||
port_list = (
|
||||
OuverturePortList.objects.prefetch_related("ouvertureport_set")
|
||||
.prefetch_related("interface_set__domain__extension")
|
||||
|
@ -1465,7 +1473,7 @@ def index_portlist(request):
|
|||
@login_required
|
||||
@can_edit(OuverturePortList)
|
||||
def edit_portlist(request, ouvertureportlist_instance, **_kwargs):
|
||||
""" View used to edit a port policy """
|
||||
"""View used to edit port policies."""
|
||||
port_list = EditOuverturePortListForm(
|
||||
request.POST or None, instance=ouvertureportlist_instance
|
||||
)
|
||||
|
@ -1500,7 +1508,7 @@ def edit_portlist(request, ouvertureportlist_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(OuverturePortList)
|
||||
def del_portlist(request, port_list_instance, **_kwargs):
|
||||
""" View used to delete a port policy """
|
||||
"""View used to delete port policies."""
|
||||
port_list_instance.delete()
|
||||
messages.success(request, _("The ports list was deleted."))
|
||||
return redirect(reverse("machines:index-portlist"))
|
||||
|
@ -1509,7 +1517,7 @@ def del_portlist(request, port_list_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(OuverturePortList)
|
||||
def add_portlist(request):
|
||||
""" View used to add a port policy """
|
||||
"""View used to create port policies."""
|
||||
port_list = EditOuverturePortListForm(request.POST or None)
|
||||
port_formset = modelformset_factory(
|
||||
OuverturePort,
|
||||
|
@ -1540,8 +1548,9 @@ def add_portlist(request):
|
|||
@can_create(OuverturePort)
|
||||
@can_edit(Interface)
|
||||
def configure_ports(request, interface_instance, **_kwargs):
|
||||
""" View to display the list of configured port policy for an
|
||||
interface """
|
||||
"""View to display the list of configured port policies for an
|
||||
interface.
|
||||
"""
|
||||
if not interface_instance.may_have_port_open():
|
||||
messages.error(
|
||||
request,
|
||||
|
|
|
@ -36,7 +36,7 @@ from topologie.models import Dormitory
|
|||
|
||||
|
||||
class DormitoryForm(FormRevMixin, Form):
|
||||
"""Select a dorm"""
|
||||
"""Form used to select dormitories."""
|
||||
|
||||
dormitory = forms.ModelMultipleChoiceField(
|
||||
queryset=Dormitory.objects.all(),
|
||||
|
|
|
@ -34,7 +34,7 @@ from .models import Preferences
|
|||
|
||||
|
||||
class EditPreferencesForm(ModelForm):
|
||||
""" Edit the ticket's settings"""
|
||||
"""Form used to edit the settings of multi_op."""
|
||||
|
||||
class Meta:
|
||||
model = Preferences
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Fichier définissant les administration des models de preference
|
||||
multi_op preferences model. The settings are used when managing dormitories
|
||||
with multiple operators.
|
||||
"""
|
||||
|
||||
|
||||
|
@ -28,7 +29,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
|
||||
class Preferences(models.Model):
|
||||
""" Definition of the app settings"""
|
||||
"""Definition of the settings of multi_op."""
|
||||
|
||||
enabled_dorm = models.ManyToManyField(
|
||||
"topologie.Dormitory",
|
||||
|
|
|
@ -53,7 +53,13 @@ from .preferences.forms import EditPreferencesForm
|
|||
|
||||
|
||||
def display_rooms_connection(request, dormitory=None):
|
||||
"""View to display global state of connection state"""
|
||||
"""View used to display an overview of the rooms' connection state.
|
||||
|
||||
Args:
|
||||
request: django request.
|
||||
dormitory: Dormitory, the dormitory used to filter rooms. If no
|
||||
dormitory is given, all rooms are displayed (default: None).
|
||||
"""
|
||||
room_list = Room.objects.select_related("building__dormitory").order_by(
|
||||
"building_dormitory", "port"
|
||||
)
|
||||
|
@ -81,19 +87,30 @@ def display_rooms_connection(request, dormitory=None):
|
|||
@login_required
|
||||
@can_view_all(Room)
|
||||
def aff_state_global(request):
|
||||
"""View used to display the connection state of all rooms."""
|
||||
return display_rooms_connection(request)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_view(Dormitory)
|
||||
def aff_state_dormitory(request, dormitory, dormitoryid):
|
||||
"""View used to display the connection state of the rooms in the given
|
||||
dormitory.
|
||||
|
||||
Args:
|
||||
request: django request.
|
||||
dormitory: Dormitory, the dormitory used to filter rooms.
|
||||
dormitoryid: int, the id of the dormitory.
|
||||
"""
|
||||
return display_rooms_connection(dormitory=dormitory)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_view_all(Room)
|
||||
def aff_pending_connection(request):
|
||||
"""Aff pending Rooms to connect on our network"""
|
||||
"""View used to display rooms pending connection to the organisation's
|
||||
network.
|
||||
"""
|
||||
room_list = (
|
||||
Room.objects.select_related("building__dormitory")
|
||||
.filter(port__isnull=True)
|
||||
|
@ -128,7 +145,9 @@ def aff_pending_connection(request):
|
|||
@login_required
|
||||
@can_view_all(Room)
|
||||
def aff_pending_disconnection(request):
|
||||
"""Aff pending Rooms to disconnect from our network"""
|
||||
"""View used to display rooms pending disconnection from the organisation's
|
||||
network.
|
||||
"""
|
||||
room_list = (
|
||||
Room.objects.select_related("building__dormitory")
|
||||
.filter(port__isnull=False)
|
||||
|
@ -163,7 +182,13 @@ def aff_pending_disconnection(request):
|
|||
@login_required
|
||||
@can_edit(Room)
|
||||
def disconnect_room(request, room, roomid):
|
||||
"""Action of disconnecting a room"""
|
||||
"""View used to disconnect a room.
|
||||
|
||||
Args:
|
||||
request: django request.
|
||||
room: Room, the room to be disconnected.
|
||||
roomid: int, the id of the room.
|
||||
"""
|
||||
room.port_set.clear()
|
||||
room.save()
|
||||
messages.success(request, _("The room %s was disconnected.") % room)
|
||||
|
@ -171,5 +196,7 @@ def disconnect_room(request, room, roomid):
|
|||
|
||||
|
||||
def navbar_user():
|
||||
"""View to display the app in user's dropdown in the navbar"""
|
||||
"""View used to display a link to manage operators in the navbar (in the
|
||||
dropdown menu Topology).
|
||||
"""
|
||||
return ("topologie", render_to_string("multi_op/navbar.html"))
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Classes admin pour les models de preferences
|
||||
Admin classes for models of preferences app.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
@ -46,79 +46,79 @@ from .models import (
|
|||
|
||||
|
||||
class OptionalUserAdmin(VersionAdmin):
|
||||
"""Class admin options user"""
|
||||
"""Admin class for user options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class OptionalTopologieAdmin(VersionAdmin):
|
||||
"""Class admin options topologie"""
|
||||
"""Admin class for topology options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class OptionalMachineAdmin(VersionAdmin):
|
||||
"""Class admin options machines"""
|
||||
"""Admin class for machines options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GeneralOptionAdmin(VersionAdmin):
|
||||
"""Class admin options générales"""
|
||||
"""Admin class for general options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ServiceAdmin(VersionAdmin):
|
||||
"""Class admin gestion des services de la page d'accueil"""
|
||||
"""Admin class for services (on the homepage)."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MailContactAdmin(VersionAdmin):
|
||||
"""Admin class for contact email adresses"""
|
||||
"""Admin class for contact email addresses."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AssoOptionAdmin(VersionAdmin):
|
||||
"""Class admin options de l'asso"""
|
||||
"""Admin class for organisation options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MailMessageOptionAdmin(VersionAdmin):
|
||||
"""Class admin options mail"""
|
||||
"""Admin class for email messages options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class HomeOptionAdmin(VersionAdmin):
|
||||
"""Class admin options home"""
|
||||
"""Admin class for home options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class RadiusKeyAdmin(VersionAdmin):
|
||||
"""Class radiuskey"""
|
||||
"""Admin class for RADIUS keys options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class SwitchManagementCredAdmin(VersionAdmin):
|
||||
"""Class managementcred for switch"""
|
||||
"""Admin class for switch management credentials options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ReminderAdmin(VersionAdmin):
|
||||
"""Class reminder for switch"""
|
||||
"""Admin class for reminder options."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DocumentTemplateAdmin(VersionAdmin):
|
||||
"""Admin class for DocumentTemplate"""
|
||||
"""Admin class for document templates."""
|
||||
|
||||
pass
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Formulaire d'edition des réglages : user, machine, topologie, asso...
|
||||
Forms to edit preferences: users, machines, topology, organisation etc.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -53,7 +53,7 @@ from topologie.models import Switch
|
|||
|
||||
|
||||
class EditOptionalUserForm(ModelForm):
|
||||
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
|
||||
"""Form used to edit user preferences."""
|
||||
|
||||
class Meta:
|
||||
model = OptionalUser
|
||||
|
@ -82,7 +82,7 @@ class EditOptionalUserForm(ModelForm):
|
|||
|
||||
|
||||
class EditOptionalMachineForm(ModelForm):
|
||||
"""Options machines (max de machines, etc)"""
|
||||
"""Form used to edit machine preferences."""
|
||||
|
||||
class Meta:
|
||||
model = OptionalMachine
|
||||
|
@ -105,9 +105,7 @@ class EditOptionalMachineForm(ModelForm):
|
|||
|
||||
|
||||
class EditOptionalTopologieForm(ModelForm):
|
||||
"""Options de topologie, formulaire d'edition (vlan par default etc)
|
||||
On rajoute un champ automatic provision switchs pour gérer facilement
|
||||
l'ajout de switchs au provisionning automatique"""
|
||||
"""Form used to edit the configuration of switches."""
|
||||
|
||||
automatic_provision_switchs = forms.ModelMultipleChoiceField(
|
||||
Switch.objects.all(), required=False
|
||||
|
@ -135,7 +133,7 @@ class EditOptionalTopologieForm(ModelForm):
|
|||
|
||||
|
||||
class EditGeneralOptionForm(ModelForm):
|
||||
"""Options générales (affichages de résultats de recherche, etc)"""
|
||||
"""Form used to edit general preferences."""
|
||||
|
||||
class Meta:
|
||||
model = GeneralOption
|
||||
|
@ -165,7 +163,7 @@ class EditGeneralOptionForm(ModelForm):
|
|||
|
||||
|
||||
class EditAssoOptionForm(ModelForm):
|
||||
"""Options de l'asso (addresse, telephone, etc)"""
|
||||
"""Form used to edit information about the organisation."""
|
||||
|
||||
class Meta:
|
||||
model = AssoOption
|
||||
|
@ -189,7 +187,7 @@ class EditAssoOptionForm(ModelForm):
|
|||
|
||||
|
||||
class EditMailMessageOptionForm(ModelForm):
|
||||
"""Formulaire d'edition des messages de bienvenue personnalisés"""
|
||||
"""Form used to edit welcome email messages."""
|
||||
|
||||
class Meta:
|
||||
model = MailMessageOption
|
||||
|
@ -207,7 +205,9 @@ class EditMailMessageOptionForm(ModelForm):
|
|||
|
||||
|
||||
class EditHomeOptionForm(ModelForm):
|
||||
"""Edition forms of Home options"""
|
||||
"""Form used to edit the social networks information displayed on the home
|
||||
page.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = HomeOption
|
||||
|
@ -222,7 +222,7 @@ class EditHomeOptionForm(ModelForm):
|
|||
|
||||
|
||||
class EditRadiusOptionForm(ModelForm):
|
||||
"""Edition forms for Radius options"""
|
||||
"""Form used to edit RADIUS preferences."""
|
||||
|
||||
class Meta:
|
||||
model = RadiusOption
|
||||
|
@ -242,7 +242,7 @@ class EditRadiusOptionForm(ModelForm):
|
|||
|
||||
|
||||
class EditCotisationsOptionForm(ModelForm):
|
||||
"""Edition forms for Cotisations options"""
|
||||
"""Form used to edit subscription preferences."""
|
||||
|
||||
class Meta:
|
||||
model = CotisationsOption
|
||||
|
@ -250,7 +250,7 @@ class EditCotisationsOptionForm(ModelForm):
|
|||
|
||||
|
||||
class MandateForm(ModelForm):
|
||||
"""Edit Mandates"""
|
||||
"""Form used to add and edit mandates."""
|
||||
|
||||
class Meta:
|
||||
model = Mandate
|
||||
|
@ -319,7 +319,7 @@ class MandateForm(ModelForm):
|
|||
|
||||
|
||||
class ServiceForm(ModelForm):
|
||||
"""Edition, ajout de services sur la page d'accueil"""
|
||||
"""Form used to add and edit services displayed on the home page."""
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
|
@ -335,7 +335,8 @@ class ServiceForm(ModelForm):
|
|||
|
||||
|
||||
class DelServiceForm(Form):
|
||||
"""Suppression de services sur la page d'accueil"""
|
||||
"""Form used to delete one or several services displayed on the home page.
|
||||
"""
|
||||
|
||||
services = forms.ModelMultipleChoiceField(
|
||||
queryset=Service.objects.none(),
|
||||
|
@ -353,7 +354,7 @@ class DelServiceForm(Form):
|
|||
|
||||
|
||||
class ReminderForm(FormRevMixin, ModelForm):
|
||||
"""Edition, ajout de services sur la page d'accueil"""
|
||||
"""Form used to add and edit reminders."""
|
||||
|
||||
class Meta:
|
||||
model = Reminder
|
||||
|
@ -365,7 +366,7 @@ class ReminderForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class RadiusKeyForm(FormRevMixin, ModelForm):
|
||||
"""Edition, ajout de clef radius"""
|
||||
"""Form used to add and edit RADIUS keys."""
|
||||
|
||||
members = forms.ModelMultipleChoiceField(
|
||||
queryset=Switch.objects.all(), required=False
|
||||
|
@ -389,8 +390,7 @@ class RadiusKeyForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class SwitchManagementCredForm(FormRevMixin, ModelForm):
|
||||
"""Edition, ajout de creds de management pour gestion
|
||||
et interface rest des switchs"""
|
||||
"""Form used to add and edit switch management credentials."""
|
||||
|
||||
members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False)
|
||||
|
||||
|
@ -412,7 +412,7 @@ class SwitchManagementCredForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class MailContactForm(ModelForm):
|
||||
"""Edition, ajout d'adresse de contact"""
|
||||
"""Form used to add and edit contact email addresses."""
|
||||
|
||||
class Meta:
|
||||
model = MailContact
|
||||
|
@ -424,7 +424,7 @@ class MailContactForm(ModelForm):
|
|||
|
||||
|
||||
class DelMailContactForm(Form):
|
||||
"""Delete contact email adress"""
|
||||
"""Form used to delete one or several contact email addresses."""
|
||||
|
||||
mailcontacts = forms.ModelMultipleChoiceField(
|
||||
queryset=MailContact.objects.none(),
|
||||
|
@ -442,9 +442,7 @@ class DelMailContactForm(Form):
|
|||
|
||||
|
||||
class DocumentTemplateForm(FormRevMixin, ModelForm):
|
||||
"""
|
||||
Form used to create a document template.
|
||||
"""
|
||||
"""Form used to add and edit document templates."""
|
||||
|
||||
class Meta:
|
||||
model = DocumentTemplate
|
||||
|
@ -456,10 +454,7 @@ class DocumentTemplateForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class DelDocumentTemplateForm(FormRevMixin, Form):
|
||||
"""
|
||||
Form used to delete one or more document templatess.
|
||||
The use must choose the one to delete by checking the boxes.
|
||||
"""
|
||||
"""Form used to delete one or several document templates."""
|
||||
|
||||
document_templates = forms.ModelMultipleChoiceField(
|
||||
queryset=DocumentTemplate.objects.none(),
|
||||
|
@ -477,7 +472,7 @@ class DelDocumentTemplateForm(FormRevMixin, Form):
|
|||
|
||||
|
||||
class RadiusAttributeForm(ModelForm):
|
||||
"""Edit and add RADIUS attributes."""
|
||||
"""Form used to add and edit RADIUS attributes."""
|
||||
|
||||
class Meta:
|
||||
model = RadiusAttribute
|
||||
|
@ -489,7 +484,7 @@ class RadiusAttributeForm(ModelForm):
|
|||
|
||||
|
||||
class DelRadiusAttributeForm(Form):
|
||||
"""Delete RADIUS attributes"""
|
||||
"""Form used to delete one or several RADIUS attributes."""
|
||||
|
||||
attributes = forms.ModelMultipleChoiceField(
|
||||
queryset=RadiusAttribute.objects.none(),
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Reglages généraux, machines, utilisateurs, mail, general pour l'application.
|
||||
Models defining the preferences for users, machines, emails, general settings
|
||||
etc.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
|
@ -44,20 +45,22 @@ from datetime import timedelta
|
|||
|
||||
|
||||
class PreferencesModel(models.Model):
|
||||
""" Base object for the Preferences objects
|
||||
Defines methods to handle the cache of the settings (they should
|
||||
not change a lot) """
|
||||
"""Base object for the Preferences objects.
|
||||
|
||||
Defines methods to handle the cache of the settings (they should not change
|
||||
a lot).
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def set_in_cache(cls):
|
||||
""" Save the preferences in a server-side cache """
|
||||
"""Save the preferences in a server-side cache."""
|
||||
instance, _created = cls.objects.get_or_create()
|
||||
cache.set(cls().__class__.__name__.lower(), instance, None)
|
||||
return instance
|
||||
|
||||
@classmethod
|
||||
def get_cached_value(cls, key):
|
||||
""" Get the preferences from the server-side cache """
|
||||
"""Get the preferences from the server-side cache."""
|
||||
instance = cache.get(cls().__class__.__name__.lower())
|
||||
if instance is None:
|
||||
instance = cls.set_in_cache()
|
||||
|
@ -68,8 +71,34 @@ class PreferencesModel(models.Model):
|
|||
|
||||
|
||||
class OptionalUser(AclMixin, PreferencesModel):
|
||||
"""Options pour l'user : obligation ou nom du telephone,
|
||||
activation ou non du solde, autorisation du negatif, fingerprint etc"""
|
||||
"""User preferences: telephone number requirement, user balance activation,
|
||||
creation of users by everyone etc.
|
||||
|
||||
Attributes:
|
||||
is_tel_mandatory: whether indicating a telephone number is mandatory.
|
||||
gpg_fingerprint: whether GPG fingerprints are enabled.
|
||||
all_can_create_club: whether all users can create a club.
|
||||
all_can_create_adherent: whether all users can create a member.
|
||||
shell_default: the default shell for users connecting to machines
|
||||
managed by the organisation.
|
||||
self_change_shell: whether users can edit their shell.
|
||||
self_change_pseudo: whether users can edit their pseudo (username).
|
||||
self_room_policy: whether users can edit the policy of their room.
|
||||
local_email_accounts_enabled: whether local email accounts are enabled.
|
||||
local_email_domain: the domain used for local email accounts.
|
||||
max_email_address: the maximum number of local email addresses allowed
|
||||
for a standard user.
|
||||
delete_notyetactive: the number of days before deleting not yet active
|
||||
users.
|
||||
disable_emailnotyetconfirmed: the number of days before disabling users
|
||||
with not yet verified email address.
|
||||
self_adhesion: whether users can create their account themselves.
|
||||
all_users_active: whether newly created users are active.
|
||||
allow_set_password_during_user_creation: whether users can set their
|
||||
password directly when creating their account.
|
||||
allow_archived_connexion: whether archived users can connect on the web
|
||||
interface.
|
||||
"""
|
||||
|
||||
DISABLED = "DISABLED"
|
||||
ONLY_INACTIVE = "ONLY_INACTIVE"
|
||||
|
@ -158,23 +187,32 @@ class OptionalUser(AclMixin, PreferencesModel):
|
|||
verbose_name = _("user preferences")
|
||||
|
||||
def clean(self):
|
||||
"""Clean model:
|
||||
Check the mail_extension
|
||||
"""
|
||||
"""Check the email extension."""
|
||||
if self.local_email_domain[0] != "@":
|
||||
raise ValidationError(_("Email domain must begin with @."))
|
||||
|
||||
|
||||
@receiver(post_save, sender=OptionalUser)
|
||||
def optionaluser_post_save(**kwargs):
|
||||
"""Ecriture dans le cache"""
|
||||
"""Write in the cache."""
|
||||
user_pref = kwargs["instance"]
|
||||
user_pref.set_in_cache()
|
||||
|
||||
|
||||
class OptionalMachine(AclMixin, PreferencesModel):
|
||||
"""Options pour les machines : maximum de machines ou d'alias par user
|
||||
sans droit, activation de l'ipv6"""
|
||||
"""Machines preferences: maximum number of machines per user, IPv6
|
||||
activation etc.
|
||||
|
||||
Attributes:
|
||||
password_machine: whether password per machine is enabled.
|
||||
max_lambdauser_interfaces: the maximum number of interfaces allowed for
|
||||
a standard user.
|
||||
max_lambdauser_aliases: the maximum number of aliases allowed for a
|
||||
standard user.
|
||||
ipv6_mode: whether IPv6 mode is enabled.
|
||||
create_machine: whether creation of machine is enabled.
|
||||
default_dns_ttl: the default TTL for CNAME, A and AAAA records.
|
||||
"""
|
||||
|
||||
SLAAC = "SLAAC"
|
||||
DHCPV6 = "DHCPV6"
|
||||
|
@ -197,7 +235,7 @@ class OptionalMachine(AclMixin, PreferencesModel):
|
|||
|
||||
@cached_property
|
||||
def ipv6(self):
|
||||
""" Check if the IPv6 option is activated """
|
||||
"""Check if the IPv6 mode is enabled."""
|
||||
return not self.get_cached_value("ipv6_mode") == "DISABLED"
|
||||
|
||||
class Meta:
|
||||
|
@ -207,7 +245,7 @@ class OptionalMachine(AclMixin, PreferencesModel):
|
|||
|
||||
@receiver(post_save, sender=OptionalMachine)
|
||||
def optionalmachine_post_save(**kwargs):
|
||||
"""Synchronisation ipv6 et ecriture dans le cache"""
|
||||
"""Synchronise IPv6 mode and write in the cache."""
|
||||
machine_pref = kwargs["instance"]
|
||||
machine_pref.set_in_cache()
|
||||
if machine_pref.ipv6_mode != "DISABLED":
|
||||
|
@ -216,8 +254,21 @@ def optionalmachine_post_save(**kwargs):
|
|||
|
||||
|
||||
class OptionalTopologie(AclMixin, PreferencesModel):
|
||||
"""Reglages pour la topologie : mode d'accès radius, vlan où placer
|
||||
les machines en accept ou reject"""
|
||||
"""Configuration of switches: automatic provision, RADIUS mode, default
|
||||
VLANs etc.
|
||||
|
||||
Attributes:
|
||||
switchs_web_management: whether web management for automatic provision
|
||||
is enabled.
|
||||
switchs_web_management_ssl: whether SSL web management is required.
|
||||
switchs_rest_management: whether REST management for automatic
|
||||
provision is enabled.
|
||||
switchs_ip_type: the IP range for the management of switches.
|
||||
switchs_provision: the provision mode for switches to get their
|
||||
configuration.
|
||||
sftp_login: the SFTP login for switches.
|
||||
sftp_pass: the SFTP password for switches.
|
||||
"""
|
||||
|
||||
MACHINE = "MACHINE"
|
||||
DEFINED = "DEFINED"
|
||||
|
@ -264,7 +315,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
|
||||
@cached_property
|
||||
def provisioned_switchs(self):
|
||||
"""Liste des switches provisionnés"""
|
||||
"""Get the list of provisioned switches."""
|
||||
from topologie.models import Switch
|
||||
|
||||
return Switch.objects.filter(automatic_provision=True).order_by(
|
||||
|
@ -273,7 +324,9 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
|
||||
@cached_property
|
||||
def switchs_management_interface(self):
|
||||
"""Return the ip of the interface that the switch have to contact to get it's config"""
|
||||
"""Get the interface that the switch has to contact to get its
|
||||
configuration.
|
||||
"""
|
||||
if self.switchs_ip_type:
|
||||
from machines.models import Role, Interface
|
||||
|
||||
|
@ -291,14 +344,16 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
|
||||
@cached_property
|
||||
def switchs_management_interface_ip(self):
|
||||
"""Same, but return the ipv4"""
|
||||
"""Get the IPv4 address of the interface that the switch has to contact
|
||||
to get its configuration.
|
||||
"""
|
||||
if not self.switchs_management_interface:
|
||||
return None
|
||||
return self.switchs_management_interface.ipv4
|
||||
|
||||
@cached_property
|
||||
def switchs_management_sftp_creds(self):
|
||||
"""Credentials des switchs pour provion sftp"""
|
||||
"""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:
|
||||
|
@ -306,7 +361,9 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
|
||||
@cached_property
|
||||
def switchs_management_utils(self):
|
||||
"""Used for switch_conf, return a list of ip on vlans"""
|
||||
"""Get the dictionary of IP addresses for the configuration of
|
||||
switches.
|
||||
"""
|
||||
from machines.models import Role, Ipv6List, Interface
|
||||
|
||||
def return_ips_dict(interfaces):
|
||||
|
@ -350,8 +407,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
|
||||
@cached_property
|
||||
def provision_switchs_enabled(self):
|
||||
"""Return true if all settings are ok : switchs on automatic provision,
|
||||
ip_type"""
|
||||
"""Check if all automatic provisioning settings are OK."""
|
||||
return bool(
|
||||
self.provisioned_switchs
|
||||
and self.switchs_ip_type
|
||||
|
@ -371,13 +427,20 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
|
||||
@receiver(post_save, sender=OptionalTopologie)
|
||||
def optionaltopologie_post_save(**kwargs):
|
||||
"""Ecriture dans le cache"""
|
||||
"""Write in the cache."""
|
||||
topologie_pref = kwargs["instance"]
|
||||
topologie_pref.set_in_cache()
|
||||
|
||||
|
||||
class RadiusKey(AclMixin, models.Model):
|
||||
"""Class of a radius key"""
|
||||
"""Class of a RADIUS key.
|
||||
|
||||
Attributes:
|
||||
radius_key: the encrypted RADIUS key.
|
||||
comment: a comment related to the key.
|
||||
default_switch: bool, True if the key is to be used by default on
|
||||
switches and False otherwise.
|
||||
"""
|
||||
|
||||
radius_key = AESEncryptedField(max_length=255, help_text=_("RADIUS key."))
|
||||
comment = models.CharField(
|
||||
|
@ -393,9 +456,7 @@ class RadiusKey(AclMixin, models.Model):
|
|||
verbose_name_plural = _("RADIUS keys")
|
||||
|
||||
def clean(self):
|
||||
"""Clean model:
|
||||
Check default switch is unique
|
||||
"""
|
||||
"""Check if there is a unique default RADIUS key."""
|
||||
if RadiusKey.objects.filter(default_switch=True).count() > 1:
|
||||
raise ValidationError(_("Default RADIUS key for switches already exists."))
|
||||
|
||||
|
@ -404,7 +465,14 @@ class RadiusKey(AclMixin, models.Model):
|
|||
|
||||
|
||||
class SwitchManagementCred(AclMixin, models.Model):
|
||||
"""Class of a management creds of a switch, for rest management"""
|
||||
"""Class of a switch management credentials, for rest management.
|
||||
|
||||
Attributes:
|
||||
management_id: the login used to connect to switches.
|
||||
management_pass: the encrypted password used to connect to switches.
|
||||
default_switch: bool, True if the credentials are to be used by default
|
||||
on switches and False otherwise.
|
||||
"""
|
||||
|
||||
management_id = models.CharField(max_length=63, help_text=_("Switch login."))
|
||||
management_pass = AESEncryptedField(max_length=63, help_text=_("Password."))
|
||||
|
@ -426,9 +494,13 @@ class SwitchManagementCred(AclMixin, models.Model):
|
|||
|
||||
|
||||
class Reminder(AclMixin, models.Model):
|
||||
"""Options pour les mails de notification de fin d'adhésion.
|
||||
Days: liste des nombres de jours pour lesquells un mail est envoyé
|
||||
optionalMessage: message additionel pour le mail
|
||||
"""Reminder of membership's end preferences: email messages, number of days
|
||||
before sending emails.
|
||||
|
||||
Attributes:
|
||||
days: the number of days before the membership's end to send the
|
||||
reminder.
|
||||
message: the content of the reminder.
|
||||
"""
|
||||
|
||||
days = models.IntegerField(
|
||||
|
@ -460,8 +532,26 @@ class Reminder(AclMixin, models.Model):
|
|||
|
||||
|
||||
class GeneralOption(AclMixin, PreferencesModel):
|
||||
"""Options générales : nombre de resultats par page, nom du site,
|
||||
temps où les liens sont valides"""
|
||||
"""General preferences: number of search results per page, website name
|
||||
etc.
|
||||
|
||||
Attributes:
|
||||
general_message_fr: general message displayed on the French version of
|
||||
the website (e.g. in case of maintenance).
|
||||
general_message_en: general message displayed on the English version of
|
||||
the website (e.g. in case of maintenance).
|
||||
search_display_page: number of results displayed (in each category)
|
||||
when searching.
|
||||
pagination_number: number of items per page (standard size).
|
||||
pagination_large_number: number of items per page (large size).
|
||||
req_expire_hrs: number of hours before expiration of the reset password
|
||||
link.
|
||||
site_name: website name.
|
||||
email_from: email address for automatic emailing.
|
||||
main_site_url: main site URL.
|
||||
GTU_sum_up: summary of the General Terms of Use.
|
||||
GTU: file, General Terms of Use.
|
||||
"""
|
||||
|
||||
general_message_fr = models.TextField(
|
||||
default="",
|
||||
|
@ -496,14 +586,20 @@ class GeneralOption(AclMixin, PreferencesModel):
|
|||
|
||||
@receiver(post_save, sender=GeneralOption)
|
||||
def generaloption_post_save(**kwargs):
|
||||
"""Ecriture dans le cache"""
|
||||
"""Write in the cache."""
|
||||
general_pref = kwargs["instance"]
|
||||
general_pref.set_in_cache()
|
||||
|
||||
|
||||
class Service(AclMixin, models.Model):
|
||||
"""Liste des services affichés sur la page d'accueil : url, description,
|
||||
image et nom"""
|
||||
"""Service displayed on the home page.
|
||||
|
||||
Attributes:
|
||||
name: the name of the service.
|
||||
url: the URL of the service.
|
||||
description: the description of the service.
|
||||
image: an image to illustrate the service (e.g. logo).
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=32)
|
||||
url = models.URLField()
|
||||
|
@ -520,7 +616,12 @@ class Service(AclMixin, models.Model):
|
|||
|
||||
|
||||
class MailContact(AclMixin, models.Model):
|
||||
"""Contact email adress with a commentary."""
|
||||
"""Contact email address with a comment.
|
||||
|
||||
Attributes:
|
||||
address: the contact email address.
|
||||
commentary: a comment used to describe the contact email address.
|
||||
"""
|
||||
|
||||
address = models.EmailField(
|
||||
default="contact@example.org", help_text=_("Contact email address.")
|
||||
|
@ -549,6 +650,15 @@ class MailContact(AclMixin, models.Model):
|
|||
|
||||
|
||||
class Mandate(RevMixin, AclMixin, models.Model):
|
||||
"""Mandate, documenting who was the president of the organisation at a
|
||||
given time.
|
||||
|
||||
Attributes:
|
||||
president: User, the president during the mandate.
|
||||
start_date: datetime, the date when the mandate started.
|
||||
end_date: datetime, the date when the mandate ended.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("mandate")
|
||||
verbose_name_plural = _("mandates")
|
||||
|
@ -567,7 +677,14 @@ class Mandate(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@classmethod
|
||||
def get_mandate(cls, date=timezone.now):
|
||||
""""Find the mandate taking place at the given date."""
|
||||
""""Get the mandate taking place at the given date.
|
||||
|
||||
Args:
|
||||
date: the date used to find the mandate (default: timezone.now).
|
||||
|
||||
Returns:
|
||||
The mandate related to the given date.
|
||||
"""
|
||||
if callable(date):
|
||||
date = date()
|
||||
mandate = (
|
||||
|
@ -590,7 +707,21 @@ class Mandate(RevMixin, AclMixin, models.Model):
|
|||
|
||||
|
||||
class AssoOption(AclMixin, PreferencesModel):
|
||||
"""Options générales de l'asso : siret, addresse, nom, etc"""
|
||||
"""Information about the organisation: name, address, SIRET number etc.
|
||||
|
||||
Attributes:
|
||||
name: the name of the organisation.
|
||||
siret: the SIRET number of the organisation.
|
||||
adresse1: the first line of the organisation's address, e.g. street and
|
||||
number.
|
||||
adresse2: the second line of the organisation's address, e.g. city and
|
||||
postal code.
|
||||
contact: contact email address.
|
||||
telephone: contact telephone number.
|
||||
pseudo: short name of the organisation.
|
||||
utilisateur_asso: the user used to manage the organisation.
|
||||
description: the description of the organisation.
|
||||
"""
|
||||
|
||||
name = models.CharField(
|
||||
default=_("Networking organisation school Something"), max_length=256
|
||||
|
@ -613,13 +744,20 @@ class AssoOption(AclMixin, PreferencesModel):
|
|||
|
||||
@receiver(post_save, sender=AssoOption)
|
||||
def assooption_post_save(**kwargs):
|
||||
"""Ecriture dans le cache"""
|
||||
"""Write in the cache."""
|
||||
asso_pref = kwargs["instance"]
|
||||
asso_pref.set_in_cache()
|
||||
|
||||
|
||||
class HomeOption(AclMixin, PreferencesModel):
|
||||
"""Settings of the home page (facebook/twitter etc)"""
|
||||
"""Social networks displayed on the home page (supports only Facebook and
|
||||
Twitter).
|
||||
|
||||
Attributes:
|
||||
facebook_url: URL of the Facebook account.
|
||||
twitter_url: URL of the Twitter account.
|
||||
twitter_account_name: name of the Twitter account.
|
||||
"""
|
||||
|
||||
facebook_url = models.URLField(null=True, blank=True)
|
||||
twitter_url = models.URLField(null=True, blank=True)
|
||||
|
@ -632,13 +770,18 @@ class HomeOption(AclMixin, PreferencesModel):
|
|||
|
||||
@receiver(post_save, sender=HomeOption)
|
||||
def homeoption_post_save(**kwargs):
|
||||
"""Ecriture dans le cache"""
|
||||
"""Write in the cache."""
|
||||
home_pref = kwargs["instance"]
|
||||
home_pref.set_in_cache()
|
||||
|
||||
|
||||
class MailMessageOption(AclMixin, models.Model):
|
||||
"""Reglages, mail de bienvenue et autre"""
|
||||
"""Welcome email messages preferences.
|
||||
|
||||
Attributes:
|
||||
welcome_mail_fr: the text of the welcome email in French.
|
||||
welcome_mail_en: the text of the welcome email in English.
|
||||
"""
|
||||
|
||||
welcome_mail_fr = models.TextField(
|
||||
default="", blank=True, help_text=_("Welcome email in French.")
|
||||
|
@ -655,6 +798,14 @@ class MailMessageOption(AclMixin, models.Model):
|
|||
|
||||
|
||||
class RadiusAttribute(RevMixin, AclMixin, models.Model):
|
||||
"""RADIUS attributes preferences.
|
||||
|
||||
Attributes:
|
||||
attribute: the name of the RADIUS attribute.
|
||||
value: the value of the RADIUS attribute.
|
||||
comment: the comment to document the attribute.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("RADIUS attribute")
|
||||
verbose_name_plural = _("RADIUS attributes")
|
||||
|
@ -677,6 +828,30 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model):
|
|||
|
||||
|
||||
class RadiusOption(AclMixin, PreferencesModel):
|
||||
"""RADIUS preferences.
|
||||
|
||||
Attributes:
|
||||
radius_general_policy: the general RADIUS policy (MACHINE or DEFINED).
|
||||
unknown_machine: the RADIUS policy for unknown machines.
|
||||
unknown_machine_vlan: the VLAN for unknown machines if not rejected.
|
||||
unknown_machine_attributes: the answer attributes for unknown machines.
|
||||
unknown_port: the RADIUS policy for unknown ports.
|
||||
unknown_port_vlan: the VLAN for unknown ports if not rejected;
|
||||
unknown_port_attributes: the answer attributes for unknown ports.
|
||||
unknown_room: the RADIUS policy for machines connecting from
|
||||
unregistered rooms (relevant for ports with STRICT RADIUS mode).
|
||||
unknown_room_vlan: the VLAN for unknown rooms if not rejected.
|
||||
unknown_room_attributes: the answer attributes for unknown rooms.
|
||||
non_member: the RADIUS policy for non members.
|
||||
non_member_vlan: the VLAN for non members if not rejected.
|
||||
non_member_attributes: the answer attributes for non members.
|
||||
banned: the RADIUS policy for banned users.
|
||||
banned_vlan: the VLAN for banned users if not rejected.
|
||||
banned_attributes: the answer attributes for banned users.
|
||||
vlan_decision_ok: the VLAN for accepted machines.
|
||||
ok_attributes: the answer attributes for accepted machines.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("RADIUS policy")
|
||||
verbose_name_plural = _("RADIUS policies")
|
||||
|
@ -847,6 +1022,15 @@ def default_voucher():
|
|||
|
||||
|
||||
class CotisationsOption(AclMixin, PreferencesModel):
|
||||
"""Subscription preferences.
|
||||
|
||||
Attributes:
|
||||
invoice_template: the template for invoices.
|
||||
voucher_template: the template for vouchers.
|
||||
send_voucher_mail: whether the voucher is sent by email when the
|
||||
invoice is controlled.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("subscription preferences")
|
||||
|
||||
|
@ -877,6 +1061,10 @@ class CotisationsOption(AclMixin, PreferencesModel):
|
|||
class DocumentTemplate(RevMixin, AclMixin, models.Model):
|
||||
"""Represent a template in order to create documents such as invoice or
|
||||
subscription voucher.
|
||||
|
||||
Attributes:
|
||||
template: file, the template used to create documents.
|
||||
name: the name of the template.
|
||||
"""
|
||||
|
||||
template = models.FileField(upload_to="templates/", verbose_name=_("template"))
|
||||
|
@ -892,9 +1080,8 @@ class DocumentTemplate(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@receiver(models.signals.post_delete, sender=DocumentTemplate)
|
||||
def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||
"""
|
||||
Deletes file from filesystem
|
||||
when corresponding `DocumentTemplate` object is deleted.
|
||||
"""Delete the tempalte file from filesystem when the related
|
||||
DocumentTemplate object is deleted.
|
||||
"""
|
||||
if instance.template:
|
||||
if os.path.isfile(instance.template.path):
|
||||
|
@ -903,10 +1090,8 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
|
|||
|
||||
@receiver(models.signals.pre_save, sender=DocumentTemplate)
|
||||
def auto_delete_file_on_change(sender, instance, **kwargs):
|
||||
"""
|
||||
Deletes old file from filesystem
|
||||
when corresponding `DocumentTemplate` object is updated
|
||||
with new file.
|
||||
"""Delete the previous file from filesystem when the related
|
||||
DocumentTemplate object is updated with new file.
|
||||
"""
|
||||
if not instance.pk:
|
||||
return False
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
# Gabriel Détraz, Augustin Lemesle
|
||||
# Gplv2
|
||||
"""
|
||||
Vue d'affichage, et de modification des réglages (réglages machine,
|
||||
topologie, users, service...)
|
||||
Views to display and edit settings (preferences of machines, users, topology,
|
||||
services etc.)
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -88,7 +88,7 @@ from . import forms
|
|||
|
||||
|
||||
def edit_options_template_function(request, section, forms, models):
|
||||
""" Edition des préférences générales"""
|
||||
"""View used to edit general preferences."""
|
||||
model = getattr(models, section, None)
|
||||
form_instance = getattr(forms, "Edit" + section + "Form", None)
|
||||
if not (model or form_instance):
|
||||
|
@ -127,8 +127,7 @@ def edit_options_template_function(request, section, forms, models):
|
|||
HomeOption,
|
||||
)
|
||||
def display_options(request):
|
||||
"""Vue pour affichage des options (en vrac) classé selon les models
|
||||
correspondants dans un tableau"""
|
||||
"""View used to display preferences sorted by model."""
|
||||
useroptions, _created = OptionalUser.objects.get_or_create()
|
||||
machineoptions, _created = OptionalMachine.objects.get_or_create()
|
||||
topologieoptions, _created = OptionalTopologie.objects.get_or_create()
|
||||
|
@ -188,7 +187,7 @@ def edit_options(request, section):
|
|||
@login_required
|
||||
@can_create(Service)
|
||||
def add_service(request):
|
||||
"""Ajout d'un service de la page d'accueil"""
|
||||
"""View used to add services displayed on the home page."""
|
||||
service = ServiceForm(request.POST or None, request.FILES or None)
|
||||
if service.is_valid():
|
||||
service.save()
|
||||
|
@ -204,7 +203,7 @@ def add_service(request):
|
|||
@login_required
|
||||
@can_edit(Service)
|
||||
def edit_service(request, service_instance, **_kwargs):
|
||||
"""Edition des services affichés sur la page d'accueil"""
|
||||
"""View used to edit services displayed on the home page."""
|
||||
service = ServiceForm(
|
||||
request.POST or None, request.FILES or None, instance=service_instance
|
||||
)
|
||||
|
@ -222,7 +221,7 @@ def edit_service(request, service_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Service)
|
||||
def del_service(request, service_instance, **_kwargs):
|
||||
"""Suppression d'un service de la page d'accueil"""
|
||||
"""View used to delete services displayed on the home page."""
|
||||
if request.method == "POST":
|
||||
service_instance.delete()
|
||||
messages.success(request, _("The service was deleted."))
|
||||
|
@ -237,7 +236,7 @@ def del_service(request, service_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Reminder)
|
||||
def add_reminder(request):
|
||||
"""Ajout d'un mail de rappel"""
|
||||
"""View used to add reminders."""
|
||||
reminder = ReminderForm(request.POST or None, request.FILES or None)
|
||||
if reminder.is_valid():
|
||||
reminder.save()
|
||||
|
@ -253,7 +252,7 @@ def add_reminder(request):
|
|||
@login_required
|
||||
@can_edit(Reminder)
|
||||
def edit_reminder(request, reminder_instance, **_kwargs):
|
||||
"""Edition reminder"""
|
||||
"""View used to edit reminders."""
|
||||
reminder = ReminderForm(
|
||||
request.POST or None, request.FILES or None, instance=reminder_instance
|
||||
)
|
||||
|
@ -271,7 +270,7 @@ def edit_reminder(request, reminder_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Reminder)
|
||||
def del_reminder(request, reminder_instance, **_kwargs):
|
||||
"""Destruction d'un reminder"""
|
||||
"""View used to delete reminders."""
|
||||
if request.method == "POST":
|
||||
reminder_instance.delete()
|
||||
messages.success(request, _("The reminder was deleted."))
|
||||
|
@ -286,7 +285,7 @@ def del_reminder(request, reminder_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(RadiusKey)
|
||||
def add_radiuskey(request):
|
||||
"""Ajout d'une clef radius"""
|
||||
"""View used to add RADIUS keys."""
|
||||
radiuskey = RadiusKeyForm(request.POST or None)
|
||||
if radiuskey.is_valid():
|
||||
radiuskey.save()
|
||||
|
@ -301,7 +300,7 @@ def add_radiuskey(request):
|
|||
|
||||
@can_edit(RadiusKey)
|
||||
def edit_radiuskey(request, radiuskey_instance, **_kwargs):
|
||||
"""Edition des clefs radius"""
|
||||
"""View used to edit RADIUS keys."""
|
||||
radiuskey = RadiusKeyForm(request.POST or None, instance=radiuskey_instance)
|
||||
if radiuskey.is_valid():
|
||||
radiuskey.save()
|
||||
|
@ -317,7 +316,7 @@ def edit_radiuskey(request, radiuskey_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(RadiusKey)
|
||||
def del_radiuskey(request, radiuskey_instance, **_kwargs):
|
||||
"""Destruction d'un radiuskey"""
|
||||
"""View used to delete RADIUS keys."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
radiuskey_instance.delete()
|
||||
|
@ -341,7 +340,7 @@ def del_radiuskey(request, radiuskey_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(SwitchManagementCred)
|
||||
def add_switchmanagementcred(request):
|
||||
"""Ajout de creds de management"""
|
||||
"""View used to add switch management credentials."""
|
||||
switchmanagementcred = SwitchManagementCredForm(request.POST or None)
|
||||
if switchmanagementcred.is_valid():
|
||||
switchmanagementcred.save()
|
||||
|
@ -356,7 +355,7 @@ def add_switchmanagementcred(request):
|
|||
|
||||
@can_edit(SwitchManagementCred)
|
||||
def edit_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
|
||||
"""Edition des creds de management"""
|
||||
"""View used to edit switch management credentials."""
|
||||
switchmanagementcred = SwitchManagementCredForm(
|
||||
request.POST or None, instance=switchmanagementcred_instance
|
||||
)
|
||||
|
@ -374,7 +373,7 @@ def edit_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs)
|
|||
@login_required
|
||||
@can_delete(SwitchManagementCred)
|
||||
def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
|
||||
"""Destruction d'un switchmanagementcred"""
|
||||
"""View used to delete switch management credentials."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
switchmanagementcred_instance.delete()
|
||||
|
@ -404,7 +403,7 @@ def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(MailContact)
|
||||
def add_mailcontact(request):
|
||||
"""Add a contact email adress."""
|
||||
"""View used to add contact email addresses."""
|
||||
mailcontact = MailContactForm(request.POST or None, request.FILES or None)
|
||||
if mailcontact.is_valid():
|
||||
mailcontact.save()
|
||||
|
@ -420,7 +419,7 @@ def add_mailcontact(request):
|
|||
@login_required
|
||||
@can_edit(MailContact)
|
||||
def edit_mailcontact(request, mailcontact_instance, **_kwargs):
|
||||
"""Edit contact email adress."""
|
||||
"""View used to edit contact email addresses."""
|
||||
mailcontact = MailContactForm(
|
||||
request.POST or None, request.FILES or None, instance=mailcontact_instance
|
||||
)
|
||||
|
@ -438,7 +437,7 @@ def edit_mailcontact(request, mailcontact_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(MailContact)
|
||||
def del_mailcontact(request, instances):
|
||||
"""Delete an email adress"""
|
||||
"""View used to delete one or several contact email addresses."""
|
||||
mailcontacts = DelMailContactForm(request.POST or None, instances=instances)
|
||||
if mailcontacts.is_valid():
|
||||
mailcontacts_dels = mailcontacts.cleaned_data["mailcontacts"]
|
||||
|
@ -456,9 +455,7 @@ def del_mailcontact(request, instances):
|
|||
@login_required
|
||||
@can_create(DocumentTemplate)
|
||||
def add_document_template(request):
|
||||
"""
|
||||
View used to add a document template.
|
||||
"""
|
||||
"""View used to add document templates."""
|
||||
document_template = DocumentTemplateForm(
|
||||
request.POST or None, request.FILES or None
|
||||
)
|
||||
|
@ -480,9 +477,7 @@ def add_document_template(request):
|
|||
@login_required
|
||||
@can_edit(DocumentTemplate)
|
||||
def edit_document_template(request, document_template_instance, **_kwargs):
|
||||
"""
|
||||
View used to edit a document_template.
|
||||
"""
|
||||
"""View used to edit document templates."""
|
||||
document_template = DocumentTemplateForm(
|
||||
request.POST or None, request.FILES or None, instance=document_template_instance
|
||||
)
|
||||
|
@ -505,9 +500,7 @@ def edit_document_template(request, document_template_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(DocumentTemplate)
|
||||
def del_document_template(request, instances):
|
||||
"""
|
||||
View used to delete a set of document template.
|
||||
"""
|
||||
"""View used to delete one or several document templates."""
|
||||
document_template = DelDocumentTemplateForm(
|
||||
request.POST or None, instances=instances
|
||||
)
|
||||
|
@ -545,7 +538,7 @@ def del_document_template(request, instances):
|
|||
@login_required
|
||||
@can_create(RadiusAttribute)
|
||||
def add_radiusattribute(request):
|
||||
"""Create a RADIUS attribute."""
|
||||
"""View used to add RADIUS attributes."""
|
||||
attribute = RadiusAttributeForm(request.POST or None)
|
||||
if attribute.is_valid():
|
||||
attribute.save()
|
||||
|
@ -561,7 +554,7 @@ def add_radiusattribute(request):
|
|||
@login_required
|
||||
@can_edit(RadiusAttribute)
|
||||
def edit_radiusattribute(request, radiusattribute_instance, **_kwargs):
|
||||
"""Edit a RADIUS attribute."""
|
||||
"""View used to edit RADIUS attributes."""
|
||||
attribute = RadiusAttributeForm(
|
||||
request.POST or None, instance=radiusattribute_instance
|
||||
)
|
||||
|
@ -579,7 +572,7 @@ def edit_radiusattribute(request, radiusattribute_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(RadiusAttribute)
|
||||
def del_radiusattribute(request, radiusattribute_instance, **_kwargs):
|
||||
"""Delete a RADIUS attribute."""
|
||||
"""View used to delete RADIUS attributes."""
|
||||
if request.method == "POST":
|
||||
radiusattribute_instance.delete()
|
||||
messages.success(request, _("The attribute was deleted."))
|
||||
|
@ -594,7 +587,7 @@ def del_radiusattribute(request, radiusattribute_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Mandate)
|
||||
def add_mandate(request):
|
||||
"""Create a mandate."""
|
||||
"""View used to add mandates."""
|
||||
mandate = MandateForm(request.POST or None)
|
||||
if mandate.is_valid():
|
||||
mandate.save()
|
||||
|
@ -610,7 +603,7 @@ def add_mandate(request):
|
|||
@login_required
|
||||
@can_edit(Mandate)
|
||||
def edit_mandate(request, mandate_instance, **_kwargs):
|
||||
"""Edit a mandate."""
|
||||
"""View used to edit mandates."""
|
||||
mandate = MandateForm(request.POST or None, instance=mandate_instance)
|
||||
if mandate.is_valid():
|
||||
mandate.save()
|
||||
|
@ -626,7 +619,7 @@ def edit_mandate(request, mandate_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Mandate)
|
||||
def del_mandate(request, mandate_instance, **_kwargs):
|
||||
"""Delete a mandate."""
|
||||
"""View used to delete mandates."""
|
||||
if request.method == "POST":
|
||||
mandate_instance.delete()
|
||||
messages.success(request, _("The mandate was deleted."))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 _
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
|
|
166
re2o/utils.py
166
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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -45,21 +45,43 @@ from re2o.base import SortTable, re2o_paginator
|
|||
class Query:
|
||||
"""Class representing a query.
|
||||
It can contain the user-entered text, the operator for the query,
|
||||
and a list of subqueries"""
|
||||
and a list of subqueries.
|
||||
|
||||
Attributes:
|
||||
text: the string written by the user in a query.
|
||||
operator: character used to link subqueries, e.g. "+".
|
||||
subqueries: list of Query objects when the current query is split in
|
||||
several parts.
|
||||
"""
|
||||
def __init__(self, text="", case_sensitive=False):
|
||||
self.text = text # Content of the query
|
||||
self.operator = None # Whether a special char (ex "+") was used
|
||||
self.subqueries = None # When splitting the query in subparts
|
||||
"""Initialise an instance of Query.
|
||||
|
||||
Args:
|
||||
text: the content of the query (default: "").
|
||||
case_sensitive: bool, True if the query is case sensitive and
|
||||
False if not (default: False).
|
||||
"""
|
||||
self.text = text
|
||||
self.operator = None
|
||||
self.subqueries = None
|
||||
self.case_sensitive = case_sensitive
|
||||
|
||||
def add_char(self, char):
|
||||
"""Add the given char to the query's text"""
|
||||
"""Add the given character to the query's text.
|
||||
|
||||
Args:
|
||||
char: the character to be added.
|
||||
"""
|
||||
self.text += char
|
||||
|
||||
def add_operator(self, operator):
|
||||
"""Consider a new operator was entered, and that it must be processed.
|
||||
The query's current text is moved to self.subqueries in the form
|
||||
of a plain Query object"""
|
||||
of a plain Query object.
|
||||
|
||||
Args:
|
||||
operator: the operator to be added.
|
||||
"""
|
||||
self.operator = operator
|
||||
|
||||
if self.subqueries is None:
|
||||
|
@ -71,7 +93,7 @@ class Query:
|
|||
|
||||
@property
|
||||
def plaintext(self):
|
||||
"""Returns a textual representation of the query's content"""
|
||||
"""Return the textual representation of the query's content."""
|
||||
if self.operator is not None:
|
||||
return self.operator.join([q.plaintext for q in self.subqueries])
|
||||
|
||||
|
@ -82,7 +104,7 @@ class Query:
|
|||
|
||||
|
||||
def filter_fields():
|
||||
"""Return the list of fields the search applies to"""
|
||||
"""Return the list of fields the search applies to."""
|
||||
return ["users",
|
||||
"clubs",
|
||||
"machines",
|
||||
|
@ -95,12 +117,12 @@ def filter_fields():
|
|||
|
||||
|
||||
def empty_filters():
|
||||
"""Build empty filters used by Django"""
|
||||
"""Build empty filters used by Django."""
|
||||
return {f: Q() for f in filter_fields()}
|
||||
|
||||
|
||||
def is_int(variable):
|
||||
""" Check if the variable can be casted to an integer """
|
||||
"""Check if the variable can be cast to an integer."""
|
||||
try:
|
||||
int(variable)
|
||||
except ValueError:
|
||||
|
@ -111,8 +133,18 @@ def is_int(variable):
|
|||
|
||||
def finish_results(request, results, col, order):
|
||||
"""Sort the results by applying filters and then limit them to the
|
||||
number of max results. Finally add the info of the nmax number of results
|
||||
to the dict"""
|
||||
number of max results. Finally add the info of the maximum number of
|
||||
results to the dictionary.
|
||||
|
||||
Args:
|
||||
request: django request, corresponding to the search.
|
||||
results: dict, the results of the search.
|
||||
col: the column used to sort the results.
|
||||
order: the order used to sort the results.
|
||||
|
||||
Returns:
|
||||
The dictionary of results sorted and paginated.
|
||||
"""
|
||||
results["users"] = SortTable.sort(
|
||||
results["users"], col, order, SortTable.USERS_INDEX
|
||||
)
|
||||
|
@ -156,7 +188,16 @@ def finish_results(request, results, col, order):
|
|||
|
||||
def contains_filter(attribute, word, case_sensitive=False):
|
||||
"""Create a django model filtering whether the given attribute
|
||||
contains the specified value."""
|
||||
contains the specified value.
|
||||
|
||||
Args:
|
||||
attribute: the attribute used to check if it contains the given word or
|
||||
not.
|
||||
word: the word used to check if it is contained in the attribute or
|
||||
not.
|
||||
case_sensitive: bool, True if the check is case sensitive and
|
||||
False if not (default: False).
|
||||
"""
|
||||
if case_sensitive:
|
||||
attr = "{}__{}".format(attribute, "contains")
|
||||
else:
|
||||
|
@ -168,12 +209,13 @@ def contains_filter(attribute, word, case_sensitive=False):
|
|||
def search_single_word(word, filters, user, start, end,
|
||||
user_state, email_state, aff,
|
||||
case_sensitive=False):
|
||||
""" Construct the correct filters to match differents fields of some models
|
||||
"""Construct the correct filters to match differents fields of some models
|
||||
with the given query according to the given filters.
|
||||
The match field are either CharField or IntegerField that will be displayed
|
||||
The match fields are either CharField or IntegerField that will be displayed
|
||||
on the results page (else, one might not see why a result has matched the
|
||||
query). IntegerField are matched against the query only if it can be casted
|
||||
to an int."""
|
||||
to an int.
|
||||
"""
|
||||
|
||||
# Users
|
||||
if "0" in aff:
|
||||
|
@ -333,7 +375,7 @@ def search_single_word(word, filters, user, start, end,
|
|||
|
||||
|
||||
def apply_filters(filters, user, aff):
|
||||
""" Apply the filters constructed by search_single_query.
|
||||
"""Apply the filters constructed by search_single_query.
|
||||
It also takes into account the visual filters defined during
|
||||
the search query.
|
||||
"""
|
||||
|
@ -406,8 +448,8 @@ def apply_filters(filters, user, aff):
|
|||
|
||||
|
||||
def search_single_query(query, filters, user, start, end, user_state, email_state, aff):
|
||||
""" Handle different queries an construct the correct filters using
|
||||
search_single_word"""
|
||||
"""Handle different queries an construct the correct filters using
|
||||
search_single_word."""
|
||||
if query.operator == "+":
|
||||
# Special queries with "+" operators should use & rather than |
|
||||
newfilters = empty_filters()
|
||||
|
|
|
@ -62,7 +62,7 @@ def initial_choices(choice_set):
|
|||
|
||||
|
||||
class SearchForm(Form):
|
||||
"""The form for a simple search"""
|
||||
"""Form used to do a simple search."""
|
||||
|
||||
q = forms.CharField(
|
||||
label=_("Search"),
|
||||
|
@ -78,7 +78,7 @@ class SearchForm(Form):
|
|||
|
||||
|
||||
class SearchFormPlus(Form):
|
||||
"""The form for an advanced search (with filters)"""
|
||||
"""Form used to do an advanced search (with filters)."""
|
||||
|
||||
q = forms.CharField(
|
||||
label=_("Search"),
|
||||
|
|
|
@ -83,7 +83,7 @@ def get_results(query, request, params):
|
|||
@login_required
|
||||
@can_view_all(User, Machine, Cotisation)
|
||||
def search(request):
|
||||
""" La page de recherche standard """
|
||||
"""View used to display the simple search page."""
|
||||
search_form = SearchForm(request.GET or None)
|
||||
if search_form.is_valid():
|
||||
return render(
|
||||
|
@ -101,7 +101,7 @@ def search(request):
|
|||
@login_required
|
||||
@can_view_all(User, Machine, Cotisation)
|
||||
def searchp(request):
|
||||
""" La page de recherche avancée """
|
||||
"""View used to display the advanced search page."""
|
||||
search_form = SearchFormPlus(request.GET or None)
|
||||
if search_form.is_valid():
|
||||
return render(
|
||||
|
|
|
@ -35,7 +35,7 @@ from .models import Ticket, CommentTicket
|
|||
|
||||
|
||||
class NewTicketForm(FormRevMixin, ModelForm):
|
||||
""" Creation of a ticket"""
|
||||
"""Form used to create tickets."""
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
|
@ -53,7 +53,7 @@ class NewTicketForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditTicketForm(FormRevMixin, ModelForm):
|
||||
""" Creation of a ticket"""
|
||||
"""Form used to edit tickets."""
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
|
@ -65,7 +65,7 @@ class EditTicketForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class CommentTicketForm(FormRevMixin, ModelForm):
|
||||
"""Edit and create comment to a ticket"""
|
||||
"""Form used to create and edit comments of a ticket."""
|
||||
|
||||
class Meta:
|
||||
model = CommentTicket
|
||||
|
|
|
@ -46,7 +46,23 @@ from .preferences.models import TicketOption
|
|||
|
||||
|
||||
class Ticket(AclMixin, models.Model):
|
||||
"""Model of a ticket"""
|
||||
"""Model of a ticket.
|
||||
|
||||
Attributes:
|
||||
user: User, the user creating the ticket.
|
||||
title: the title of the ticket, chosen by the user.
|
||||
description: the main content of the ticket, written by the user to
|
||||
explain their problem.
|
||||
date: datetime, the date of creation of the ticket.
|
||||
email: the email address used to reply to the ticket.
|
||||
solved: boolean, True if the problem explained in the ticket has been
|
||||
solved, False otherwise. It is used to see easily which tickets
|
||||
still require attention.
|
||||
language: the language of the ticket, used to select the appropriate
|
||||
template when sending automatic emails, e.g. ticket creation.
|
||||
request: the request displayed if there is an error when sending emails
|
||||
related to the ticket.
|
||||
"""
|
||||
|
||||
user = models.ForeignKey(
|
||||
"users.User",
|
||||
|
@ -86,7 +102,7 @@ class Ticket(AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def opened_by(self):
|
||||
"""Return full name of this ticket opener"""
|
||||
"""Get the full name of the user who opened the ticket."""
|
||||
if self.user:
|
||||
return self.user.get_full_name()
|
||||
else:
|
||||
|
@ -94,10 +110,13 @@ class Ticket(AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def get_mail(self):
|
||||
"""Return the mail of the owner of this ticket"""
|
||||
"""Get the email address of the user who opened the ticket."""
|
||||
return self.email or self.user.get_mail
|
||||
|
||||
def publish_mail(self):
|
||||
"""Send an email for a newly opened ticket to the address set in the
|
||||
preferences.
|
||||
"""
|
||||
site_url = GeneralOption.get_cached_value("main_site_url")
|
||||
to_addr = TicketOption.get_cached_value("publish_address")
|
||||
context = {"ticket": self, "site_url": site_url}
|
||||
|
@ -120,8 +139,8 @@ class Ticket(AclMixin, models.Model):
|
|||
|
||||
|
||||
def can_view(self, user_request, *_args, **_kwargs):
|
||||
""" Check that the user has the right to view the ticket
|
||||
or that it is the author"""
|
||||
"""Check that the user has the right to view the ticket
|
||||
or that it is the author."""
|
||||
if (
|
||||
not user_request.has_perm("tickets.view_ticket")
|
||||
and self.user != user_request
|
||||
|
@ -136,7 +155,7 @@ class Ticket(AclMixin, models.Model):
|
|||
|
||||
@staticmethod
|
||||
def can_view_all(user_request, *_args, **_kwargs):
|
||||
""" Check that the user has access to the list of all tickets"""
|
||||
"""Check that the user has access to the list of all tickets."""
|
||||
can = user_request.has_perm("tickets.view_ticket")
|
||||
return (
|
||||
can,
|
||||
|
@ -147,12 +166,23 @@ class Ticket(AclMixin, models.Model):
|
|||
)
|
||||
|
||||
def can_create(user_request, *_args, **_kwargs):
|
||||
""" Authorise all users to open tickets """
|
||||
"""Authorise all users to open tickets."""
|
||||
return True, None, None
|
||||
|
||||
|
||||
class CommentTicket(AclMixin, models.Model):
|
||||
"""A comment of a ticket"""
|
||||
"""A comment of a ticket.
|
||||
|
||||
Attributes:
|
||||
date: datetime, the date of creation of the comment.
|
||||
comment: the text written as a comment to a ticket.
|
||||
parent_ticket: the ticket which is commented.
|
||||
created_at: datetime, the date of creation of the comment.
|
||||
created_by: the user who wrote the comment.
|
||||
request: the request used if there is an error when sending emails
|
||||
related to the comment.
|
||||
"""
|
||||
|
||||
date = models.DateTimeField(auto_now_add=True)
|
||||
comment = models.TextField(
|
||||
max_length=4095,
|
||||
|
@ -180,8 +210,8 @@ class CommentTicket(AclMixin, models.Model):
|
|||
return CommentTicket.objects.filter(parent_ticket=self.parent_ticket, pk__lt=self.pk).count() + 1
|
||||
|
||||
def can_view(self, user_request, *_args, **_kwargs):
|
||||
""" Check that the user has the right to view the ticket comment
|
||||
or that it is the author"""
|
||||
"""Check that the user has the right to view the ticket comment
|
||||
or that it is the author."""
|
||||
if (
|
||||
not user_request.has_perm("tickets.view_commentticket")
|
||||
and self.parent_ticket.user != user_request
|
||||
|
@ -195,8 +225,8 @@ class CommentTicket(AclMixin, models.Model):
|
|||
return True, None, None
|
||||
|
||||
def can_edit(self, user_request, *_args, **_kwargs):
|
||||
""" Check that the user has the right to edit the ticket comment
|
||||
or that it is the author"""
|
||||
"""Check that the user has the right to edit the ticket comment
|
||||
or that it is the author."""
|
||||
if (
|
||||
not user_request.has_perm("tickets.change_commentticket")
|
||||
and (self.parent_ticket.user != user_request or self.parent_ticket.user != self.created_by)
|
||||
|
@ -211,7 +241,7 @@ class CommentTicket(AclMixin, models.Model):
|
|||
|
||||
@staticmethod
|
||||
def can_view_all(user_request, *_args, **_kwargs):
|
||||
""" Check that the user has access to the list of all tickets comments"""
|
||||
"""Check that the user has access to the list of all tickets comments."""
|
||||
can = user_request.has_perm("tickets.view_commentticket")
|
||||
return (
|
||||
can,
|
||||
|
@ -225,7 +255,9 @@ class CommentTicket(AclMixin, models.Model):
|
|||
return "Comment " + str(self.comment_id) + " on " + str(self.parent_ticket)
|
||||
|
||||
def publish_mail(self):
|
||||
"""Send mail to user and admin after new comment"""
|
||||
"""Send an email for a newly written comment to the ticket's author and
|
||||
to the address set in the preferences.
|
||||
"""
|
||||
site_url = GeneralOption.get_cached_value("main_site_url")
|
||||
to_addr = TicketOption.get_cached_value("publish_address")
|
||||
context = {"comment": self, "site_url": site_url}
|
||||
|
@ -246,7 +278,7 @@ class CommentTicket(AclMixin, models.Model):
|
|||
|
||||
@receiver(post_save, sender=Ticket)
|
||||
def ticket_post_save(**kwargs):
|
||||
""" Send the mail to publish the new ticket """
|
||||
"""Call the method to publish an email when a ticket is created."""
|
||||
if kwargs["created"]:
|
||||
if TicketOption.get_cached_value("publish_address"):
|
||||
ticket = kwargs["instance"]
|
||||
|
@ -255,7 +287,7 @@ def ticket_post_save(**kwargs):
|
|||
|
||||
@receiver(post_save, sender=CommentTicket)
|
||||
def comment_post_save(**kwargs):
|
||||
""" Send the mail to publish the new comment """
|
||||
"""Call the method to publish an email when a comment is created."""
|
||||
if kwargs["created"]:
|
||||
if TicketOption.get_cached_value("publish_address"):
|
||||
comment = kwargs["instance"]
|
||||
|
|
|
@ -32,7 +32,7 @@ from .models import TicketOption
|
|||
|
||||
|
||||
class EditTicketOptionForm(FormRevMixin, ModelForm):
|
||||
""" Edit the ticket's settings"""
|
||||
"""Form used to edit the settings of tickets."""
|
||||
|
||||
class Meta:
|
||||
model = TicketOption
|
||||
|
|
|
@ -32,7 +32,7 @@ from preferences.models import PreferencesModel
|
|||
|
||||
|
||||
class TicketOption(AclMixin, PreferencesModel):
|
||||
""" Definition of the ticket's settings"""
|
||||
"""Definition of the settings of tickets."""
|
||||
|
||||
publish_address = models.EmailField(
|
||||
help_text=_(
|
||||
|
|
|
@ -42,7 +42,7 @@ from . import models
|
|||
|
||||
|
||||
def aff_preferences(request):
|
||||
""" View to display the settings of the tickets in the preferences page"""
|
||||
"""View used to display the settings of tickets in the preferences page."""
|
||||
pref, created = models.TicketOption.objects.get_or_create()
|
||||
context = {
|
||||
"preferences": pref,
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
# App de gestion des users pour re2o
|
||||
# Lara Kermarec, Gabriel Détraz, Lemesle Augustin
|
||||
# Gplv2
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
|
@ -52,7 +48,7 @@ from .forms import NewTicketForm, EditTicketForm, CommentTicketForm
|
|||
|
||||
|
||||
def new_ticket(request):
|
||||
""" Ticket creation view"""
|
||||
"""View used to display the creation form of tickets."""
|
||||
ticketform = NewTicketForm(request.POST or None, request=request)
|
||||
if ticketform.is_valid():
|
||||
ticketform.save()
|
||||
|
@ -76,7 +72,7 @@ def new_ticket(request):
|
|||
@login_required
|
||||
@can_view(Ticket)
|
||||
def aff_ticket(request, ticket, ticketid):
|
||||
"""View to display only one ticket"""
|
||||
"""View used to display a single ticket."""
|
||||
comments = CommentTicket.objects.filter(parent_ticket=ticket)
|
||||
return render(
|
||||
request,
|
||||
|
@ -88,7 +84,7 @@ def aff_ticket(request, ticket, ticketid):
|
|||
@login_required
|
||||
@can_edit(Ticket)
|
||||
def change_ticket_status(request, ticket, ticketid):
|
||||
"""View to edit ticket state"""
|
||||
"""View used to change a ticket's status."""
|
||||
ticket.solved = not ticket.solved
|
||||
ticket.save()
|
||||
return redirect(
|
||||
|
@ -99,7 +95,7 @@ def change_ticket_status(request, ticket, ticketid):
|
|||
@login_required
|
||||
@can_edit(Ticket)
|
||||
def edit_ticket(request, ticket, ticketid):
|
||||
""" Ticket creation view"""
|
||||
"""View used to display the edit form of tickets."""
|
||||
ticketform = EditTicketForm(request.POST or None, instance=ticket)
|
||||
if ticketform.is_valid():
|
||||
ticketform.save()
|
||||
|
@ -120,7 +116,7 @@ def edit_ticket(request, ticket, ticketid):
|
|||
@login_required
|
||||
@can_view(Ticket)
|
||||
def add_comment(request, ticket, ticketid):
|
||||
""" Add a comment to a ticket"""
|
||||
"""View used to add a comment to a ticket."""
|
||||
commentticket = CommentTicketForm(request.POST or None, request=request)
|
||||
if commentticket.is_valid():
|
||||
commentticket = commentticket.save(commit=False)
|
||||
|
@ -139,7 +135,7 @@ def add_comment(request, ticket, ticketid):
|
|||
@login_required
|
||||
@can_edit(CommentTicket)
|
||||
def edit_comment(request, commentticket_instance, **_kwargs):
|
||||
""" Edit a comment of a ticket"""
|
||||
"""View used to edit a comment of a ticket."""
|
||||
commentticket = CommentTicketForm(request.POST or None, instance=commentticket_instance)
|
||||
if commentticket.is_valid():
|
||||
ticketid = commentticket_instance.parent_ticket.id
|
||||
|
@ -157,7 +153,7 @@ def edit_comment(request, commentticket_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(CommentTicket)
|
||||
def del_comment(request, commentticket, **_kwargs):
|
||||
"""Delete a comment of a ticket"""
|
||||
"""View used to delete a comment of a ticket."""
|
||||
if request.method == "POST":
|
||||
ticketid = commentticket.parent_ticket.id
|
||||
commentticket.delete()
|
||||
|
@ -173,7 +169,7 @@ def del_comment(request, commentticket, **_kwargs):
|
|||
@login_required
|
||||
@can_view_all(Ticket)
|
||||
def aff_tickets(request):
|
||||
""" View to display all the tickets """
|
||||
"""View used to display all tickets."""
|
||||
tickets_list = Ticket.objects.all().order_by("-date")
|
||||
nbr_tickets = tickets_list.count()
|
||||
nbr_tickets_unsolved = tickets_list.filter(solved=False).count()
|
||||
|
@ -196,9 +192,9 @@ def aff_tickets(request):
|
|||
return render(request, "tickets/index.html", context=context)
|
||||
|
||||
|
||||
# views cannoniques des apps optionnels
|
||||
# Canonic views for optional apps
|
||||
def profil(request, user):
|
||||
""" View to display the ticket's module on the profil"""
|
||||
"""View used to display the tickets on a user's profile."""
|
||||
tickets_list = Ticket.objects.filter(user=user).all().order_by("-date")
|
||||
nbr_tickets = tickets_list.count()
|
||||
nbr_tickets_unsolved = tickets_list.filter(solved=False).count()
|
||||
|
@ -223,16 +219,19 @@ def profil(request, user):
|
|||
|
||||
|
||||
def contact(request):
|
||||
"""View to display a contact address on the contact page
|
||||
used here to display a link to open a ticket"""
|
||||
"""View used to display contact addresses to be used for tickets on the
|
||||
contact page.
|
||||
"""
|
||||
return render_to_string("tickets/contact.html")
|
||||
|
||||
|
||||
def navbar_user():
|
||||
"""View to display the ticket link in thet user's dropdown in the navbar"""
|
||||
"""View used to display a link to tickets in the navbar (in the dropdown
|
||||
menu Users).
|
||||
"""
|
||||
return ("users", render_to_string("tickets/navbar.html"))
|
||||
|
||||
|
||||
def navbar_logout():
|
||||
"""View to display the ticket link to log out users"""
|
||||
"""View used to display a link to open tickets for logged out users."""
|
||||
return render_to_string("tickets/navbar_logout.html")
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
# 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.
|
||||
"""
|
||||
Fichier définissant les administration des models dans l'interface admin
|
||||
"""topologie.admin
|
||||
The objects, fields and datastructures visible in the Django admin view.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -45,67 +45,67 @@ from .models import (
|
|||
|
||||
|
||||
class StackAdmin(VersionAdmin):
|
||||
"""Administration d'une stack de switches (inclus des switches)"""
|
||||
"""Admin class of stacks (includes switches)."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class SwitchAdmin(VersionAdmin):
|
||||
"""Administration d'un switch"""
|
||||
"""Admin class of switches."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class PortAdmin(VersionAdmin):
|
||||
"""Administration d'un port de switches"""
|
||||
"""Admin class of switch ports."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AccessPointAdmin(VersionAdmin):
|
||||
"""Administration d'une borne"""
|
||||
"""Admin class of APs."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class RoomAdmin(VersionAdmin):
|
||||
"""Administration d'un chambre"""
|
||||
"""Admin class of rooms."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ModelSwitchAdmin(VersionAdmin):
|
||||
"""Administration d'un modèle de switch"""
|
||||
"""Admin class of switch models."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ConstructorSwitchAdmin(VersionAdmin):
|
||||
"""Administration d'un constructeur d'un switch"""
|
||||
"""Admin class of switch constructors."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class SwitchBayAdmin(VersionAdmin):
|
||||
"""Administration d'une baie de brassage"""
|
||||
"""Admin class of switch bays."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BuildingAdmin(VersionAdmin):
|
||||
"""Administration d'un batiment"""
|
||||
"""Admin class of buildings."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DormitoryAdmin(VersionAdmin):
|
||||
"""Administration d'une residence"""
|
||||
"""Admin class of dormitories."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class PortProfileAdmin(VersionAdmin):
|
||||
"""Administration of a port profile"""
|
||||
"""Admin class of port profiles."""
|
||||
|
||||
pass
|
||||
|
||||
|
|
|
@ -20,14 +20,12 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Un forms le plus simple possible pour les objets topologie de re2o.
|
||||
Forms for the topologie app of re2o.
|
||||
|
||||
Permet de créer et supprimer : un Port de switch, relié à un switch.
|
||||
|
||||
Permet de créer des stacks et d'y ajouter des switchs (StackForm)
|
||||
|
||||
Permet de créer, supprimer et editer un switch (EditSwitchForm,
|
||||
NewSwitchForm)
|
||||
The forms are used to:
|
||||
* create and delete switch ports, related to a switch.
|
||||
* create stacks and add switches to them (StackForm).
|
||||
* create, edit and delete a switch (NewSwitchForm, EditSwitchForm).
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -59,8 +57,7 @@ from .models import (
|
|||
|
||||
|
||||
class PortForm(FormRevMixin, ModelForm):
|
||||
"""Formulaire pour la création d'un port d'un switch
|
||||
Relié directement au modèle port"""
|
||||
"""Form used to manage a switch's port."""
|
||||
|
||||
class Meta:
|
||||
model = Port
|
||||
|
@ -72,14 +69,11 @@ class PortForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditPortForm(FormRevMixin, ModelForm):
|
||||
"""Form pour l'édition d'un port de switche : changement des reglages
|
||||
radius ou vlan, ou attribution d'une chambre, autre port ou machine
|
||||
"""Form used to edit a switch's port: change in RADIUS or VLANs settings,
|
||||
assignement to a room, port or machine.
|
||||
|
||||
Un port est relié à une chambre, un autre port (uplink) ou une machine
|
||||
(serveur ou borne), mutuellement exclusif
|
||||
Optimisation sur les queryset pour machines et port_related pour
|
||||
optimiser le temps de chargement avec select_related (vraiment
|
||||
lent sans)"""
|
||||
A port is related to either a room, another port (uplink) or a machine (server or AP).
|
||||
"""
|
||||
|
||||
class Meta(PortForm.Meta):
|
||||
fields = [
|
||||
|
@ -106,8 +100,7 @@ class EditPortForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class AddPortForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'ajouter un port de switch. Voir EditPortForm pour plus
|
||||
d'informations"""
|
||||
"""Form used to add a switch's port. See EditPortForm."""
|
||||
|
||||
class Meta(PortForm.Meta):
|
||||
fields = [
|
||||
|
@ -139,8 +132,7 @@ class AddPortForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class StackForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'edition d'une stack : stack_id, et switches membres
|
||||
de la stack"""
|
||||
"""Form used to create and edit stacks."""
|
||||
|
||||
class Meta:
|
||||
model = Stack
|
||||
|
@ -152,8 +144,7 @@ class StackForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class AddAccessPointForm(NewMachineForm):
|
||||
"""Formulaire pour la création d'une borne
|
||||
Relié directement au modèle borne"""
|
||||
"""Form used to create access points."""
|
||||
|
||||
class Meta:
|
||||
model = AccessPoint
|
||||
|
@ -161,7 +152,7 @@ class AddAccessPointForm(NewMachineForm):
|
|||
|
||||
|
||||
class EditAccessPointForm(EditMachineForm):
|
||||
"""Edition d'une borne. Edition complète"""
|
||||
"""Form used to edit access points."""
|
||||
|
||||
class Meta:
|
||||
model = AccessPoint
|
||||
|
@ -169,7 +160,7 @@ class EditAccessPointForm(EditMachineForm):
|
|||
|
||||
|
||||
class EditSwitchForm(EditMachineForm):
|
||||
"""Permet d'éditer un switch : nom et nombre de ports"""
|
||||
"""Form used to edit switches."""
|
||||
|
||||
class Meta:
|
||||
model = Switch
|
||||
|
@ -177,15 +168,14 @@ class EditSwitchForm(EditMachineForm):
|
|||
|
||||
|
||||
class NewSwitchForm(NewMachineForm):
|
||||
"""Permet de créer un switch : emplacement, paramètres machine,
|
||||
membre d'un stack (option), nombre de ports (number)"""
|
||||
"""Form used to create a switch."""
|
||||
|
||||
class Meta(EditSwitchForm.Meta):
|
||||
fields = ["name", "switchbay", "number", "stack", "stack_member_id"]
|
||||
|
||||
|
||||
class EditRoomForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'éediter le nom et commentaire d'une prise murale"""
|
||||
"""Form used to edit a room."""
|
||||
|
||||
class Meta:
|
||||
model = Room
|
||||
|
@ -197,14 +187,14 @@ class EditRoomForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class CreatePortsForm(forms.Form):
|
||||
"""Permet de créer une liste de ports pour un switch."""
|
||||
"""Form used to create switch ports lists."""
|
||||
|
||||
begin = forms.IntegerField(label=_("Start:"), min_value=0)
|
||||
end = forms.IntegerField(label=_("End:"), min_value=0)
|
||||
|
||||
|
||||
class EditModelSwitchForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'éediter un modèle de switch : nom et constructeur"""
|
||||
"""Form used to edit switch models."""
|
||||
|
||||
members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False)
|
||||
|
||||
|
@ -226,7 +216,7 @@ class EditModelSwitchForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditConstructorSwitchForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'éediter le nom d'un constructeur"""
|
||||
"""Form used to edit switch constructors."""
|
||||
|
||||
class Meta:
|
||||
model = ConstructorSwitch
|
||||
|
@ -238,7 +228,7 @@ class EditConstructorSwitchForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditSwitchBayForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'éditer une baie de brassage"""
|
||||
"""Form used to edit switch bays."""
|
||||
|
||||
members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False)
|
||||
|
||||
|
@ -260,7 +250,7 @@ class EditSwitchBayForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditBuildingForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'éditer le batiment"""
|
||||
"""Form used to edit buildings."""
|
||||
|
||||
class Meta:
|
||||
model = Building
|
||||
|
@ -272,7 +262,7 @@ class EditBuildingForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditDormitoryForm(FormRevMixin, ModelForm):
|
||||
"""Enable dormitory edition"""
|
||||
"""Form used to edit dormitories."""
|
||||
|
||||
class Meta:
|
||||
model = Dormitory
|
||||
|
@ -284,7 +274,7 @@ class EditDormitoryForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditPortProfileForm(FormRevMixin, ModelForm):
|
||||
"""Form to edit a port profile"""
|
||||
"""Form used to edit port profiles."""
|
||||
|
||||
class Meta:
|
||||
model = PortProfile
|
||||
|
@ -296,7 +286,7 @@ class EditPortProfileForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditModuleForm(FormRevMixin, ModelForm):
|
||||
"""Add and edit module instance"""
|
||||
"""Form used to add and edit switch modules."""
|
||||
|
||||
class Meta:
|
||||
model = ModuleSwitch
|
||||
|
@ -308,7 +298,7 @@ class EditModuleForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditSwitchModuleForm(FormRevMixin, ModelForm):
|
||||
"""Add/edit a switch to a module"""
|
||||
"""Form used to add and edit modules related to a switch."""
|
||||
|
||||
class Meta:
|
||||
model = ModuleOnSwitch
|
||||
|
|
|
@ -21,18 +21,15 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Definition des modèles de l'application topologie.
|
||||
Definition of models for the 'topologie' app.
|
||||
|
||||
On défini les models suivants :
|
||||
|
||||
- stack (id, id_min, id_max et nom) regrouppant les switches
|
||||
- switch : nom, nombre de port, et interface
|
||||
machine correspondante (mac, ip, etc) (voir machines.models.interface)
|
||||
- Port: relié à un switch parent par foreign_key, numero du port,
|
||||
relié de façon exclusive à un autre port, une machine
|
||||
(serveur ou borne) ou une prise murale
|
||||
- room : liste des prises murales, nom et commentaire de l'état de
|
||||
la prise
|
||||
The following models are defined:
|
||||
* stack (grouping switches): id, id_min, id_max and name
|
||||
* switch: name, number of ports, related interface and machine (MAC
|
||||
address, IP address etc.) (see machines.models.interface)
|
||||
* port: related to a switch by foreign_key, number of the port, related
|
||||
exclusively to another port, machine (server or AP) or room outlets
|
||||
* room: list of outlets, name and comments about the plug's state
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -56,9 +53,15 @@ from re2o.mixins import AclMixin, RevMixin
|
|||
|
||||
|
||||
class Stack(AclMixin, RevMixin, models.Model):
|
||||
"""Un objet stack. Regrouppe des switchs en foreign key
|
||||
,contient une id de stack, un switch id min et max dans
|
||||
le stack"""
|
||||
"""Switch stack.
|
||||
|
||||
Attributes:
|
||||
name: the name of the stack.
|
||||
stack_id: the ID of the stack, as a text chosen by the user.
|
||||
details: the description to provide details about the stack.
|
||||
member_id_min: the minimum switch ID in the stack.
|
||||
member_id_max: the maximum switch ID in the stack.
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=32, blank=True, null=True)
|
||||
stack_id = models.CharField(max_length=32, unique=True)
|
||||
|
@ -81,7 +84,7 @@ class Stack(AclMixin, RevMixin, models.Model):
|
|||
super(Stack, self).save(*args, **kwargs)
|
||||
|
||||
def clean(self):
|
||||
""" Verification que l'id_max < id_min"""
|
||||
"""Check if id_max < id_min."""
|
||||
if self.member_id_max < self.member_id_min:
|
||||
raise ValidationError(
|
||||
{"member_id_max": _("The maximum ID is less than the minimum ID.")}
|
||||
|
@ -89,9 +92,10 @@ class Stack(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class AccessPoint(Machine):
|
||||
"""Define a wireless AP. Inherit from machines.interfaces
|
||||
"""Wireless Access Point. Inherits from machines.interfaces.
|
||||
|
||||
Definition pour une borne wifi , hérite de machines.interfaces
|
||||
Attributes:
|
||||
location: the text to provide details about the AP's location.
|
||||
"""
|
||||
|
||||
location = models.CharField(
|
||||
|
@ -107,17 +111,16 @@ class AccessPoint(Machine):
|
|||
verbose_name_plural = _("access points")
|
||||
|
||||
def port(self):
|
||||
"""Return the queryset of ports for this device"""
|
||||
"""Return the queryset of ports for this device."""
|
||||
return Port.objects.filter(machine_interface__machine=self)
|
||||
|
||||
def switch(self):
|
||||
"""Return the switch where this is plugged"""
|
||||
"""Return the switch where this is plugged."""
|
||||
return Switch.objects.filter(ports__machine_interface__machine=self)
|
||||
|
||||
def building(self):
|
||||
"""
|
||||
Return the building of the AP/Server (building of the switchs
|
||||
connected to...)
|
||||
"""Return the building of the AP/Server (building of the switches
|
||||
connected to...).
|
||||
"""
|
||||
return Building.objects.filter(switchbay__switch=self.switch())
|
||||
|
||||
|
@ -127,7 +130,14 @@ class AccessPoint(Machine):
|
|||
|
||||
@classmethod
|
||||
def all_ap_in(cls, building_instance):
|
||||
"""Get a building as argument, returns all ap of a building"""
|
||||
"""Get all the APs of the given building.
|
||||
|
||||
Args:
|
||||
building_instance: the building used to find APs.
|
||||
|
||||
Returns:
|
||||
The queryset of all APs in the given building.
|
||||
"""
|
||||
return cls.objects.filter(
|
||||
interface__port__switch__switchbay__building=building_instance
|
||||
)
|
||||
|
@ -158,25 +168,24 @@ class AccessPoint(Machine):
|
|||
|
||||
|
||||
class Server(Machine):
|
||||
"""
|
||||
Dummy class, to retrieve servers of a building, or get switch of a server
|
||||
"""Dummy class, to retrieve servers of a building, or get switch of a
|
||||
server.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
def port(self):
|
||||
"""Return the queryset of ports for this device"""
|
||||
"""Return the queryset of ports for this device."""
|
||||
return Port.objects.filter(machine_interface__machine=self)
|
||||
|
||||
def switch(self):
|
||||
"""Return the switch where this is plugged"""
|
||||
"""Return the switch where this is plugged."""
|
||||
return Switch.objects.filter(ports__machine_interface__machine=self)
|
||||
|
||||
def building(self):
|
||||
"""
|
||||
Return the building of the AP/Server
|
||||
(building of the switchs connected to...)
|
||||
"""Return the building of the AP/Server (building of the switches
|
||||
connected to...).
|
||||
"""
|
||||
return Building.objects.filter(switchbay__switch=self.switch())
|
||||
|
||||
|
@ -186,7 +195,14 @@ class Server(Machine):
|
|||
|
||||
@classmethod
|
||||
def all_server_in(cls, building_instance):
|
||||
"""Get a building as argument, returns all server of a building"""
|
||||
"""Get all the servers of the given building.
|
||||
|
||||
Args:
|
||||
building_instance: the building used to find servers.
|
||||
|
||||
Returns:
|
||||
The queryset of all servers in the given building.
|
||||
"""
|
||||
return cls.objects.filter(
|
||||
interface__port__switch__switchbay__building=building_instance
|
||||
).exclude(accesspoint__isnull=False)
|
||||
|
@ -217,17 +233,19 @@ class Server(Machine):
|
|||
|
||||
|
||||
class Switch(Machine):
|
||||
""" Definition d'un switch. Contient un nombre de ports (number),
|
||||
un emplacement (location), un stack parent (optionnel, stack)
|
||||
et un id de membre dans le stack (stack_member_id)
|
||||
relié en onetoone à une interface
|
||||
Pourquoi ne pas avoir fait hériter switch de interface ?
|
||||
Principalement par méconnaissance de la puissance de cette façon de faire.
|
||||
Ceci étant entendu, django crée en interne un onetoone, ce qui a un
|
||||
effet identique avec ce que l'on fait ici
|
||||
"""Switch.
|
||||
|
||||
Validation au save que l'id du stack est bien dans le range id_min
|
||||
id_max de la stack parente"""
|
||||
Attributes:
|
||||
number: the number of ports of the switch.
|
||||
stack: the stack the switch is a part of.
|
||||
stack_member_id: the ID of the switch in the related stack.
|
||||
model: the model of the switch.
|
||||
switchbay: the bay in which the switch is located.
|
||||
radius_key: the RADIUS key of the switch.
|
||||
management_creds: the management credentials of the switch.
|
||||
automatic_provision: whether automatic provision is enabled for the
|
||||
switch.
|
||||
"""
|
||||
|
||||
number = models.PositiveIntegerField(help_text=_("Number of ports."))
|
||||
stack = models.ForeignKey(
|
||||
|
@ -269,8 +287,9 @@ class Switch(Machine):
|
|||
verbose_name_plural = _("switches")
|
||||
|
||||
def clean(self):
|
||||
""" Verifie que l'id stack est dans le bon range
|
||||
Appelle également le clean de la classe parente"""
|
||||
"""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()
|
||||
if self.stack is not None:
|
||||
if self.stack_member_id is not None:
|
||||
|
@ -291,8 +310,12 @@ class Switch(Machine):
|
|||
)
|
||||
|
||||
def create_ports(self, begin, end):
|
||||
""" Crée les ports de begin à end si les valeurs données
|
||||
sont cohérentes. """
|
||||
"""Create ports for the switch if the values are consistent.
|
||||
|
||||
Args:
|
||||
begin: the number of the start port.
|
||||
end: the number of the end port.
|
||||
"""
|
||||
if end < begin:
|
||||
raise ValidationError(_("The end port is less than the start port."))
|
||||
ports_to_create = range(begin, end + 1)
|
||||
|
@ -313,8 +336,7 @@ class Switch(Machine):
|
|||
)
|
||||
|
||||
def main_interface(self):
|
||||
""" Returns the 'main' interface of the switch
|
||||
It must the the management interface for that device"""
|
||||
"""Get the main interface of the switch (the management interface)."""
|
||||
switch_iptype = OptionalTopologie.get_cached_value("switchs_ip_type")
|
||||
if switch_iptype:
|
||||
return (
|
||||
|
@ -329,12 +351,14 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def get_radius_key(self):
|
||||
"""Retourne l'objet de la clef radius de ce switch"""
|
||||
"""Get the RADIUS key object related to the switch."""
|
||||
return self.radius_key or RadiusKey.objects.filter(default_switch=True).first()
|
||||
|
||||
@cached_property
|
||||
def get_radius_key_value(self):
|
||||
"""Retourne la valeur en str de la clef radius, none si il n'y en a pas"""
|
||||
"""Get the RADIUS key as a string, or None if there are no RADIUS key
|
||||
related to the switch.
|
||||
"""
|
||||
if self.get_radius_key:
|
||||
return self.get_radius_key.radius_key
|
||||
else:
|
||||
|
@ -362,7 +386,7 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def get_management_cred(self):
|
||||
"""Retourne l'objet des creds de managament de ce switch"""
|
||||
"""Get the management credentials objects of the switch."""
|
||||
return (
|
||||
self.management_creds
|
||||
or SwitchManagementCred.objects.filter(default_switch=True).first()
|
||||
|
@ -370,7 +394,9 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def get_management_cred_value(self):
|
||||
"""Retourne un dict des creds de management du switch"""
|
||||
"""Get the management credentials as a dictionary, or None if there are
|
||||
no management credentials related to the switch.
|
||||
"""
|
||||
if self.get_management_cred:
|
||||
return {
|
||||
"id": self.get_management_cred.management_id,
|
||||
|
@ -401,17 +427,19 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def ipv4(self):
|
||||
"""Return the switch's management ipv4"""
|
||||
"""Get the IPv4 address of the switch's management interface."""
|
||||
return str(self.main_interface().ipv4)
|
||||
|
||||
@cached_property
|
||||
def ipv6(self):
|
||||
"""Returne the switch's management ipv6"""
|
||||
"""Get the IPv6 address of the switch's management interface."""
|
||||
return str(self.main_interface().ipv6().first())
|
||||
|
||||
@cached_property
|
||||
def interfaces_subnet(self):
|
||||
"""Return dict ip:subnet for all ip of the switch"""
|
||||
"""Get a dictionary of IPv4 addresses:subnets of all the switch's
|
||||
interfaces.
|
||||
"""
|
||||
return dict(
|
||||
(
|
||||
str(interface.ipv4),
|
||||
|
@ -423,7 +451,9 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def interfaces6_subnet(self):
|
||||
"""Return dict ip6:subnet for all ipv6 of the switch"""
|
||||
"""Get a dictionary of IPv6 addresses:subnets of all the switch's
|
||||
interfaces.
|
||||
"""
|
||||
return dict(
|
||||
(
|
||||
str(interface.ipv6().first()),
|
||||
|
@ -434,7 +464,9 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def list_modules(self):
|
||||
"""Return modules of that switch, list of dict (rank, reference)"""
|
||||
"""Get the list of dictionaries (rank, reference) of modules related to
|
||||
the switch.
|
||||
"""
|
||||
modules = []
|
||||
if getattr(self.model, "is_modular", None):
|
||||
if self.model.is_itself_module:
|
||||
|
@ -445,7 +477,7 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def get_dormitory(self):
|
||||
"""Returns the dormitory of that switch"""
|
||||
"""Get the dormitory in which the switch is located."""
|
||||
if self.switchbay:
|
||||
return self.switchbay.building.dormitory
|
||||
else:
|
||||
|
@ -453,19 +485,19 @@ class Switch(Machine):
|
|||
|
||||
@classmethod
|
||||
def nothing_profile(cls):
|
||||
"""Return default nothing port profile"""
|
||||
"""Return default nothing port profile."""
|
||||
nothing_profile, _created = PortProfile.objects.get_or_create(
|
||||
profil_default="nothing", name="nothing", radius_type="NO"
|
||||
)
|
||||
return nothing_profile
|
||||
|
||||
def profile_type_or_nothing(self, profile_type):
|
||||
"""Return the profile for a profile_type of this switch
|
||||
"""Return the profile for a profile_type of this switch.
|
||||
|
||||
If exists, returns the defined default profile for a profile type on the dormitory which
|
||||
the switch belongs
|
||||
|
||||
Otherwise, returns the nothing profile"""
|
||||
If it exists, return the defined default profile for a profile type on
|
||||
the dormitory which the switch belongs.
|
||||
Otherwise, return the nothing profile.
|
||||
"""
|
||||
profile_queryset = PortProfile.objects.filter(profil_default=profile_type)
|
||||
if self.get_dormitory:
|
||||
port_profile = (
|
||||
|
@ -478,22 +510,22 @@ class Switch(Machine):
|
|||
|
||||
@cached_property
|
||||
def default_uplink_profile(self):
|
||||
"""Default uplink profile for that switch -- in cache"""
|
||||
"""Default uplink profile for that switch -- in cache."""
|
||||
return self.profile_type_or_nothing("uplink")
|
||||
|
||||
@cached_property
|
||||
def default_access_point_profile(self):
|
||||
"""Default ap profile for that switch -- in cache"""
|
||||
"""Default AP profile for that switch -- in cache."""
|
||||
return self.profile_type_or_nothing("access_point")
|
||||
|
||||
@cached_property
|
||||
def default_room_profile(self):
|
||||
"""Default room profile for that switch -- in cache"""
|
||||
"""Default room profile for that switch -- in cache."""
|
||||
return self.profile_type_or_nothing("room")
|
||||
|
||||
@cached_property
|
||||
def default_asso_machine_profile(self):
|
||||
"""Default asso machine profile for that switch -- in cache"""
|
||||
"""Default asso machine profile for that switch -- in cache."""
|
||||
return self.profile_type_or_nothing("asso_machine")
|
||||
|
||||
def __str__(self):
|
||||
|
@ -522,7 +554,16 @@ class Switch(Machine):
|
|||
|
||||
|
||||
class ModelSwitch(AclMixin, RevMixin, models.Model):
|
||||
"""Un modèle (au sens constructeur) de switch"""
|
||||
"""Switch model.
|
||||
|
||||
Attributes:
|
||||
reference: the reference of the switch model.
|
||||
commercial_name: the commercial name of the switch model.
|
||||
constructor: the constructor of the switch model.
|
||||
firmware: the firmware of the switch model.
|
||||
is_modular: whether the switch model is modular.
|
||||
is_itself_module: whether the switch is considered as a module.
|
||||
"""
|
||||
|
||||
reference = models.CharField(max_length=255)
|
||||
commercial_name = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
@ -550,7 +591,12 @@ class ModelSwitch(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class ModuleSwitch(AclMixin, RevMixin, models.Model):
|
||||
"""A module of a switch"""
|
||||
"""Switch module.
|
||||
|
||||
Attributes:
|
||||
reference: the reference of the switch module.
|
||||
comment: the comment to describe the switch module.
|
||||
"""
|
||||
|
||||
reference = models.CharField(
|
||||
max_length=255,
|
||||
|
@ -575,7 +621,13 @@ class ModuleSwitch(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class ModuleOnSwitch(AclMixin, RevMixin, models.Model):
|
||||
"""Link beetween module and switch"""
|
||||
"""Link beetween module and switch.
|
||||
|
||||
Attributes:
|
||||
module: the switch module related to the link.
|
||||
switch: the switch related to the link.
|
||||
slot: the slot on the switch related to the link.
|
||||
"""
|
||||
|
||||
module = models.ForeignKey("ModuleSwitch", on_delete=models.CASCADE)
|
||||
switch = models.ForeignKey("Switch", on_delete=models.CASCADE)
|
||||
|
@ -601,7 +653,11 @@ class ModuleOnSwitch(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class ConstructorSwitch(AclMixin, RevMixin, models.Model):
|
||||
"""Un constructeur de switch"""
|
||||
"""Switch constructor.
|
||||
|
||||
Attributes:
|
||||
name: the name of the switch constructor.
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
|
@ -617,7 +673,13 @@ class ConstructorSwitch(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class SwitchBay(AclMixin, RevMixin, models.Model):
|
||||
"""Une baie de brassage"""
|
||||
"""Switch bay.
|
||||
|
||||
Attributes:
|
||||
name: the name of the switch bay.
|
||||
building: the building in which the switch bay is located.
|
||||
info: the information to describe to switch bay.
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
building = models.ForeignKey("Building", on_delete=models.PROTECT)
|
||||
|
@ -633,8 +695,11 @@ class SwitchBay(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class Dormitory(AclMixin, RevMixin, models.Model):
|
||||
"""A student accomodation/dormitory
|
||||
Une résidence universitaire"""
|
||||
"""Dormitory.
|
||||
|
||||
Attributes:
|
||||
name: the name of the dormitory.
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
|
@ -644,7 +709,7 @@ class Dormitory(AclMixin, RevMixin, models.Model):
|
|||
verbose_name_plural = _("dormitories")
|
||||
|
||||
def all_ap_in(self):
|
||||
"""Returns all ap of the dorms"""
|
||||
"""Get all the APs in the dormitory."""
|
||||
return AccessPoint.all_ap_in(self.building_set.all())
|
||||
|
||||
@classmethod
|
||||
|
@ -660,8 +725,13 @@ class Dormitory(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class Building(AclMixin, RevMixin, models.Model):
|
||||
"""A building of a dormitory
|
||||
Un batiment"""
|
||||
"""Building.
|
||||
|
||||
Attributes:
|
||||
name: the name of the building.
|
||||
dormitory: the dormitory of the building (a Dormitory can contain
|
||||
multiple dormitories).
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
dormitory = models.ForeignKey("Dormitory", on_delete=models.PROTECT)
|
||||
|
@ -672,7 +742,7 @@ class Building(AclMixin, RevMixin, models.Model):
|
|||
verbose_name_plural = _("buildings")
|
||||
|
||||
def all_ap_in(self):
|
||||
"""Returns all ap of the building"""
|
||||
"""Get all the APs in the building."""
|
||||
return AccessPoint.all_ap_in(self)
|
||||
|
||||
def get_name(self):
|
||||
|
@ -690,21 +760,32 @@ class Building(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class Port(AclMixin, RevMixin, models.Model):
|
||||
""" Definition d'un port. Relié à un switch(foreign_key),
|
||||
un port peut etre relié de manière exclusive à :
|
||||
- une chambre (room)
|
||||
- une machine (serveur etc) (machine_interface)
|
||||
- un autre port (uplink) (related)
|
||||
Champs supplémentaires :
|
||||
- RADIUS (mode STRICT : connexion sur port uniquement si machine
|
||||
d'un adhérent à jour de cotisation et que la chambre est également à
|
||||
jour de cotisation
|
||||
mode COMMON : vérification uniquement du statut de la machine
|
||||
mode NO : accepte toute demande venant du port et place sur le vlan normal
|
||||
mode BLOQ : rejet de toute authentification
|
||||
- vlan_force : override la politique générale de placement vlan, permet
|
||||
de forcer un port sur un vlan particulier. S'additionne à la politique
|
||||
RADIUS"""
|
||||
"""Port of a switch.
|
||||
|
||||
A port is related exclusively to either:
|
||||
* a room
|
||||
* a machine, e.g. server
|
||||
* another port
|
||||
Behaviour according to the RADIUS mode:
|
||||
* STRICT: connection only if the machine and room have access
|
||||
* COMMON: check only the machine's state
|
||||
* NO: accept only request coming from the port and set on the standard
|
||||
VLAN.
|
||||
* BLOQ: reject all requests.
|
||||
The VLAN can be forced to override the general policy for VLAN setting.
|
||||
This enables to force a port to a particular VLAN. It adds to the RADIUS
|
||||
policy.
|
||||
|
||||
Attributes:
|
||||
switch: the switch to which the port belongs.
|
||||
port: the port number on the switch for the Port object.
|
||||
room: the room to which the port is related.
|
||||
machine_interface: the machine to which the port is related
|
||||
related: the other port to which is port is related.
|
||||
custom_profile: the port profile of the port.
|
||||
state: whether the port is active.
|
||||
details: the details to describre the port.
|
||||
"""
|
||||
|
||||
switch = models.ForeignKey("Switch", related_name="ports", on_delete=models.CASCADE)
|
||||
port = models.PositiveIntegerField()
|
||||
|
@ -733,7 +814,7 @@ class Port(AclMixin, RevMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def pretty_name(self):
|
||||
"""More elaborated name for label on switch conf"""
|
||||
"""More elaborated name for label on switch configuration."""
|
||||
if self.related:
|
||||
return _("Uplink: ") + self.related.switch.short_name
|
||||
elif self.machine_interface:
|
||||
|
@ -745,14 +826,13 @@ class Port(AclMixin, RevMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def get_port_profile(self):
|
||||
"""Return the config profil for this port
|
||||
:returns: the profile of self (port)
|
||||
|
||||
If is defined a custom profile, returns it
|
||||
elIf a default profile is defined for its dormitory, returns it
|
||||
Else, returns the global default profil
|
||||
If not exists, create a nothing profile"""
|
||||
"""Get the configuration profile for this port.
|
||||
|
||||
Returns:
|
||||
The custom profile if it exists, else the default profile of the
|
||||
dormitory if it exists, else the global default profile, else the
|
||||
nothing profile.
|
||||
"""
|
||||
if self.custom_profile:
|
||||
return self.custom_profile
|
||||
elif self.related:
|
||||
|
@ -779,26 +859,25 @@ class Port(AclMixin, RevMixin, models.Model):
|
|||
)
|
||||
|
||||
def make_port_related(self):
|
||||
""" Synchronise le port distant sur self"""
|
||||
"""Synchronise the related port with self."""
|
||||
related_port = self.related
|
||||
related_port.related = self
|
||||
related_port.save()
|
||||
|
||||
def clean_port_related(self):
|
||||
""" Supprime la relation related sur self"""
|
||||
"""Delete the related relation on self."""
|
||||
related_port = self.related_port
|
||||
related_port.related = None
|
||||
related_port.save()
|
||||
|
||||
def clean(self):
|
||||
""" Verifie que un seul de chambre, interface_parent et related_port
|
||||
est rempli. Verifie que le related n'est pas le port lui-même....
|
||||
Verifie que le related n'est pas déjà occupé par une machine ou une
|
||||
chambre. Si ce n'est pas le cas, applique la relation related
|
||||
Si un port related point vers self, on nettoie la relation
|
||||
A priori pas d'autre solution que de faire ça à la main. A priori
|
||||
tout cela est dans un bloc transaction, donc pas de problème de
|
||||
cohérence"""
|
||||
"""
|
||||
Check if the port is only related exclusively to either a room, a
|
||||
machine or another port.
|
||||
Check if the related port is not self and applies the relation to the
|
||||
related port if the relation is correct.
|
||||
Delete the relation if it points to self.
|
||||
"""
|
||||
if hasattr(self, "switch"):
|
||||
if self.port > self.switch.number:
|
||||
raise ValidationError(
|
||||
|
@ -835,7 +914,13 @@ class Port(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class Room(AclMixin, RevMixin, models.Model):
|
||||
"""Une chambre/local contenant une prise murale"""
|
||||
"""Room.
|
||||
|
||||
Attributes:
|
||||
name: the name of the room.
|
||||
details: the details describing the room.
|
||||
building: the building in which the room is located.
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
details = models.CharField(max_length=255, blank=True)
|
||||
|
@ -853,7 +938,28 @@ class Room(AclMixin, RevMixin, models.Model):
|
|||
|
||||
|
||||
class PortProfile(AclMixin, RevMixin, models.Model):
|
||||
"""Contains the information of the ports' configuration for a switch"""
|
||||
"""Port profile.
|
||||
|
||||
Contains the information of the ports' configuration for a switch.
|
||||
|
||||
Attributes:
|
||||
name: the name of the port profile.
|
||||
profil_default: the type of default profile (room, AP, uplink etc.).
|
||||
on_dormitory: the dormitory with this default port profile.
|
||||
vlan_untagged: the VLAN untagged of the port profile.
|
||||
vlan_tagged: the VLAN(s) tagged of the port profile.
|
||||
radius_type: the type of RADIUS authentication (inactive, MAC-address
|
||||
or 802.1X) of the port profile.
|
||||
radius_mode: the RADIUS mode of the port profile.
|
||||
speed: the port speed limit of the port profile.
|
||||
mac_limit: the MAC limit of the port profile.
|
||||
flow_control: whether flow control is enabled.
|
||||
dhcp_snooping: whether DHCP snooping is enabled.
|
||||
dhcpv6_snooping: whether DHCPv6 snooping is enabled.
|
||||
arp_protect: whether ARP protection is enabled.
|
||||
ra_guard: whether RA guard is enabled.
|
||||
loop_protect: whether loop protection is enabled.
|
||||
"""
|
||||
|
||||
TYPES = (("NO", "NO"), ("802.1X", "802.1X"), ("MAC-radius", _("MAC-RADIUS")))
|
||||
MODES = (("STRICT", "STRICT"), ("COMMON", "COMMON"))
|
||||
|
@ -983,7 +1089,7 @@ class PortProfile(AclMixin, RevMixin, models.Model):
|
|||
return ",".join(self.security_parameters_enabled)
|
||||
|
||||
def clean(self):
|
||||
""" Check that there is only one generic profil default"""
|
||||
"""Check that there is only one generic profile default."""
|
||||
super(PortProfile, self).clean()
|
||||
if (
|
||||
self.profil_default
|
||||
|
@ -1007,21 +1113,21 @@ class PortProfile(AclMixin, RevMixin, models.Model):
|
|||
|
||||
@receiver(post_save, sender=AccessPoint)
|
||||
def ap_post_save(**_kwargs):
|
||||
"""Regeneration des noms des bornes vers le controleur"""
|
||||
"""Regenerate the AP names towards the controller."""
|
||||
regen("unifi-ap-names")
|
||||
regen("graph_topo")
|
||||
|
||||
|
||||
@receiver(post_delete, sender=AccessPoint)
|
||||
def ap_post_delete(**_kwargs):
|
||||
"""Regeneration des noms des bornes vers le controleur"""
|
||||
"""Regenerate the AP names towards the controller."""
|
||||
regen("unifi-ap-names")
|
||||
regen("graph_topo")
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Stack)
|
||||
def stack_post_delete(**_kwargs):
|
||||
"""Vide les id des switches membres d'une stack supprimée"""
|
||||
"""Empty the stack member ID of switches when a stack is deleted."""
|
||||
Switch.objects.filter(stack=None).update(stack_member_id=None)
|
||||
|
||||
|
||||
|
|
|
@ -19,11 +19,8 @@
|
|||
# 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.
|
||||
"""
|
||||
Definition des urls de l'application topologie.
|
||||
Inclu dans urls de re2o.
|
||||
|
||||
Fait référence aux fonctions du views
|
||||
"""topologie.urls
|
||||
The defined URLs for topologie app. Included in re2o.urls.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
|
|
@ -20,18 +20,17 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Page des vues de l'application topologie
|
||||
Views for the 'topologie' app of re2o.
|
||||
|
||||
Permet de créer, modifier et supprimer :
|
||||
- un port (add_port, edit_port, del_port)
|
||||
- un switch : les vues d'ajout et d'édition font appel aux forms de creation
|
||||
de switch, mais aussi aux forms de machines.forms (domain, interface et
|
||||
machine). Le views les envoie et les save en même temps. TODO : rationaliser
|
||||
et faire que la creation de machines (interfaces, domain etc) soit gérée
|
||||
coté models et forms de topologie
|
||||
- une chambre (new_room, edit_room, del_room)
|
||||
- une stack
|
||||
- l'historique de tous les objets cités
|
||||
They are used to create, edit and delete:
|
||||
* a port (add_port, edit_port, del_port)
|
||||
* a switch: the views call forms for switches but also machines (domain,
|
||||
interface and machine), send and save them at the same time.
|
||||
TODO rationalise, enforce the creation of machines (interfaces, domains
|
||||
etc.) in models and forms from 'topologie'
|
||||
* a room (new_room, edit_room, del_room)
|
||||
* a stack
|
||||
* histories of all objects mentioned.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
@ -105,7 +104,7 @@ from os.path import isfile
|
|||
@login_required
|
||||
@can_view_all(Switch)
|
||||
def index(request):
|
||||
""" Vue d'affichage de tous les swicthes"""
|
||||
"""View used to display all switches."""
|
||||
switch_list = (
|
||||
Switch.objects.prefetch_related(
|
||||
Prefetch(
|
||||
|
@ -171,7 +170,7 @@ def index_port_profile(request):
|
|||
@can_view_all(Port)
|
||||
@can_view(Switch)
|
||||
def index_port(request, switch, switchid):
|
||||
""" Affichage de l'ensemble des ports reliés à un switch particulier"""
|
||||
"""View used to display all ports related to the given switch."""
|
||||
port_list = (
|
||||
Port.objects.filter(switch=switch)
|
||||
.select_related("room__building__dormitory")
|
||||
|
@ -204,7 +203,7 @@ def index_port(request, switch, switchid):
|
|||
@login_required
|
||||
@can_view_all(Room)
|
||||
def index_room(request):
|
||||
""" Affichage de l'ensemble des chambres"""
|
||||
"""View used to display all rooms."""
|
||||
room_list = Room.objects.select_related("building__dormitory")
|
||||
room_list = SortTable.sort(
|
||||
room_list,
|
||||
|
@ -220,7 +219,7 @@ def index_room(request):
|
|||
@login_required
|
||||
@can_view_all(AccessPoint)
|
||||
def index_ap(request):
|
||||
""" Affichage de l'ensemble des bornes"""
|
||||
"""View used to display all APs."""
|
||||
ap_list = AccessPoint.objects.prefetch_related(
|
||||
Prefetch(
|
||||
"interface_set",
|
||||
|
@ -245,7 +244,7 @@ def index_ap(request):
|
|||
@login_required
|
||||
@can_view_all(Stack, Building, Dormitory, SwitchBay)
|
||||
def index_physical_grouping(request):
|
||||
"""Affichage de la liste des stacks (affiche l'ensemble des switches)"""
|
||||
"""View used to display the list of stacks (display all switches)."""
|
||||
stack_list = Stack.objects.prefetch_related(
|
||||
"switch_set__interface_set__domain__extension"
|
||||
)
|
||||
|
@ -293,7 +292,7 @@ def index_physical_grouping(request):
|
|||
@login_required
|
||||
@can_view_all(ModelSwitch, ConstructorSwitch)
|
||||
def index_model_switch(request):
|
||||
""" Affichage de l'ensemble des modèles de switches"""
|
||||
"""View used to display all switch models."""
|
||||
model_switch_list = ModelSwitch.objects.select_related(
|
||||
"constructor"
|
||||
).prefetch_related("switch_set__interface_set__domain")
|
||||
|
@ -323,7 +322,7 @@ def index_model_switch(request):
|
|||
@login_required
|
||||
@can_view_all(ModuleSwitch)
|
||||
def index_module(request):
|
||||
"""Display all modules of switchs"""
|
||||
"""View used to display all switch modules."""
|
||||
module_list = ModuleSwitch.objects.all()
|
||||
modular_switchs = (
|
||||
Switch.objects.filter(model__is_modular=True)
|
||||
|
@ -342,7 +341,7 @@ def index_module(request):
|
|||
@login_required
|
||||
@can_edit(Vlan)
|
||||
def edit_vlanoptions(request, vlan_instance, **_kwargs):
|
||||
""" View used to edit options for switch of VLAN object """
|
||||
"""View used to edit options for switch of VLAN object."""
|
||||
vlan = EditOptionVlanForm(request.POST or None, instance=vlan_instance)
|
||||
if vlan.is_valid():
|
||||
if vlan.changed_data:
|
||||
|
@ -357,7 +356,7 @@ def edit_vlanoptions(request, vlan_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Port)
|
||||
def new_port(request, switchid):
|
||||
""" Nouveau port"""
|
||||
"""View used to create ports."""
|
||||
try:
|
||||
switch = Switch.objects.get(pk=switchid)
|
||||
except Switch.DoesNotExist:
|
||||
|
@ -383,9 +382,10 @@ def new_port(request, switchid):
|
|||
@login_required
|
||||
@can_edit(Port)
|
||||
def edit_port(request, port_object, **_kwargs):
|
||||
""" Edition d'un port. Permet de changer le switch parent et
|
||||
l'affectation du port"""
|
||||
"""View used to edit ports.
|
||||
|
||||
It enables to change the related switch and the port assignment.
|
||||
"""
|
||||
port = EditPortForm(request.POST or None, instance=port_object)
|
||||
if port.is_valid():
|
||||
if port.changed_data:
|
||||
|
@ -410,7 +410,7 @@ def edit_port(request, port_object, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Port)
|
||||
def del_port(request, port, **_kwargs):
|
||||
""" Supprime le port"""
|
||||
"""View used to delete ports."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
port.delete()
|
||||
|
@ -435,7 +435,7 @@ def del_port(request, port, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Stack)
|
||||
def new_stack(request):
|
||||
"""Ajoute un nouveau stack : stackid_min, max, et nombre de switches"""
|
||||
"""View used to create stacks."""
|
||||
stack = StackForm(request.POST or None)
|
||||
if stack.is_valid():
|
||||
stack.save()
|
||||
|
@ -449,7 +449,7 @@ def new_stack(request):
|
|||
@login_required
|
||||
@can_edit(Stack)
|
||||
def edit_stack(request, stack, **_kwargs):
|
||||
"""Edition d'un stack (nombre de switches, nom...)"""
|
||||
"""View used to edit stacks."""
|
||||
stack = StackForm(request.POST or None, instance=stack)
|
||||
if stack.is_valid():
|
||||
if stack.changed_data:
|
||||
|
@ -464,7 +464,7 @@ def edit_stack(request, stack, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Stack)
|
||||
def del_stack(request, stack, **_kwargs):
|
||||
"""Supprime un stack"""
|
||||
"""View used to delete stacks."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
stack.delete()
|
||||
|
@ -487,8 +487,7 @@ def del_stack(request, stack, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(Stack)
|
||||
def edit_switchs_stack(request, stack, **_kwargs):
|
||||
"""Permet d'éditer la liste des switches dans une stack et l'ajouter"""
|
||||
|
||||
"""View used to edit the list of switches of the given stack."""
|
||||
if request.method == "POST":
|
||||
pass
|
||||
else:
|
||||
|
@ -500,9 +499,12 @@ def edit_switchs_stack(request, stack, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Switch)
|
||||
def new_switch(request):
|
||||
""" Creation d'un switch. Cree en meme temps l'interface et la machine
|
||||
associée. Vue complexe. Appelle successivement les 4 models forms
|
||||
adaptés : machine, interface, domain et switch"""
|
||||
"""View used to create switches.
|
||||
|
||||
At the same time, it creates the related interface and machine. The view
|
||||
successively calls the 4 appropriate forms: machine, interface, domain and
|
||||
switch.
|
||||
"""
|
||||
switch = NewSwitchForm(request.POST or None, user=request.user)
|
||||
interface = AddInterfaceForm(request.POST or None, user=request.user)
|
||||
domain = DomainForm(request.POST or None, user=request.user)
|
||||
|
@ -549,7 +551,7 @@ def new_switch(request):
|
|||
@login_required
|
||||
@can_create(Port)
|
||||
def create_ports(request, switchid):
|
||||
""" Création d'une liste de ports pour un switch."""
|
||||
"""View used to create port lists for the given switch."""
|
||||
try:
|
||||
switch = Switch.objects.get(pk=switchid)
|
||||
except Switch.DoesNotExist:
|
||||
|
@ -578,9 +580,11 @@ def create_ports(request, switchid):
|
|||
@login_required
|
||||
@can_edit(Switch)
|
||||
def edit_switch(request, switch, switchid):
|
||||
""" Edition d'un switch. Permet de chambre nombre de ports,
|
||||
place dans le stack, interface et machine associée"""
|
||||
"""View used to edit switches.
|
||||
|
||||
It enables to change the number of ports, location in the stack, or the
|
||||
related interface and machine.
|
||||
"""
|
||||
switch_form = EditSwitchForm(
|
||||
request.POST or None, instance=switch, user=request.user
|
||||
)
|
||||
|
@ -622,9 +626,11 @@ def edit_switch(request, switch, switchid):
|
|||
@login_required
|
||||
@can_create(AccessPoint)
|
||||
def new_ap(request):
|
||||
""" Creation d'une ap. Cree en meme temps l'interface et la machine
|
||||
associée. Vue complexe. Appelle successivement les 3 models forms
|
||||
adaptés : machine, interface, domain et switch"""
|
||||
"""View used to create APs.
|
||||
|
||||
At the same time, it creates the related interface and machine. The view
|
||||
successively calls the 3 appropriate forms: machine, interface, domain.
|
||||
"""
|
||||
ap = AddAccessPointForm(request.POST or None, user=request.user)
|
||||
interface = AddInterfaceForm(request.POST or None, user=request.user)
|
||||
domain = DomainForm(request.POST or None, user=request.user)
|
||||
|
@ -671,8 +677,7 @@ def new_ap(request):
|
|||
@login_required
|
||||
@can_edit(AccessPoint)
|
||||
def edit_ap(request, ap, **_kwargs):
|
||||
""" Edition d'un switch. Permet de chambre nombre de ports,
|
||||
place dans le stack, interface et machine associée"""
|
||||
"""View used to edit APs."""
|
||||
interface_form = EditInterfaceForm(
|
||||
request.POST or None, user=request.user, instance=ap.interface_set.first()
|
||||
)
|
||||
|
@ -723,7 +728,7 @@ def edit_ap(request, ap, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Room)
|
||||
def new_room(request):
|
||||
"""Nouvelle chambre """
|
||||
"""View used to create rooms."""
|
||||
room = EditRoomForm(request.POST or None)
|
||||
if room.is_valid():
|
||||
room.save()
|
||||
|
@ -737,7 +742,7 @@ def new_room(request):
|
|||
@login_required
|
||||
@can_edit(Room)
|
||||
def edit_room(request, room, **_kwargs):
|
||||
""" Edition numero et details de la chambre"""
|
||||
"""View used to edit rooms."""
|
||||
room = EditRoomForm(request.POST or None, instance=room)
|
||||
if room.is_valid():
|
||||
if room.changed_data:
|
||||
|
@ -752,7 +757,7 @@ def edit_room(request, room, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Room)
|
||||
def del_room(request, room, **_kwargs):
|
||||
""" Suppression d'un chambre"""
|
||||
"""View used to delete rooms."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
room.delete()
|
||||
|
@ -777,7 +782,7 @@ def del_room(request, room, **_kwargs):
|
|||
@login_required
|
||||
@can_create(ModelSwitch)
|
||||
def new_model_switch(request):
|
||||
"""Nouveau modèle de switch"""
|
||||
"""View used to create switch models."""
|
||||
model_switch = EditModelSwitchForm(request.POST or None)
|
||||
if model_switch.is_valid():
|
||||
model_switch.save()
|
||||
|
@ -793,8 +798,7 @@ def new_model_switch(request):
|
|||
@login_required
|
||||
@can_edit(ModelSwitch)
|
||||
def edit_model_switch(request, model_switch, **_kwargs):
|
||||
""" Edition d'un modèle de switch"""
|
||||
|
||||
"""View used to edit switch models."""
|
||||
model_switch = EditModelSwitchForm(request.POST or None, instance=model_switch)
|
||||
if model_switch.is_valid():
|
||||
if model_switch.changed_data:
|
||||
|
@ -811,7 +815,7 @@ def edit_model_switch(request, model_switch, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(ModelSwitch)
|
||||
def del_model_switch(request, model_switch, **_kwargs):
|
||||
""" Suppression d'un modèle de switch"""
|
||||
"""View used to delete switch models."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
model_switch.delete()
|
||||
|
@ -838,7 +842,7 @@ def del_model_switch(request, model_switch, **_kwargs):
|
|||
@login_required
|
||||
@can_create(SwitchBay)
|
||||
def new_switch_bay(request):
|
||||
"""Nouvelle baie de switch"""
|
||||
"""View used to create switch bays."""
|
||||
switch_bay = EditSwitchBayForm(request.POST or None)
|
||||
if switch_bay.is_valid():
|
||||
switch_bay.save()
|
||||
|
@ -854,7 +858,7 @@ def new_switch_bay(request):
|
|||
@login_required
|
||||
@can_edit(SwitchBay)
|
||||
def edit_switch_bay(request, switch_bay, **_kwargs):
|
||||
""" Edition d'une baie de switch"""
|
||||
"""View used to edit switch bays."""
|
||||
switch_bay = EditSwitchBayForm(request.POST or None, instance=switch_bay)
|
||||
if switch_bay.is_valid():
|
||||
if switch_bay.changed_data:
|
||||
|
@ -871,7 +875,7 @@ def edit_switch_bay(request, switch_bay, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(SwitchBay)
|
||||
def del_switch_bay(request, switch_bay, **_kwargs):
|
||||
""" Suppression d'une baie de switch"""
|
||||
"""View used to delete switch bays."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
switch_bay.delete()
|
||||
|
@ -898,8 +902,7 @@ def del_switch_bay(request, switch_bay, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Building)
|
||||
def new_building(request):
|
||||
"""New Building of a dorm
|
||||
Nouveau batiment"""
|
||||
"""View used to create buildings."""
|
||||
building = EditBuildingForm(request.POST or None)
|
||||
if building.is_valid():
|
||||
building.save()
|
||||
|
@ -915,8 +918,7 @@ def new_building(request):
|
|||
@login_required
|
||||
@can_edit(Building)
|
||||
def edit_building(request, building, **_kwargs):
|
||||
"""Edit a building
|
||||
Edition d'un batiment"""
|
||||
"""View used to edit buildings."""
|
||||
building = EditBuildingForm(request.POST or None, instance=building)
|
||||
if building.is_valid():
|
||||
if building.changed_data:
|
||||
|
@ -931,8 +933,7 @@ def edit_building(request, building, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Building)
|
||||
def del_building(request, building, **_kwargs):
|
||||
"""Delete a building
|
||||
Suppression d'un batiment"""
|
||||
"""View used to delete buildings."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
building.delete()
|
||||
|
@ -959,8 +960,7 @@ def del_building(request, building, **_kwargs):
|
|||
@login_required
|
||||
@can_create(Dormitory)
|
||||
def new_dormitory(request):
|
||||
"""A new dormitory
|
||||
Nouvelle residence"""
|
||||
"""View used to create dormitories."""
|
||||
dormitory = EditDormitoryForm(request.POST or None)
|
||||
if dormitory.is_valid():
|
||||
dormitory.save()
|
||||
|
@ -976,8 +976,7 @@ def new_dormitory(request):
|
|||
@login_required
|
||||
@can_edit(Dormitory)
|
||||
def edit_dormitory(request, dormitory, **_kwargs):
|
||||
"""Edit a dormitory
|
||||
Edition d'une residence"""
|
||||
"""View used to edit dormitories."""
|
||||
dormitory = EditDormitoryForm(request.POST or None, instance=dormitory)
|
||||
if dormitory.is_valid():
|
||||
if dormitory.changed_data:
|
||||
|
@ -994,8 +993,7 @@ def edit_dormitory(request, dormitory, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Dormitory)
|
||||
def del_dormitory(request, dormitory, **_kwargs):
|
||||
"""Delete a dormitory
|
||||
Suppression d'une residence"""
|
||||
"""View used to delete dormitories."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
dormitory.delete()
|
||||
|
@ -1022,7 +1020,7 @@ def del_dormitory(request, dormitory, **_kwargs):
|
|||
@login_required
|
||||
@can_create(ConstructorSwitch)
|
||||
def new_constructor_switch(request):
|
||||
"""Nouveau constructeur de switch"""
|
||||
"""View used to create switch constructors."""
|
||||
constructor_switch = EditConstructorSwitchForm(request.POST or None)
|
||||
if constructor_switch.is_valid():
|
||||
constructor_switch.save()
|
||||
|
@ -1038,8 +1036,7 @@ def new_constructor_switch(request):
|
|||
@login_required
|
||||
@can_edit(ConstructorSwitch)
|
||||
def edit_constructor_switch(request, constructor_switch, **_kwargs):
|
||||
""" Edition d'un constructeur de switch"""
|
||||
|
||||
"""View used to edit switch constructors."""
|
||||
constructor_switch = EditConstructorSwitchForm(
|
||||
request.POST or None, instance=constructor_switch
|
||||
)
|
||||
|
@ -1058,7 +1055,7 @@ def edit_constructor_switch(request, constructor_switch, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(ConstructorSwitch)
|
||||
def del_constructor_switch(request, constructor_switch, **_kwargs):
|
||||
""" Suppression d'un constructeur de switch"""
|
||||
"""View used to delete switch constructors."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
constructor_switch.delete()
|
||||
|
@ -1085,7 +1082,7 @@ def del_constructor_switch(request, constructor_switch, **_kwargs):
|
|||
@login_required
|
||||
@can_create(PortProfile)
|
||||
def new_port_profile(request):
|
||||
"""Create a new port profile"""
|
||||
"""View used to create port profiles."""
|
||||
port_profile = EditPortProfileForm(request.POST or None)
|
||||
if port_profile.is_valid():
|
||||
port_profile.save()
|
||||
|
@ -1101,7 +1098,7 @@ def new_port_profile(request):
|
|||
@login_required
|
||||
@can_edit(PortProfile)
|
||||
def edit_port_profile(request, port_profile, **_kwargs):
|
||||
"""Edit a port profile"""
|
||||
"""View used to edit port profiles."""
|
||||
port_profile = EditPortProfileForm(request.POST or None, instance=port_profile)
|
||||
if port_profile.is_valid():
|
||||
if port_profile.changed_data:
|
||||
|
@ -1118,7 +1115,7 @@ def edit_port_profile(request, port_profile, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(PortProfile)
|
||||
def del_port_profile(request, port_profile, **_kwargs):
|
||||
"""Delete a port profile"""
|
||||
"""View used to delete port profiles."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
port_profile.delete()
|
||||
|
@ -1136,7 +1133,7 @@ def del_port_profile(request, port_profile, **_kwargs):
|
|||
@login_required
|
||||
@can_create(ModuleSwitch)
|
||||
def add_module(request):
|
||||
""" View used to add a Module object """
|
||||
"""View used to create switch modules."""
|
||||
module = EditModuleForm(request.POST or None)
|
||||
if module.is_valid():
|
||||
module.save()
|
||||
|
@ -1150,7 +1147,7 @@ def add_module(request):
|
|||
@login_required
|
||||
@can_edit(ModuleSwitch)
|
||||
def edit_module(request, module_instance, **_kwargs):
|
||||
""" View used to edit a Module object """
|
||||
"""View used to edit switch modules."""
|
||||
module = EditModuleForm(request.POST or None, instance=module_instance)
|
||||
if module.is_valid():
|
||||
if module.changed_data:
|
||||
|
@ -1165,7 +1162,7 @@ def edit_module(request, module_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(ModuleSwitch)
|
||||
def del_module(request, module, **_kwargs):
|
||||
"""Compleete delete a module"""
|
||||
"""View used to delete switch modules."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
module.delete()
|
||||
|
@ -1190,7 +1187,7 @@ def del_module(request, module, **_kwargs):
|
|||
@login_required
|
||||
@can_create(ModuleOnSwitch)
|
||||
def add_module_on(request):
|
||||
"""Add a module to a switch"""
|
||||
"""View used to add a module to a switch."""
|
||||
module_switch = EditSwitchModuleForm(request.POST or None)
|
||||
if module_switch.is_valid():
|
||||
module_switch.save()
|
||||
|
@ -1206,7 +1203,7 @@ def add_module_on(request):
|
|||
@login_required
|
||||
@can_edit(ModuleOnSwitch)
|
||||
def edit_module_on(request, module_instance, **_kwargs):
|
||||
""" View used to edit a Module object """
|
||||
"""View used to edit a module on a switch."""
|
||||
module = EditSwitchModuleForm(request.POST or None, instance=module_instance)
|
||||
if module.is_valid():
|
||||
if module.changed_data:
|
||||
|
@ -1221,7 +1218,7 @@ def edit_module_on(request, module_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(ModuleOnSwitch)
|
||||
def del_module_on(request, module, **_kwargs):
|
||||
"""Compleete delete a module"""
|
||||
"""View used to delete a module on a switch."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
module.delete()
|
||||
|
@ -1244,9 +1241,7 @@ def del_module_on(request, module, **_kwargs):
|
|||
|
||||
|
||||
def make_machine_graph():
|
||||
"""
|
||||
Create the graph of switchs, machines and access points.
|
||||
"""
|
||||
"""Create the graph of switches, machines and access points."""
|
||||
dico = {
|
||||
"subs": [],
|
||||
"links": [],
|
||||
|
@ -1284,7 +1279,7 @@ def make_machine_graph():
|
|||
"machines": [],
|
||||
}
|
||||
)
|
||||
# Visit all switchs in this building
|
||||
# Visit all switches in this building
|
||||
for switch in (
|
||||
Switch.objects.filter(switchbay__building=building)
|
||||
.prefetch_related(
|
||||
|
@ -1311,7 +1306,7 @@ def make_machine_graph():
|
|||
"ports": [],
|
||||
}
|
||||
)
|
||||
# visit all ports of this switch and add the switchs linked to it
|
||||
# visit all ports of this switch and add the switches linked to it
|
||||
for port in switch.ports.filter(related__isnull=False).select_related(
|
||||
"related__switch"
|
||||
):
|
||||
|
@ -1365,29 +1360,29 @@ def make_machine_graph():
|
|||
links, new_detected = recursive_switchs(missing[0], None, [missing[0]])
|
||||
for link in links:
|
||||
dico["links"].append(link)
|
||||
# Update the lists of missings and already detected switchs
|
||||
# Update the lists of missings and already detected switches
|
||||
missing = [i for i in missing if i not in new_detected]
|
||||
detected += new_detected
|
||||
# If the switch have no ports, don't explore it and hop to the next one
|
||||
# If the switch has no ports, don't explore it and hop to the next one
|
||||
else:
|
||||
del missing[0]
|
||||
# Switchs that are not connected or not in a building
|
||||
# Switches that are not connected or not in a building
|
||||
for switch in Switch.objects.filter(switchbay__isnull=True).exclude(
|
||||
ports__related__isnull=False
|
||||
):
|
||||
dico["alone"].append({"id": switch.id, "name": switch.get_name})
|
||||
|
||||
# generate the dot file
|
||||
# Generate the dot file
|
||||
dot_data = generate_dot(dico, "topologie/graph_switch.dot")
|
||||
|
||||
# Create a temporary file to store the dot data
|
||||
f = tempfile.NamedTemporaryFile(mode="w+", encoding="utf-8", delete=False)
|
||||
with f:
|
||||
f.write(dot_data)
|
||||
unflatten = Popen( # unflatten the graph to make it look better
|
||||
unflatten = Popen( # Unflatten the graph to make it look better
|
||||
["unflatten", "-l", "3", f.name], stdout=PIPE
|
||||
)
|
||||
Popen( # pipe the result of the first command into the second
|
||||
Popen( # Pipe the result of the first command into the second
|
||||
["dot", "-Tpng", "-o", MEDIA_ROOT + "/images/switchs.png"],
|
||||
stdin=unflatten.stdout,
|
||||
stdout=PIPE,
|
||||
|
@ -1395,10 +1390,15 @@ def make_machine_graph():
|
|||
|
||||
|
||||
def generate_dot(data, template):
|
||||
"""create the dot file
|
||||
:param data: dictionary passed to the template
|
||||
:param template: path to the dot template
|
||||
:return: all the lines of the dot file"""
|
||||
"""Generate a dot file from the data and template given.
|
||||
|
||||
Args:
|
||||
data: dictionary passed to the template.
|
||||
template: path to the dot template.
|
||||
|
||||
Returns:
|
||||
All the lines of the dot file.
|
||||
"""
|
||||
t = loader.get_template(template)
|
||||
if not isinstance(t, Template) and not (
|
||||
hasattr(t, "template") and isinstance(t.template, Template)
|
||||
|
@ -1415,18 +1415,19 @@ def generate_dot(data, template):
|
|||
|
||||
|
||||
def recursive_switchs(switch_start, switch_before, detected):
|
||||
"""Visit the switch and travel to the switchs linked to it.
|
||||
:param switch_start: the switch to begin the visit on
|
||||
:param switch_before: the switch that you come from.
|
||||
None if switch_start is the first one
|
||||
:param detected: list of all switchs already visited.
|
||||
None if switch_start is the first one
|
||||
:return: A list of all the links found and a list of
|
||||
all the switchs visited
|
||||
"""Visit the switch and travel to the switches linked to it.
|
||||
|
||||
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.
|
||||
|
||||
Returns:
|
||||
A list of all the links found and a list of all the switches visited.
|
||||
"""
|
||||
detected.append(switch_start)
|
||||
links_return = [] # list of dictionaries of the links to be detected
|
||||
# create links to every switchs below
|
||||
links_return = [] # List of dictionaries of the links to be detected
|
||||
# Create links to every switches below
|
||||
for port in switch_start.ports.filter(related__isnull=False):
|
||||
# Not the switch that we come from, not the current switch
|
||||
if (
|
||||
|
@ -1440,11 +1441,11 @@ def recursive_switchs(switch_start, switch_before, detected):
|
|||
}
|
||||
links_return.append(links) # Add current and below levels links
|
||||
|
||||
# go down on every related switchs
|
||||
# Go down on every related switches
|
||||
for port in switch_start.ports.filter(related__isnull=False):
|
||||
# The switch at the end of this link has not been visited
|
||||
if port.related.switch not in detected:
|
||||
# explore it and get the results
|
||||
# Explore it and get the results
|
||||
links_down, detected = recursive_switchs(
|
||||
port.related.switch, switch_start, detected
|
||||
)
|
||||
|
|
121
users/admin.py
121
users/admin.py
|
@ -21,8 +21,10 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Definition des vues pour les admin. Classique, sauf pour users,
|
||||
où on fait appel à UserChange et ServiceUserChange, forms custom
|
||||
Admin views basic definition, include basic definition of admin view.
|
||||
|
||||
Except for Admin edition and creation of users and services users;
|
||||
with AdherentAdmin, ClubAdmin and ServiceUserAdmin.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -56,15 +58,26 @@ from .forms import (
|
|||
|
||||
|
||||
class LdapUserAdmin(admin.ModelAdmin):
|
||||
"""Administration du ldapuser"""
|
||||
"""LdapUser Admin view. Can't change password, manage
|
||||
by User General model.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
list_display = ("name", "uidNumber", "login_shell")
|
||||
exclude = ("user_password", "sambat_nt_password")
|
||||
search_fields = ("name",)
|
||||
|
||||
|
||||
class LdapServiceUserAdmin(admin.ModelAdmin):
|
||||
"""Administration du ldapserviceuser"""
|
||||
"""LdapServiceUser Admin view. Can't change password, manage
|
||||
by User General model.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
list_display = ("name",)
|
||||
exclude = ("user_password",)
|
||||
|
@ -72,63 +85,123 @@ class LdapServiceUserAdmin(admin.ModelAdmin):
|
|||
|
||||
|
||||
class LdapUserGroupAdmin(admin.ModelAdmin):
|
||||
"""Administration du ldapusergroupe"""
|
||||
"""LdapUserGroup Admin view.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
list_display = ("name", "members", "gid")
|
||||
search_fields = ("name",)
|
||||
|
||||
|
||||
class LdapServiceUserGroupAdmin(admin.ModelAdmin):
|
||||
"""Administration du ldap serviceusergroup"""
|
||||
"""LdapServiceUserGroup Admin view.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
list_display = ("name",)
|
||||
search_fields = ("name",)
|
||||
|
||||
|
||||
class SchoolAdmin(VersionAdmin):
|
||||
"""Administration, gestion des écoles"""
|
||||
"""School Admin view and management.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ListRightAdmin(VersionAdmin):
|
||||
"""Gestion de la liste des droits existants
|
||||
Ne permet pas l'edition du gid (primarykey pour ldap)"""
|
||||
"""ListRight and groups Admin view and management.
|
||||
Even if it is possible, gid should NOT be changed
|
||||
as it is the ldap primary key.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
list_display = ("unix_name",)
|
||||
|
||||
|
||||
class ListShellAdmin(VersionAdmin):
|
||||
"""Gestion de la liste des shells coté admin"""
|
||||
"""Users Shell Admin view and management.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class RequestAdmin(admin.ModelAdmin):
|
||||
"""Gestion des request objet, ticket pour lien de reinit mot de passe"""
|
||||
"""User Request Admin view and management, for
|
||||
change password and email validation.
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
list_display = ("user", "type", "created_at", "expires_at")
|
||||
|
||||
|
||||
class BanAdmin(VersionAdmin):
|
||||
"""Gestion des bannissements"""
|
||||
"""Ban Admin view and management, for
|
||||
User Ban
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class EMailAddressAdmin(VersionAdmin):
|
||||
"""Gestion des alias mail"""
|
||||
"""EmailAddress Admin view and management, for
|
||||
auxiliary and local email addresses
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class WhitelistAdmin(VersionAdmin):
|
||||
"""Gestion des whitelist"""
|
||||
"""Whitelist Admin view and management, for
|
||||
free access whitelisted users
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AdherentAdmin(VersionAdmin, BaseUserAdmin):
|
||||
"""Adherent Admin view and management, for
|
||||
Adherent fields : password, pseudo, etc, admin can
|
||||
edit all fields on user instance.
|
||||
Inherit from django BaseUserAdmin
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
# The forms to add and change user instances
|
||||
|
||||
add_form = UserAdminForm
|
||||
|
@ -179,6 +252,15 @@ class AdherentAdmin(VersionAdmin, BaseUserAdmin):
|
|||
|
||||
|
||||
class ClubAdmin(VersionAdmin, BaseUserAdmin):
|
||||
"""Club Admin view and management, for
|
||||
Club fields : password, pseudo, etc, admin can
|
||||
edit all fields on user instance.
|
||||
Inherit from django BaseUserAdmin
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
# The forms to add and change user instances
|
||||
add_form = UserAdminForm
|
||||
form = UserAdminForm
|
||||
|
@ -225,8 +307,15 @@ class ClubAdmin(VersionAdmin, BaseUserAdmin):
|
|||
|
||||
|
||||
class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
|
||||
"""Gestion d'un service user admin : champs personnels,
|
||||
mot de passe; etc"""
|
||||
"""ServiceUser Admin view and management, for
|
||||
User fields : password, pseudo, etc, admin can
|
||||
edit all fields on user instance.
|
||||
Inherit from django BaseUserAdmin
|
||||
|
||||
Parameters:
|
||||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
# The forms to add and change user instances
|
||||
form = ServiceUserAdminForm
|
||||
|
|
448
users/forms.py
448
users/forms.py
|
@ -23,14 +23,20 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Definition des forms pour l'application users.
|
||||
Forms for the 'users' app of re2o. It highly depends on
|
||||
:users:models and is mainly used by :users:views.
|
||||
|
||||
Modification, creation de :
|
||||
- un user (informations personnelles)
|
||||
- un bannissement
|
||||
- le mot de passe d'un user
|
||||
- une whiteliste
|
||||
- un user de service
|
||||
The following forms are mainly used to create, edit or delete
|
||||
anything related to 'users' :
|
||||
* Adherent (personnal data)
|
||||
* Club
|
||||
* Ban
|
||||
* ServiceUser
|
||||
* Whitelists
|
||||
* ...
|
||||
|
||||
See the details for each of these operations in the documentation
|
||||
of each of the method.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -72,62 +78,16 @@ from .models import (
|
|||
)
|
||||
|
||||
|
||||
class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
|
||||
"""Formulaire de changement de mot de passe. Verifie que les 2
|
||||
nouveaux mots de passe renseignés sont identiques et respectent
|
||||
une norme"""
|
||||
|
||||
selfpasswd = forms.CharField(
|
||||
label=_("Current password"), max_length=255, widget=forms.PasswordInput
|
||||
)
|
||||
passwd1 = forms.CharField(
|
||||
label=_("New password"),
|
||||
max_length=255,
|
||||
widget=forms.PasswordInput,
|
||||
help_text=password_validators_help_text_html()
|
||||
)
|
||||
passwd2 = forms.CharField(
|
||||
label=_("New password confirmation"),
|
||||
max_length=255,
|
||||
widget=forms.PasswordInput,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = []
|
||||
|
||||
def clean_passwd2(self):
|
||||
"""Verifie que passwd1 et 2 sont identiques"""
|
||||
# Check that the two password entries match
|
||||
password1 = self.cleaned_data.get("passwd1")
|
||||
password2 = self.cleaned_data.get("passwd2")
|
||||
if password1 and password2 and password1 != password2:
|
||||
raise forms.ValidationError(_("The new passwords don't match."))
|
||||
validate_password(password1, user=self.instance)
|
||||
return password2
|
||||
|
||||
def clean_selfpasswd(self):
|
||||
"""Verifie si il y a lieu que le mdp self est correct"""
|
||||
if not self.instance.check_password(self.cleaned_data.get("selfpasswd")):
|
||||
raise forms.ValidationError(_("The current password is incorrect."))
|
||||
return
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Changement du mot de passe"""
|
||||
user = super(PassForm, self).save(commit=False)
|
||||
user.set_password(self.cleaned_data.get("passwd1"))
|
||||
user.state = User.STATE_NOT_YET_ACTIVE
|
||||
user.set_active()
|
||||
user.save()
|
||||
#### Django Admin Custom Views
|
||||
|
||||
|
||||
class UserAdminForm(FormRevMixin, forms.ModelForm):
|
||||
"""A form for creating new and editing users. Includes all the required
|
||||
fields, plus a repeated password.
|
||||
|
||||
Formulaire pour la création d'un user. N'est utilisé que pour
|
||||
l'admin, lors de la creation d'un user par admin. Inclu tous les
|
||||
champs obligatoires"""
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
password1 = forms.CharField(
|
||||
label=_("Password"),
|
||||
|
@ -152,8 +112,14 @@ class UserAdminForm(FormRevMixin, forms.ModelForm):
|
|||
fields = ("pseudo", "surname", "name", "email", "is_superuser")
|
||||
|
||||
def clean_password2(self):
|
||||
"""Verifie que password1 et 2 sont identiques"""
|
||||
# Check that the two password entries match
|
||||
"""Clean password 2, check if passwd1 and 2 values match.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form UserCreationForm instance
|
||||
|
||||
Returns:
|
||||
password2 (string): The password2 value if all tests returned True
|
||||
"""
|
||||
password1 = self.cleaned_data.get("password1")
|
||||
password2 = self.cleaned_data.get("password2")
|
||||
if password1 and password2:
|
||||
|
@ -163,6 +129,13 @@ class UserAdminForm(FormRevMixin, forms.ModelForm):
|
|||
return password2
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Save function. Call standard "set_password" django function,
|
||||
from provided value for new password, for making hash.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form UserCreationForm instance
|
||||
commit : If False, don't make the real save in database
|
||||
"""
|
||||
# Save the provided password in hashed format
|
||||
user = super(UserAdminForm, self).save(commit=False)
|
||||
if self.cleaned_data["password1"]:
|
||||
|
@ -172,11 +145,12 @@ class UserAdminForm(FormRevMixin, forms.ModelForm):
|
|||
|
||||
|
||||
class ServiceUserAdminForm(FormRevMixin, forms.ModelForm):
|
||||
"""A form for creating new users. Includes all the required
|
||||
fields, plus a repeated password.
|
||||
"""A form for creating new service users. Includes all the required
|
||||
fields, plus a repeated password. For Admin view purpose only.
|
||||
|
||||
Formulaire pour la creation de nouveaux serviceusers.
|
||||
Requiert seulement un mot de passe; et un pseudo"""
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
password1 = forms.CharField(
|
||||
label=_("Password"),
|
||||
|
@ -198,8 +172,14 @@ class ServiceUserAdminForm(FormRevMixin, forms.ModelForm):
|
|||
fields = ("pseudo",)
|
||||
|
||||
def clean_password2(self):
|
||||
"""Verifie que password1 et 2 sont identiques"""
|
||||
# Check that the two password entries match
|
||||
"""Clean password 2, check if passwd1 and 2 values match.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form UserCreationForm instance
|
||||
|
||||
Returns:
|
||||
password2 (string): The password2 value if all tests returned True
|
||||
"""
|
||||
password1 = self.cleaned_data.get("password1")
|
||||
password2 = self.cleaned_data.get("password2")
|
||||
if password1 and password2 and password1 != password2:
|
||||
|
@ -207,25 +187,111 @@ class ServiceUserAdminForm(FormRevMixin, forms.ModelForm):
|
|||
return password2
|
||||
|
||||
def save(self, commit=True):
|
||||
# Save the provided password in hashed format
|
||||
"""Save function. Call standard "set_password" django function,
|
||||
from provided value for new password, for making hash.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form ServiceUserAdminForm instance
|
||||
commit : If False, don't make the real save in database
|
||||
"""
|
||||
user = super(ServiceUserAdminForm, self).save(commit=False)
|
||||
user.set_password(self.cleaned_data["password1"])
|
||||
user.save()
|
||||
return user
|
||||
|
||||
|
||||
### Classic Django View
|
||||
|
||||
|
||||
class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
|
||||
"""Django form for changing password, check if 2 passwords are the same,
|
||||
and validate password for django base password validators provided in
|
||||
settings_local.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
|
||||
"""
|
||||
selfpasswd = forms.CharField(
|
||||
label=_("Current password"), max_length=255, widget=forms.PasswordInput
|
||||
)
|
||||
passwd1 = forms.CharField(
|
||||
label=_("New password"),
|
||||
max_length=255,
|
||||
widget=forms.PasswordInput,
|
||||
help_text=password_validators_help_text_html()
|
||||
)
|
||||
passwd2 = forms.CharField(
|
||||
label=_("New password confirmation"),
|
||||
max_length=255,
|
||||
widget=forms.PasswordInput,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = []
|
||||
|
||||
def clean_passwd2(self):
|
||||
"""Clean password 2, check if passwd1 and 2 values match, and
|
||||
apply django validator with validate_password function.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form PassForm instance
|
||||
|
||||
Returns:
|
||||
password2 (string): The password2 value if all tests returned True
|
||||
"""
|
||||
password1 = self.cleaned_data.get("passwd1")
|
||||
password2 = self.cleaned_data.get("passwd2")
|
||||
if password1 and password2 and password1 != password2:
|
||||
raise forms.ValidationError(_("The new passwords don't match."))
|
||||
validate_password(password1, user=self.instance)
|
||||
return password2
|
||||
|
||||
def clean_selfpasswd(self):
|
||||
"""Clean selfpassword, check if provided original user password match
|
||||
with the stored value.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form PassForm instance
|
||||
"""
|
||||
if not self.instance.check_password(self.cleaned_data.get("selfpasswd")):
|
||||
raise forms.ValidationError(_("The current password is incorrect."))
|
||||
return
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Save function. Call standard "set_password" django function,
|
||||
and call set_active for set user in active state if needed.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form PassForm instance
|
||||
commit : If False, don't make the real save in database
|
||||
"""
|
||||
user = super(PassForm, self).save(commit=False)
|
||||
user.set_password(self.cleaned_data.get("passwd1"))
|
||||
user.state = User.STATE_NOT_YET_ACTIVE
|
||||
user.set_active()
|
||||
user.save()
|
||||
|
||||
|
||||
class ResetPasswordForm(forms.Form):
|
||||
"""Formulaire de demande de reinitialisation de mot de passe,
|
||||
mdp oublié"""
|
||||
"""A form for asking to reset password.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
pseudo = forms.CharField(label=_("Username"), max_length=255)
|
||||
email = forms.EmailField(max_length=255)
|
||||
|
||||
|
||||
class MassArchiveForm(forms.Form):
|
||||
"""Formulaire d'archivage des users inactif. Prend en argument
|
||||
du formulaire la date de depart avant laquelle archiver les
|
||||
users"""
|
||||
"""A form for archiving a lot de users. Get a start date
|
||||
for start archiving.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
date = forms.DateTimeField(help_text="%d/%m/%y")
|
||||
full_archive = forms.BooleanField(
|
||||
|
@ -251,9 +317,12 @@ class MassArchiveForm(forms.Form):
|
|||
|
||||
|
||||
class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
|
||||
pour l'edition de self par self ou un cableur. On formate les champs
|
||||
avec des label plus jolis"""
|
||||
"""Adherent Edition Form, base form used for editing user by himself
|
||||
or another user. Labels are provided for help purposes.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
|
@ -288,24 +357,42 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
)
|
||||
|
||||
def clean_telephone(self):
|
||||
"""Verifie que le tel est présent si 'option est validée
|
||||
dans preferences"""
|
||||
"""Clean telephone, check if telephone is made mandatory, and
|
||||
raise error if not provided
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form AdherentForm instance
|
||||
|
||||
Returns:
|
||||
telephone (string): The telephone string if clean is True
|
||||
"""
|
||||
telephone = self.cleaned_data["telephone"]
|
||||
if not telephone and OptionalUser.get_cached_value("is_tel_mandatory"):
|
||||
raise forms.ValidationError(_("A valid telephone number is required."))
|
||||
return telephone
|
||||
|
||||
def clean_force(self):
|
||||
"""On supprime l'ancien user de la chambre si et seulement si la
|
||||
case est cochée"""
|
||||
"""Clean force, remove previous user from room if needed.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form AdherentForm instance
|
||||
"""
|
||||
room = self.cleaned_data.get("room")
|
||||
if self.cleaned_data.get("force", False) and room:
|
||||
remove_user_room(room)
|
||||
return
|
||||
|
||||
def clean_room(self):
|
||||
"""On supprime l'ancien user de la chambre si l'option est activée,
|
||||
et que l'ancien user a une connexion désactivée"""
|
||||
"""Clean room, based on room policy provided by preferences.
|
||||
If needed, call remove_user_room to make the room empty before
|
||||
saving self.instance into that room.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form AdherentForm instance
|
||||
|
||||
Returns:
|
||||
room (string): The room instance
|
||||
"""
|
||||
# Handle case where regular users can force move
|
||||
room = self.cleaned_data.get("room")
|
||||
room_policy = OptionalUser.get_cached_value("self_room_policy")
|
||||
|
@ -320,10 +407,13 @@ class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class AdherentCreationForm(AdherentForm):
|
||||
"""Formulaire de création d'un user.
|
||||
AdherentForm auquel on ajoute une checkbox afin d'éviter les
|
||||
doublons d'utilisateurs et, optionnellement,
|
||||
un champ mot de passe"""
|
||||
"""AdherentCreationForm. Inherit from AdherentForm, base form used for creating
|
||||
user by himself or another user. Labels are provided for help purposes.
|
||||
Add some instructions, and validation for initial creation.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
# Champ pour choisir si un lien est envoyé par mail pour le mot de passe
|
||||
init_password_by_mail_info = _(
|
||||
"If this options is set, you will receive a link to set"
|
||||
|
@ -407,7 +497,15 @@ class AdherentCreationForm(AdherentForm):
|
|||
self.fields.pop("password2")
|
||||
|
||||
def clean_password2(self):
|
||||
"""Verifie que password1 et 2 sont identiques (si nécessaire)"""
|
||||
"""Clean password 2, check if passwd1 and 2 values match, and
|
||||
apply django validator with validate_password function.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form AdherentCreationForm instance
|
||||
|
||||
Returns:
|
||||
password2 (string): The password2 value if all tests returned True
|
||||
"""
|
||||
send_email = self.cleaned_data.get("init_password_by_mail")
|
||||
if send_email:
|
||||
return None
|
||||
|
@ -421,9 +519,14 @@ class AdherentCreationForm(AdherentForm):
|
|||
return password2
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Set the user's password, if entered
|
||||
Returns the user and a bool indicating whether
|
||||
an email to init the password should be sent"""
|
||||
"""Save function. If password has been set during creation,
|
||||
call standard "set_password" django function from provided value
|
||||
for new password, for making hash.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form AdherentCreationForm instance
|
||||
commit : If False, don't make the real save in database
|
||||
"""
|
||||
# Save the provided password in hashed format
|
||||
user = super(AdherentForm, self).save(commit=False)
|
||||
|
||||
|
@ -437,8 +540,13 @@ class AdherentCreationForm(AdherentForm):
|
|||
|
||||
|
||||
class AdherentEditForm(AdherentForm):
|
||||
"""Formulaire d'édition d'un user.
|
||||
AdherentForm incluant la modification des champs gpg et shell"""
|
||||
"""AdherentEditForm. Inherit from AdherentForm, base form used for editing
|
||||
user by himself or another user. Labels are provided for help purposes.
|
||||
Add some instructions, and validation, fields depends on editing user rights.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AdherentEditForm, self).__init__(*args, **kwargs)
|
||||
|
@ -469,9 +577,13 @@ class AdherentEditForm(AdherentForm):
|
|||
|
||||
|
||||
class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
|
||||
pour l'edition de self par self ou un cableur. On formate les champs
|
||||
avec des label plus jolis"""
|
||||
"""ClubForm. For editing club by himself or another user. Labels are provided for
|
||||
help purposes. Add some instructions, and validation, fields depends
|
||||
on editing user rights.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
|
@ -503,8 +615,15 @@ class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
]
|
||||
|
||||
def clean_telephone(self):
|
||||
"""Verifie que le tel est présent si 'option est validée
|
||||
dans preferences"""
|
||||
"""Clean telephone, check if telephone is made mandatory, and
|
||||
raise error if not provided
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form ClubForm instance
|
||||
|
||||
Returns:
|
||||
telephone (string): The telephone string if clean is True
|
||||
"""
|
||||
telephone = self.cleaned_data["telephone"]
|
||||
if not telephone and OptionalUser.get_cached_value("is_tel_mandatory"):
|
||||
raise forms.ValidationError(_("A valid telephone number is required."))
|
||||
|
@ -512,8 +631,12 @@ class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class ClubAdminandMembersForm(FormRevMixin, ModelForm):
|
||||
"""Permet d'éditer la liste des membres et des administrateurs
|
||||
d'un club"""
|
||||
"""ClubAdminandMembersForm. Only For editing administrators of a club by himself
|
||||
or another user.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Club
|
||||
|
@ -525,8 +648,11 @@ class ClubAdminandMembersForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class PasswordForm(FormRevMixin, ModelForm):
|
||||
""" Formulaire de changement brut de mot de passe.
|
||||
Ne pas utiliser sans traitement"""
|
||||
"""PasswordForm. Do not use directly in views without extra validations.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
|
@ -538,8 +664,12 @@ class PasswordForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class ServiceUserForm(FormRevMixin, ModelForm):
|
||||
"""Service user creation
|
||||
force initial password set"""
|
||||
"""ServiceUserForm, used for creating a service user, require
|
||||
a password and set it.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
password = forms.CharField(
|
||||
label=_("New password"),
|
||||
|
@ -558,7 +688,14 @@ class ServiceUserForm(FormRevMixin, ModelForm):
|
|||
super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Password change"""
|
||||
"""Save function. If password has been changed and provided,
|
||||
call standard "set_password" django function from provided value
|
||||
for new password, for making hash.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form ServiceUserForm instance
|
||||
commit : If False, don't make the real save in database
|
||||
"""
|
||||
user = super(ServiceUserForm, self).save(commit=False)
|
||||
if self.cleaned_data["password"]:
|
||||
user.set_password(self.cleaned_data.get("password"))
|
||||
|
@ -566,8 +703,12 @@ class ServiceUserForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EditServiceUserForm(ServiceUserForm):
|
||||
"""Formulaire d'edition de base d'un service user. Ne permet
|
||||
d'editer que son group d'acl et son commentaire"""
|
||||
"""EditServiceUserForm, used for editing a service user, can
|
||||
edit password, access_group and comment.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
password = forms.CharField(
|
||||
label=_("New password"),
|
||||
|
@ -582,7 +723,12 @@ class EditServiceUserForm(ServiceUserForm):
|
|||
|
||||
|
||||
class StateForm(FormRevMixin, ModelForm):
|
||||
"""Change state of an user, and if its main email is verified or not"""
|
||||
"""StateForm, Change state of an user, and if
|
||||
its main email is verified or not
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
|
@ -596,7 +742,11 @@ class StateForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class GroupForm(FieldPermissionFormMixin, FormRevMixin, ModelForm):
|
||||
""" Gestion des groupes d'un user"""
|
||||
"""GroupForm, form used for editing user groups.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
groups = forms.ModelMultipleChoiceField(
|
||||
Group.objects.all(), widget=forms.CheckboxSelectMultiple, required=False
|
||||
|
@ -614,7 +764,11 @@ class GroupForm(FieldPermissionFormMixin, FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class SchoolForm(FormRevMixin, ModelForm):
|
||||
"""Edition, creation d'un école"""
|
||||
"""SchoolForm, form used for creating or editing school.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = School
|
||||
|
@ -627,7 +781,11 @@ class SchoolForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class ShellForm(FormRevMixin, ModelForm):
|
||||
"""Edition, creation d'un école"""
|
||||
"""ShellForm, form used for creating or editing shell.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = ListShell
|
||||
|
@ -640,8 +798,13 @@ class ShellForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class ListRightForm(FormRevMixin, ModelForm):
|
||||
"""Edition, d'un groupe , équivalent à un droit
|
||||
Ne permet pas d'editer le gid, car il sert de primary key"""
|
||||
"""ListRightForm, form used for editing a listright,
|
||||
related with django group object. Gid, primary key, can't
|
||||
be edited.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
permissions = forms.ModelMultipleChoiceField(
|
||||
Permission.objects.all().select_related("content_type"),
|
||||
|
@ -660,7 +823,12 @@ class ListRightForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class NewListRightForm(ListRightForm):
|
||||
"""Ajout d'un groupe/list de droit """
|
||||
"""ListRightForm, form used for creating a listright,
|
||||
related with django group object.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
class Meta(ListRightForm.Meta):
|
||||
fields = ("name", "unix_name", "gid", "critical", "permissions", "details")
|
||||
|
@ -673,7 +841,12 @@ class NewListRightForm(ListRightForm):
|
|||
|
||||
|
||||
class DelListRightForm(Form):
|
||||
"""Suppression d'un ou plusieurs groupes"""
|
||||
"""DelListRightForm, form for deleting one or several ListRight
|
||||
instances.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
listrights = forms.ModelMultipleChoiceField(
|
||||
queryset=ListRight.objects.none(),
|
||||
|
@ -691,7 +864,12 @@ class DelListRightForm(Form):
|
|||
|
||||
|
||||
class DelSchoolForm(Form):
|
||||
"""Suppression d'une ou plusieurs écoles"""
|
||||
"""DelSchoolForm, form for deleting one or several School
|
||||
instances.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
schools = forms.ModelMultipleChoiceField(
|
||||
queryset=School.objects.none(),
|
||||
|
@ -709,7 +887,11 @@ class DelSchoolForm(Form):
|
|||
|
||||
|
||||
class BanForm(FormRevMixin, ModelForm):
|
||||
"""Creation, edition d'un objet bannissement"""
|
||||
"""BanForm, form used for creating or editing a ban instance.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
|
@ -724,7 +906,11 @@ class BanForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class WhitelistForm(FormRevMixin, ModelForm):
|
||||
"""Creation, edition d'un objet whitelist"""
|
||||
"""WhitelistForm, form used for creating or editing a whitelist instance.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
|
@ -739,7 +925,12 @@ class WhitelistForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EMailAddressForm(FormRevMixin, ModelForm):
|
||||
"""Create and edit a local email address"""
|
||||
"""EMailAddressForm, form used for creating or editing a local
|
||||
email for a user.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
|
@ -756,7 +947,11 @@ class EMailAddressForm(FormRevMixin, ModelForm):
|
|||
|
||||
|
||||
class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
"""Edit email-related settings"""
|
||||
"""EMailSettingsForm, form used for editing email settings for a user.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
|
@ -775,6 +970,12 @@ class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
|||
|
||||
|
||||
class InitialRegisterForm(forms.Form):
|
||||
"""InitialRegisterForm, form used for auto-register of room and mac-address
|
||||
with captive-portal.
|
||||
|
||||
Parameters:
|
||||
DjangoForm : Inherit from basic django form
|
||||
"""
|
||||
register_room = forms.BooleanField(required=False)
|
||||
register_machine = forms.BooleanField(required=False)
|
||||
|
||||
|
@ -818,6 +1019,13 @@ class InitialRegisterForm(forms.Form):
|
|||
self.fields.pop("register_machine")
|
||||
|
||||
def clean_register_room(self):
|
||||
"""Clean room, call remove_user_room to make the room empty before
|
||||
saving self.instance into that room.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form InitialRegisterForm instance
|
||||
|
||||
"""
|
||||
if self.cleaned_data["register_room"]:
|
||||
if self.user.is_class_adherent:
|
||||
remove_user_room(self.new_room)
|
||||
|
@ -830,6 +1038,12 @@ class InitialRegisterForm(forms.Form):
|
|||
user.save()
|
||||
|
||||
def clean_register_machine(self):
|
||||
"""Clean register room, autoregister machine from user request mac_address.
|
||||
|
||||
Parameters:
|
||||
self : Apply on a django Form InitialRegisterForm instance
|
||||
|
||||
"""
|
||||
if self.cleaned_data["register_machine"]:
|
||||
if self.mac_address and self.nas_type:
|
||||
self.user.autoregister_machine(self.mac_address, self.nas_type)
|
||||
|
|
1723
users/models.py
1723
users/models.py
File diff suppressed because it is too large
Load diff
|
@ -23,7 +23,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""
|
||||
Definition des urls, pointant vers les views
|
||||
The defined URLs for the Users app
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
|
673
users/views.py
673
users/views.py
|
@ -27,13 +27,30 @@
|
|||
# Lara Kermarec, Gabriel Détraz, Lemesle Augustin
|
||||
# Gplv2
|
||||
"""
|
||||
Module des views.
|
||||
Django users views module.
|
||||
|
||||
On définit les vues pour l'ajout, l'edition des users : infos personnelles,
|
||||
mot de passe, etc
|
||||
Here are defined all functions of views, for the users re2o application. This views
|
||||
allow both edition, creation, deletion and diplay of users objects.
|
||||
Here are view that allow the addition/deletion/edition of:
|
||||
* Users (Club/Adherent) and derived settings like EmailSettings of users
|
||||
* School
|
||||
* Bans
|
||||
* Whitelist
|
||||
* Shell
|
||||
* ServiceUser
|
||||
|
||||
Also add extra views for :
|
||||
* Ask for reset password by email
|
||||
* Ask for new email for email confirmation
|
||||
* Register room and interface on user account with switch web redirection.
|
||||
|
||||
All the view must be as simple as possible, with returning the correct form to user during
|
||||
get, and during post, performing change in database with simple ".save()" function.
|
||||
|
||||
The aim is to put all "intelligent" functions in both forms and models functions. In fact, this
|
||||
will allow to user other frontend (like REST api) to perform editions, creations, etc on database,
|
||||
without code duplication.
|
||||
|
||||
Permet aussi l'ajout, edition et suppression des droits, des bannissements,
|
||||
des whitelist, des services users et des écoles
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
@ -117,8 +134,17 @@ import os
|
|||
|
||||
@can_create(Adherent)
|
||||
def new_user(request):
|
||||
""" Vue de création d'un nouvel utilisateur,
|
||||
envoie un mail pour le mot de passe"""
|
||||
"""View for new Adherent/User form creation.
|
||||
Then, send an email to the new user, and also if needed to
|
||||
set its password.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
user = AdherentCreationForm(request.POST or None, request.FILES or None, user=request.user)
|
||||
user.request = request
|
||||
|
||||
|
@ -167,8 +193,17 @@ def new_user(request):
|
|||
@login_required
|
||||
@can_create(Club)
|
||||
def new_club(request):
|
||||
""" Vue de création d'un nouveau club,
|
||||
envoie un mail pour le mot de passe"""
|
||||
"""View for new Club/User form creation.
|
||||
Then, send an email to the new user, and also if needed to
|
||||
set its password.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
club = ClubForm(request.POST or None, request.FILES or None, user=request.user)
|
||||
club.request = request
|
||||
|
||||
|
@ -192,8 +227,16 @@ def new_club(request):
|
|||
@login_required
|
||||
@can_edit(Club)
|
||||
def edit_club_admin_members(request, club_instance, **_kwargs):
|
||||
"""Vue d'edition de la liste des users administrateurs et
|
||||
membres d'un club"""
|
||||
"""View for editing clubs and administrators.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
club_instance: Club instance to edit
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
club = ClubAdminandMembersForm(request.POST or None, request.FILES or None, instance=club_instance)
|
||||
if club.is_valid():
|
||||
if club.changed_data:
|
||||
|
@ -212,9 +255,17 @@ def edit_club_admin_members(request, club_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(User)
|
||||
def edit_info(request, user, userid):
|
||||
""" Edite un utilisateur à partir de son id,
|
||||
si l'id est différent de request.user, vérifie la
|
||||
possession du droit cableur """
|
||||
"""View for editing base user informations.
|
||||
Perform an acl check on user instance.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
if user.is_class_adherent:
|
||||
user_form = AdherentEditForm(
|
||||
request.POST or None, request.FILES or None, instance=user.adherent, user=request.user
|
||||
|
@ -246,7 +297,18 @@ def edit_info(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(User, "state")
|
||||
def state(request, user, userid):
|
||||
""" Change the state (active/unactive/archived) of a user"""
|
||||
"""View for editing state of user.
|
||||
Perform an acl check on user instance, and check if editing user
|
||||
has state edition permission.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
state_form = StateForm(request.POST or None, instance=user)
|
||||
if state_form.is_valid():
|
||||
if state_form.changed_data:
|
||||
|
@ -265,7 +327,18 @@ def state(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(User, "groups")
|
||||
def groups(request, user, userid):
|
||||
""" View to edit the groups of a user """
|
||||
"""View for editing groups of user.
|
||||
Perform an acl check on user instance, and check if editing user
|
||||
has groups edition permission.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
group_form = GroupForm(request.POST or None, instance=user, user=request.user)
|
||||
if group_form.is_valid():
|
||||
if group_form.changed_data:
|
||||
|
@ -280,9 +353,20 @@ def groups(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(User, "password")
|
||||
def password(request, user, userid):
|
||||
""" Reinitialisation d'un mot de passe à partir de l'userid,
|
||||
pour self par défaut, pour tous sans droit si droit cableur,
|
||||
pour tous si droit bureau """
|
||||
"""View for editing password of user.
|
||||
Perform an acl check on user instance, and check if editing user
|
||||
has password edition permission.
|
||||
If User instance is in critical groups, the edition requires extra
|
||||
permission.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit password
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
u_form = PassForm(request.POST or None, instance=user, user=request.user)
|
||||
if u_form.is_valid():
|
||||
if u_form.changed_data:
|
||||
|
@ -299,7 +383,20 @@ def password(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(User, "groups")
|
||||
def del_group(request, user, listrightid, **_kwargs):
|
||||
""" View used to delete a group """
|
||||
"""View for editing groups of user.
|
||||
Perform an acl check on user instance, and check if editing user
|
||||
has groups edition permission.
|
||||
If User instance is in critical groups, the edition requires extra
|
||||
permission.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit groups
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
user.groups.remove(ListRight.objects.get(id=listrightid))
|
||||
user.save()
|
||||
messages.success(request, _("%s was removed from the group.") % user)
|
||||
|
@ -309,7 +406,18 @@ def del_group(request, user, listrightid, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(User, "is_superuser")
|
||||
def del_superuser(request, user, **_kwargs):
|
||||
"""Remove the superuser right of an user."""
|
||||
"""View for editing superuser attribute of user.
|
||||
Perform an acl check on user instance, and check if editing user
|
||||
has edition of superuser flag on target user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit superuser flag.
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
user.is_superuser = False
|
||||
user.save()
|
||||
messages.success(request, _("%s is no longer superuser.") % user)
|
||||
|
@ -319,7 +427,18 @@ def del_superuser(request, user, **_kwargs):
|
|||
@login_required
|
||||
@can_create(ServiceUser)
|
||||
def new_serviceuser(request):
|
||||
""" Vue de création d'un nouvel utilisateur service"""
|
||||
"""View for creation of new serviceuser, for external services on
|
||||
ldap tree for auth purpose (dokuwiki, owncloud, etc).
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of create new serviceuser.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django ServiceUser form.
|
||||
|
||||
"""
|
||||
user = ServiceUserForm(request.POST or None)
|
||||
if user.is_valid():
|
||||
user.save()
|
||||
|
@ -333,7 +452,19 @@ def new_serviceuser(request):
|
|||
@login_required
|
||||
@can_edit(ServiceUser)
|
||||
def edit_serviceuser(request, serviceuser, **_kwargs):
|
||||
""" Edit a ServiceUser """
|
||||
"""View for edition of serviceuser, for external services on
|
||||
ldap tree for auth purpose (dokuwiki, owncloud, etc).
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of edit target serviceuser.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
serviceuser: ServiceUser instance to edit attributes.
|
||||
|
||||
Returns:
|
||||
Django ServiceUser form.
|
||||
|
||||
"""
|
||||
serviceuser = EditServiceUserForm(request.POST or None, instance=serviceuser)
|
||||
if serviceuser.is_valid():
|
||||
if serviceuser.changed_data:
|
||||
|
@ -348,7 +479,19 @@ def edit_serviceuser(request, serviceuser, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(ServiceUser)
|
||||
def del_serviceuser(request, serviceuser, **_kwargs):
|
||||
"""Suppression d'un ou plusieurs serviceusers"""
|
||||
"""View for removing serviceuser, for external services on
|
||||
ldap tree for auth purpose (dokuwiki, owncloud, etc).
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting target serviceuser.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
serviceuser: ServiceUser instance to delete.
|
||||
|
||||
Returns:
|
||||
Django ServiceUser form.
|
||||
|
||||
"""
|
||||
if request.method == "POST":
|
||||
serviceuser.delete()
|
||||
messages.success(request, _("The service user was deleted."))
|
||||
|
@ -364,9 +507,19 @@ def del_serviceuser(request, serviceuser, **_kwargs):
|
|||
@can_create(Ban)
|
||||
@can_edit(User)
|
||||
def add_ban(request, user, userid):
|
||||
""" Ajouter un banissement, nécessite au moins le droit bofh
|
||||
(a fortiori bureau)
|
||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
|
||||
"""View for adding a ban object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of adding a ban on target user, add_ban.
|
||||
Syntaxe: DD/MM/AAAA, the ban takes an immediate effect.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to add a ban.
|
||||
|
||||
Returns:
|
||||
Django Ban form.
|
||||
|
||||
"""
|
||||
ban_instance = Ban(user=user)
|
||||
ban = BanForm(request.POST or None, instance=ban_instance)
|
||||
ban.request = request
|
||||
|
@ -383,9 +536,19 @@ def add_ban(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(Ban)
|
||||
def edit_ban(request, ban_instance, **_kwargs):
|
||||
""" Editer un bannissement, nécessite au moins le droit bofh
|
||||
(a fortiori bureau)
|
||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
|
||||
"""View for editing a ban object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing a ban on target user, edit_ban.
|
||||
Syntaxe: DD/MM/AAAA, the ban takes an immediate effect.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
ban: Ban instance to edit.
|
||||
|
||||
Returns:
|
||||
Django Ban form.
|
||||
|
||||
"""
|
||||
ban = BanForm(request.POST or None, instance=ban_instance)
|
||||
ban.request = request
|
||||
|
||||
|
@ -400,7 +563,18 @@ def edit_ban(request, ban_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Ban)
|
||||
def del_ban(request, ban, **_kwargs):
|
||||
""" Supprime un banissement"""
|
||||
"""View for removing a ban object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting a ban on target user, del_ban.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
ban: Ban instance to delete.
|
||||
|
||||
Returns:
|
||||
Django Ban form.
|
||||
|
||||
"""
|
||||
if request.method == "POST":
|
||||
ban.delete()
|
||||
messages.success(request, _("The ban was deleted."))
|
||||
|
@ -412,10 +586,19 @@ def del_ban(request, ban, **_kwargs):
|
|||
@can_create(Whitelist)
|
||||
@can_edit(User)
|
||||
def add_whitelist(request, user, userid):
|
||||
""" Accorder un accès gracieux, temporaire ou permanent.
|
||||
Need droit cableur
|
||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement,
|
||||
raison obligatoire"""
|
||||
"""View for adding a whitelist object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of adding a wheitelist on target user, add_whitelist.
|
||||
Syntaxe: DD/MM/AAAA, the whitelist takes an immediate effect.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to add a whitelist.
|
||||
|
||||
Returns:
|
||||
Django Whitelist form.
|
||||
|
||||
"""
|
||||
whitelist_instance = Whitelist(user=user)
|
||||
whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance)
|
||||
if whitelist.is_valid():
|
||||
|
@ -434,10 +617,19 @@ def add_whitelist(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(Whitelist)
|
||||
def edit_whitelist(request, whitelist_instance, **_kwargs):
|
||||
""" Editer un accès gracieux, temporaire ou permanent.
|
||||
Need droit cableur
|
||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement,
|
||||
raison obligatoire"""
|
||||
"""View for editing a whitelist object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing a whitelist on target user, edit_whitelist.
|
||||
Syntaxe: DD/MM/AAAA, the whitelist takes an immediate effect.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
whitelist: whitelist instance to edit.
|
||||
|
||||
Returns:
|
||||
Django Whitelist form.
|
||||
|
||||
"""
|
||||
whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance)
|
||||
if whitelist.is_valid():
|
||||
if whitelist.changed_data:
|
||||
|
@ -452,7 +644,18 @@ def edit_whitelist(request, whitelist_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(Whitelist)
|
||||
def del_whitelist(request, whitelist, **_kwargs):
|
||||
""" Supprime un acces gracieux"""
|
||||
"""View for removing a whitelist object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting a whitelist on target user, del_whitelist.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
whitelist: Whitelist instance to delete.
|
||||
|
||||
Returns:
|
||||
Django Whitelist form.
|
||||
|
||||
"""
|
||||
if request.method == "POST":
|
||||
whitelist.delete()
|
||||
messages.success(request, _("The whitelist was deleted."))
|
||||
|
@ -468,7 +671,18 @@ def del_whitelist(request, whitelist, **_kwargs):
|
|||
@can_create(EMailAddress)
|
||||
@can_edit(User)
|
||||
def add_emailaddress(request, user, userid):
|
||||
""" Create a new local email account"""
|
||||
"""View for adding an emailaddress object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of adding an emailaddress on target user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to add an emailaddress.
|
||||
|
||||
Returns:
|
||||
Django EmailAddress form.
|
||||
|
||||
"""
|
||||
emailaddress_instance = EMailAddress(user=user)
|
||||
emailaddress = EMailAddressForm(
|
||||
request.POST or None, instance=emailaddress_instance
|
||||
|
@ -487,7 +701,18 @@ def add_emailaddress(request, user, userid):
|
|||
@login_required
|
||||
@can_edit(EMailAddress)
|
||||
def edit_emailaddress(request, emailaddress_instance, **_kwargs):
|
||||
""" Edit a local email account"""
|
||||
"""View for edit an emailaddress object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing an emailaddress on target user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
emailaddress: Emailaddress to edit.
|
||||
|
||||
Returns:
|
||||
Django EmailAddress form.
|
||||
|
||||
"""
|
||||
emailaddress = EMailAddressForm(
|
||||
request.POST or None, instance=emailaddress_instance
|
||||
)
|
||||
|
@ -510,7 +735,18 @@ def edit_emailaddress(request, emailaddress_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(EMailAddress)
|
||||
def del_emailaddress(request, emailaddress, **_kwargs):
|
||||
"""Delete a local email account"""
|
||||
"""View for deleting an emailaddress object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting an emailaddress on target user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
emailaddress: Emailaddress to delete.
|
||||
|
||||
Returns:
|
||||
Django EmailAddress form.
|
||||
|
||||
"""
|
||||
if request.method == "POST":
|
||||
emailaddress.delete()
|
||||
messages.success(request, _("The local email account was deleted."))
|
||||
|
@ -527,7 +763,18 @@ def del_emailaddress(request, emailaddress, **_kwargs):
|
|||
@login_required
|
||||
@can_edit(User)
|
||||
def edit_email_settings(request, user_instance, **_kwargs):
|
||||
"""Edit the email settings of a user"""
|
||||
"""View for editing User's emailaddress settings for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing email settings on target user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
user: User instance to edit email settings.
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
email_settings = EmailSettingsForm(
|
||||
request.POST or None, instance=user_instance, user=request.user
|
||||
)
|
||||
|
@ -559,8 +806,17 @@ def edit_email_settings(request, user_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_create(School)
|
||||
def add_school(request):
|
||||
""" Ajouter un établissement d'enseignement à la base de donnée,
|
||||
need cableur"""
|
||||
"""View for adding a new school object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of adding a new school, add_school.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django School form.
|
||||
|
||||
"""
|
||||
school = SchoolForm(request.POST or None)
|
||||
if school.is_valid():
|
||||
school.save()
|
||||
|
@ -574,8 +830,18 @@ def add_school(request):
|
|||
@login_required
|
||||
@can_edit(School)
|
||||
def edit_school(request, school_instance, **_kwargs):
|
||||
""" Editer un établissement d'enseignement à partir du schoolid dans
|
||||
la base de donnée, need cableur"""
|
||||
"""View for editing a school instance object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing a school, edit_school.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
school_instance: school instance to edit.
|
||||
|
||||
Returns:
|
||||
Django School form.
|
||||
|
||||
"""
|
||||
school = SchoolForm(request.POST or None, instance=school_instance)
|
||||
if school.is_valid():
|
||||
if school.changed_data:
|
||||
|
@ -590,10 +856,20 @@ def edit_school(request, school_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(School)
|
||||
def del_school(request, instances):
|
||||
""" Supprimer un établissement d'enseignement à la base de donnée,
|
||||
need cableur
|
||||
Objet protégé, possible seulement si aucun user n'est affecté à
|
||||
l'établissement """
|
||||
"""View for deleting a school instance object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting a school, del_school.
|
||||
A school can be deleted only if it is not assigned to a user (mode
|
||||
protect).
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
school_instance: school instance to delete.
|
||||
|
||||
Returns:
|
||||
Django School form.
|
||||
|
||||
"""
|
||||
school = DelSchoolForm(request.POST or None, instances=instances)
|
||||
if school.is_valid():
|
||||
school_dels = school.cleaned_data["schools"]
|
||||
|
@ -619,7 +895,17 @@ def del_school(request, instances):
|
|||
@login_required
|
||||
@can_create(ListShell)
|
||||
def add_shell(request):
|
||||
""" Ajouter un shell à la base de donnée"""
|
||||
"""View for adding a new linux shell object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of adding a new shell, add_school.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django Shell form.
|
||||
|
||||
"""
|
||||
shell = ShellForm(request.POST or None)
|
||||
if shell.is_valid():
|
||||
shell.save()
|
||||
|
@ -633,7 +919,18 @@ def add_shell(request):
|
|||
@login_required
|
||||
@can_edit(ListShell)
|
||||
def edit_shell(request, shell_instance, **_kwargs):
|
||||
""" Editer un shell à partir du listshellid"""
|
||||
"""View for editing a shell instance object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing a shell, edit_shell.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
shell_instance: shell instance to edit.
|
||||
|
||||
Returns:
|
||||
Django Shell form.
|
||||
|
||||
"""
|
||||
shell = ShellForm(request.POST or None, instance=shell_instance)
|
||||
if shell.is_valid():
|
||||
if shell.changed_data:
|
||||
|
@ -648,7 +945,20 @@ def edit_shell(request, shell_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete(ListShell)
|
||||
def del_shell(request, shell, **_kwargs):
|
||||
"""Destruction d'un shell"""
|
||||
"""View for deleting a shell instance object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting a shell, del_shell.
|
||||
A shell can be deleted only if it is not assigned to a user (mode
|
||||
protect).
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
shell_instance: shell instance to delete.
|
||||
|
||||
Returns:
|
||||
Django Shell form.
|
||||
|
||||
"""
|
||||
if request.method == "POST":
|
||||
shell.delete()
|
||||
messages.success(request, _("The shell was deleted."))
|
||||
|
@ -661,8 +971,18 @@ def del_shell(request, shell, **_kwargs):
|
|||
@login_required
|
||||
@can_create(ListRight)
|
||||
def add_listright(request):
|
||||
""" Ajouter un droit/groupe, nécessite droit bureau.
|
||||
Obligation de fournir un gid pour la synchro ldap, unique """
|
||||
"""View for adding a new group of rights and users (listright linked to groups)
|
||||
object for user instance.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of adding a new listright.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django ListRight form.
|
||||
|
||||
"""
|
||||
listright = NewListRightForm(request.POST or None)
|
||||
if listright.is_valid():
|
||||
listright.save()
|
||||
|
@ -678,8 +998,18 @@ def add_listright(request):
|
|||
@login_required
|
||||
@can_edit(ListRight)
|
||||
def edit_listright(request, listright_instance, **_kwargs):
|
||||
""" Editer un groupe/droit, necessite droit bureau,
|
||||
à partir du listright id """
|
||||
"""View for editing a listright instance object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of editing a listright, edit_listright.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
listright_instance: listright instance to edit.
|
||||
|
||||
Returns:
|
||||
Django ListRight form.
|
||||
|
||||
"""
|
||||
listright_form = ListRightForm(request.POST or None, instance=listright_instance)
|
||||
if listright_form.is_valid():
|
||||
if listright_form.changed_data:
|
||||
|
@ -701,8 +1031,20 @@ def edit_listright(request, listright_instance, **_kwargs):
|
|||
@login_required
|
||||
@can_delete_set(ListRight)
|
||||
def del_listright(request, instances):
|
||||
""" Supprimer un ou plusieurs groupe, possible si il est vide, need droit
|
||||
bureau """
|
||||
"""View for deleting a listright instance object.
|
||||
Perform an acl check on editing user, and check if editing user
|
||||
has permission of deleting a listright, del_listright.
|
||||
A listright/group can be deleted only if it is empty (mode
|
||||
protect).
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
listright_instance: listright instance to delete.
|
||||
|
||||
Returns:
|
||||
Django ListRight form.
|
||||
|
||||
"""
|
||||
listright = DelListRightForm(request.POST or None, instances=instances)
|
||||
if listright.is_valid():
|
||||
listright_dels = listright.cleaned_data["listrights"]
|
||||
|
@ -729,7 +1071,17 @@ def del_listright(request, instances):
|
|||
@can_view_all(User)
|
||||
@can_change(User, "state")
|
||||
def mass_archive(request):
|
||||
""" Permet l'archivage massif"""
|
||||
"""View for performing a mass archive operation.
|
||||
Check if editing User has the acl for globaly changing "State"
|
||||
flag on users, and can edit all the users.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django User form.
|
||||
|
||||
"""
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
to_archive_form = MassArchiveForm(request.POST or None)
|
||||
to_archive_list = []
|
||||
|
@ -764,7 +1116,16 @@ def mass_archive(request):
|
|||
@login_required
|
||||
@can_view_all(Adherent)
|
||||
def index(request):
|
||||
""" Affiche l'ensemble des adherents, need droit cableur """
|
||||
"""View for displaying the paginated list of all users/adherents in re2o.
|
||||
Need the global acl for viewing all users, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django Adherent Form.
|
||||
|
||||
"""
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
users_list = Adherent.objects.select_related("room")
|
||||
users_list = SortTable.sort(
|
||||
|
@ -780,7 +1141,16 @@ def index(request):
|
|||
@login_required
|
||||
@can_view_all(Club)
|
||||
def index_clubs(request):
|
||||
""" Affiche l'ensemble des clubs, need droit cableur """
|
||||
"""View for displaying the paginated list of all users/clubs in re2o.
|
||||
Need the global acl for viewing all users, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django Adherent Form.
|
||||
|
||||
"""
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
clubs_list = Club.objects.select_related("room")
|
||||
clubs_list = SortTable.sort(
|
||||
|
@ -796,7 +1166,16 @@ def index_clubs(request):
|
|||
@login_required
|
||||
@can_view_all(Ban)
|
||||
def index_ban(request):
|
||||
""" Affiche l'ensemble des ban, need droit cableur """
|
||||
"""View for displaying the paginated list of all bans in re2o.
|
||||
Need the global acl for viewing all bans, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django Ban Form.
|
||||
|
||||
"""
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
ban_list = Ban.objects.select_related("user")
|
||||
ban_list = SortTable.sort(
|
||||
|
@ -812,7 +1191,16 @@ def index_ban(request):
|
|||
@login_required
|
||||
@can_view_all(Whitelist)
|
||||
def index_white(request):
|
||||
""" Affiche l'ensemble des whitelist, need droit cableur """
|
||||
"""View for displaying the paginated list of all whitelists in re2o.
|
||||
Need the global acl for viewing all whitelists, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django Whitelist Form.
|
||||
|
||||
"""
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
white_list = Whitelist.objects.select_related("user")
|
||||
white_list = SortTable.sort(
|
||||
|
@ -828,7 +1216,16 @@ def index_white(request):
|
|||
@login_required
|
||||
@can_view_all(School)
|
||||
def index_school(request):
|
||||
""" Affiche l'ensemble des établissement"""
|
||||
"""View for displaying the paginated list of all schools in re2o.
|
||||
Need the global acl for viewing all schools, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django School Form.
|
||||
|
||||
"""
|
||||
school_list = School.objects.order_by("name")
|
||||
pagination_number = GeneralOption.get_cached_value("pagination_number")
|
||||
school_list = SortTable.sort(
|
||||
|
@ -844,7 +1241,16 @@ def index_school(request):
|
|||
@login_required
|
||||
@can_view_all(ListShell)
|
||||
def index_shell(request):
|
||||
""" Affiche l'ensemble des shells"""
|
||||
"""View for displaying the paginated list of all shells in re2o.
|
||||
Need the global acl for viewing all shells, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django Shell Form.
|
||||
|
||||
"""
|
||||
shell_list = ListShell.objects.order_by("shell")
|
||||
return render(request, "users/index_shell.html", {"shell_list": shell_list})
|
||||
|
||||
|
@ -852,7 +1258,17 @@ def index_shell(request):
|
|||
@login_required
|
||||
@can_view_all(ListRight)
|
||||
def index_listright(request):
|
||||
""" Affiche l'ensemble des droits"""
|
||||
"""View for displaying the listrights/groups list in re2o.
|
||||
The listrights are sorted by members users, and individual
|
||||
acl for a complete display.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django ListRight Form.
|
||||
|
||||
"""
|
||||
rights = {}
|
||||
for right in (
|
||||
ListRight.objects.order_by("name")
|
||||
|
@ -875,7 +1291,17 @@ def index_listright(request):
|
|||
@login_required
|
||||
@can_view_all(ServiceUser)
|
||||
def index_serviceusers(request):
|
||||
""" Affiche les users de services (pour les accès ldap)"""
|
||||
"""View for displaying the paginated list of all serviceusers in re2o
|
||||
See ServiceUser model for more informations on service users.
|
||||
Need the global acl for viewing all serviceusers, can_view_all.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django ServiceUser Form.
|
||||
|
||||
"""
|
||||
serviceusers_list = ServiceUser.objects.order_by("pseudo")
|
||||
return render(
|
||||
request,
|
||||
|
@ -886,14 +1312,42 @@ def index_serviceusers(request):
|
|||
|
||||
@login_required
|
||||
def mon_profil(request):
|
||||
""" Lien vers profil, renvoie request.id à la fonction """
|
||||
"""Shortcuts view to profil view, with correct arguments.
|
||||
Returns the view profil with users argument, users is set to
|
||||
default request.user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django User Profil Form.
|
||||
|
||||
"""
|
||||
return redirect(reverse("users:profil", kwargs={"userid": str(request.user.id)}))
|
||||
|
||||
|
||||
@login_required
|
||||
@can_view(User)
|
||||
def profil(request, users, **_kwargs):
|
||||
""" Affiche un profil, self or cableur, prend un userid en argument """
|
||||
"""Profil view. Display informations on users, the single user.
|
||||
Informations displayed are:
|
||||
* Adherent or Club User instance informations
|
||||
* Interface/Machine belonging to User instance
|
||||
* Invoice belonging to User instance
|
||||
* Ban instances belonging to User
|
||||
* Whitelists instances belonging to User
|
||||
* Email Settings of User instance
|
||||
* Tickets belonging to User instance.
|
||||
Requires the acl can_view on user instance.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
users: User instance to display profil
|
||||
|
||||
Returns:
|
||||
Django User Profil Form.
|
||||
|
||||
"""
|
||||
machines = (
|
||||
Machine.objects.filter(user=users)
|
||||
.select_related("user")
|
||||
|
@ -969,7 +1423,17 @@ def profil(request, users, **_kwargs):
|
|||
|
||||
|
||||
def reset_password(request):
|
||||
""" Reintialisation du mot de passe si mdp oublié """
|
||||
"""Reset password form, linked to form forgotten password.
|
||||
If an user is found, send an email to him with a link
|
||||
to reset its password.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Django ResetPassword Form.
|
||||
|
||||
"""
|
||||
userform = ResetPasswordForm(request.POST or None)
|
||||
if userform.is_valid():
|
||||
try:
|
||||
|
@ -994,8 +1458,17 @@ def reset_password(request):
|
|||
|
||||
|
||||
def process(request, token):
|
||||
"""Process, lien pour la reinitialisation du mot de passe
|
||||
et la confirmation de l'email"""
|
||||
"""Process view, in case of both reset password, or confirm email in case
|
||||
of new email set.
|
||||
This view calls process_passwd or process_email.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Correct Django process Form.
|
||||
|
||||
"""
|
||||
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
|
||||
req = get_object_or_404(valid_reqs, token=token)
|
||||
|
||||
|
@ -1009,8 +1482,16 @@ def process(request, token):
|
|||
|
||||
|
||||
def process_passwd(request, req):
|
||||
"""Process le changeemnt de mot de passe, renvoie le formulaire
|
||||
demandant le nouveau password"""
|
||||
"""Process view, in case of reset password by email. Returns
|
||||
a form to change and reset the password.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Correct Django process password Form.
|
||||
|
||||
"""
|
||||
user = req.user
|
||||
u_form = PassForm(request.POST or None, instance=user, user=request.user)
|
||||
if u_form.is_valid():
|
||||
|
@ -1031,8 +1512,17 @@ def process_passwd(request, req):
|
|||
|
||||
|
||||
def process_email(request, req):
|
||||
"""Process la confirmation de mail, renvoie le formulaire
|
||||
de validation"""
|
||||
"""Process view, in case of confirm a new email. Returns
|
||||
a form to notify the success of the email confirmation to
|
||||
request.User.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Correct Django process email Form.
|
||||
|
||||
"""
|
||||
user = req.user
|
||||
if request.method == "POST":
|
||||
with transaction.atomic(), reversion.create_revision():
|
||||
|
@ -1055,7 +1545,16 @@ def process_email(request, req):
|
|||
@login_required
|
||||
@can_edit(User)
|
||||
def resend_confirmation_email(request, logged_user, userid):
|
||||
""" Renvoi du mail de confirmation """
|
||||
"""View to resend confirm email, for adding a new email.
|
||||
Check if User has the correct acl.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Correct Django resend email Form.
|
||||
|
||||
"""
|
||||
try:
|
||||
user = User.objects.get(
|
||||
id=userid,
|
||||
|
@ -1074,6 +1573,20 @@ def resend_confirmation_email(request, logged_user, userid):
|
|||
|
||||
@login_required
|
||||
def initial_register(request):
|
||||
"""View to register both a new room, and a new interface/machine for a user.
|
||||
This view is used with switchs function of redirect web after AAA authentication
|
||||
failed. Then, the users log-in, and the new mac-address and switch port, in order to
|
||||
get the room, are included in HTTP Headers by the switch redirection functionnality.
|
||||
This allow to add the new interface with the correct mac-address, and confirm if needed,
|
||||
the new room of request.user.
|
||||
|
||||
Parameters:
|
||||
request (django request): Standard django request.
|
||||
|
||||
Returns:
|
||||
Initial room and interface/machine register Form.
|
||||
|
||||
"""
|
||||
switch_ip = request.GET.get("switch_ip", None)
|
||||
switch_port = request.GET.get("switch_port", None)
|
||||
client_mac = request.GET.get("client_mac", None)
|
||||
|
|
Loading…
Reference in a new issue