8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-30 08:32:26 +00:00

Docstrings, docstrings everywhere

This commit is contained in:
Maël Kervella 2018-06-17 01:06:58 +00:00 committed by Maël Kervella
parent 374dd8da1e
commit ecc5ed0b22
10 changed files with 716 additions and 165 deletions

View file

@ -1,9 +1,8 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2018 Maël Kervella # Copyright © 2018 Maël Kervella
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -19,34 +18,41 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""api.acl """Defines the ACL for the whole API.
Here are defined some functions to check acl on the application. Importing this module, creates the 'can view api' permission if not already
done.
""" """
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.utils.translation import ugettext_lazy as _
# Creates the 'use_api' permission if not created def _create_api_permission():
# The 'use_api' is a fake permission in the sense """Creates the 'use_api' permission if not created.
# it is not associated with an existing model and
# this ensure the permission is created every tun The 'use_api' is a fake permission in the sense it is not associated with an
api_content_type, created = ContentType.objects.get_or_create( existing model and this ensure the permission is created every time this file
app_label=settings.API_CONTENT_TYPE_APP_LABEL, is imported.
model=settings.API_CONTENT_TYPE_MODEL """
) api_content_type, created = ContentType.objects.get_or_create(
if created: app_label=settings.API_CONTENT_TYPE_APP_LABEL,
api_content_type.save() model=settings.API_CONTENT_TYPE_MODEL
api_permission, created = Permission.objects.get_or_create( )
name=settings.API_PERMISSION_NAME, if created:
content_type=api_content_type, api_content_type.save()
codename=settings.API_PERMISSION_CODENAME api_permission, created = Permission.objects.get_or_create(
) name=settings.API_PERMISSION_NAME,
if created: content_type=api_content_type,
api_permission.save() codename=settings.API_PERMISSION_CODENAME
)
if created:
api_permission.save()
_create_api_permission()
def can_view(user): def can_view(user):
@ -64,4 +70,4 @@ def can_view(user):
'codename': settings.API_PERMISSION_CODENAME 'codename': settings.API_PERMISSION_CODENAME
} }
can = user.has_perm('%(app_label)s.%(codename)s' % kwargs) can = user.has_perm('%(app_label)s.%(codename)s' % kwargs)
return can, None if can else "Vous ne pouvez pas voir cette application." return can, None if can else _("You cannot see this application.")

View file

@ -1,20 +1,43 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2018 Maël Kervella
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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.
"""Defines the authentication classes used in the API to authenticate a user.
"""
import datetime import datetime
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions from rest_framework import exceptions
class ExpiringTokenAuthentication(TokenAuthentication): class ExpiringTokenAuthentication(TokenAuthentication):
"""Authenticate a user if the provided token is valid and not expired.
"""
def authenticate_credentials(self, key): def authenticate_credentials(self, key):
model = self.get_model() """See base class. Add the verification the token is not expired.
try: """
token = model.objects.select_related('user').get(key=key) base = super(ExpiringTokenAuthentication, self)
except model.DoesNotExist: user, token = base.authenticate_credentials(key)
raise exceptions.AuthenticationFailed(_('Invalid token.'))
if not token.user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
# Check that the genration time of the token is not too old
token_duration = datetime.timedelta( token_duration = datetime.timedelta(
seconds=settings.API_TOKEN_DURATION seconds=settings.API_TOKEN_DURATION
) )

View file

@ -1,15 +1,57 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2018 Maël Kervella
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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.
"""Defines the pagination classes used in the API to paginate the results.
"""
from rest_framework import pagination from rest_framework import pagination
class PageSizedPagination(pagination.PageNumberPagination): class PageSizedPagination(pagination.PageNumberPagination):
""" """Provide the possibility to control the page size by using the
Pagination subclass to all to control the page size 'page_size' parameter. The value 'all' can be used for this parameter
to retrieve all the results in a single page.
Attributes:
page_size_query_param: The string to look for in the parameters of
a query to get the page_size requested.
all_pages_strings: A set of strings that can be used in the query to
request all results in a single page.
max_page_size: The maximum number of results a page can output no
matter what is requested.
""" """
page_size_query_param = 'page_size' page_size_query_param = 'page_size'
all_pages_strings = ('all',) all_pages_strings = ('all',)
max_page_size = 10000 max_page_size = 10000
def get_page_size(self, request): def get_page_size(self, request):
"""Retrieve the size of the page according to the parameters of the
request.
Args:
request: the request of the user
Returns:
A integer between 0 and `max_page_size` that represent the size
of the page to use.
"""
try: try:
page_size_str = request.query_params[self.page_size_query_param] page_size_str = request.query_params[self.page_size_query_param]
if page_size_str in self.all_pages_strings: if page_size_str in self.all_pages_strings:

View file

@ -1,13 +1,61 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2018 Maël Kervella
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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.
"""Defines the permission classes used in the API.
"""
from rest_framework import permissions, exceptions from rest_framework import permissions, exceptions
from re2o.acl import can_create, can_edit, can_delete, can_view_all from re2o.acl import can_create, can_edit, can_delete, can_view_all
from . import acl from . import acl
def can_see_api(*_, **__): def can_see_api(*_, **__):
"""Check if a user can view the API.
Returns:
A function that takes a user as an argument and returns
an ACL tuple that assert this user can see the API.
"""
return lambda user: acl.can_view(user) return lambda user: acl.can_view(user)
def _get_param_in_view(view, param_name): def _get_param_in_view(view, param_name):
"""Utility function to retrieve an attribute in a view passed in argument.
Uses the result of `{view}.get_{param_name}()` if existing else uses the
value of `{view}.{param_name}` directly.
Args:
view: The view where to look into.
param_name: The name of the attribute to look for.
Returns:
The result of the getter function if found else the value of the
attribute itself.
Raises:
AssertionError: None of the getter function or the attribute are
defined in the view.
"""
assert hasattr(view, 'get_'+param_name) \ assert hasattr(view, 'get_'+param_name) \
or getattr(view, param_name, None) is not None, ( or getattr(view, param_name, None) is not None, (
'cannot apply {} on a view that does not set ' 'cannot apply {} on a view that does not set '
@ -24,15 +72,30 @@ def _get_param_in_view(view, param_name):
class ACLPermission(permissions.BasePermission): class ACLPermission(permissions.BasePermission):
""" """A permission class used to check the ACL to validate the permissions
Permission subclass for views that requires a specific model-based of a user.
permission or don't define a queryset
The view must define a `.get_perms_map()` or a `.perms_map` attribute.
See the wiki for the syntax of this attribute.
""" """
def get_required_permissions(self, method, view): def get_required_permissions(self, method, view):
""" """Build the list of permissions required for the request to be
Given a list of models and an HTTP method, return the list accepted.
of acl functions that the user is required to verify.
Args:
method: The HTTP method name used for the request.
view: The view which is responding to the request.
Returns:
The list of ACL functions to apply to a user in order to check
if he has the right permissions.
Raises:
AssertionError: None of `.get_perms_map()` or `.perms_map` are
defined in the view.
rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view.
""" """
perms_map = _get_param_in_view(view, 'perms_map') perms_map = _get_param_in_view(view, 'perms_map')
@ -42,6 +105,22 @@ class ACLPermission(permissions.BasePermission):
return [can_see_api()] + list(perms_map[method]) return [can_see_api()] + list(perms_map[method])
def has_permission(self, request, view): def has_permission(self, request, view):
"""Check that the user has the permissions to perform the request.
Args:
request: The request performed.
view: The view which is responding to the request.
Returns:
A boolean indicating if the user has the permission to
perform the request.
Raises:
AssertionError: None of `.get_perms_map()` or `.perms_map` are
defined in the view.
rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view.
"""
# Workaround to ensure ACLPermissions are not applied # Workaround to ensure ACLPermissions are not applied
# to the root view when using DefaultRouter. # to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False): if getattr(view, '_ignore_model_permissions', False):
@ -54,19 +133,20 @@ class ACLPermission(permissions.BasePermission):
return all(perm(request.user)[0] for perm in perms) return all(perm(request.user)[0] for perm in perms)
def has_object_permission(self, request, view, obj):
# Should never be called here but documentation
# requires to implement this function
return False
class AutodetectACLPermission(permissions.BasePermission): class AutodetectACLPermission(permissions.BasePermission):
"""A permission class used to autodetect the ACL needed to validate the
permissions of a user based on the queryset of the view.
The view must define a `.get_queryset()` or a `.queryset` attribute.
Attributes:
perms_map: The mapping of each valid HTTP method to the required
model-based ACL permissions.
perms_obj_map: The mapping of each valid HTTP method to the required
object-based ACL permissions.
""" """
Permission subclass in charge of checking the ACL to determine
if a user can access the models. Autodetect which ACL are required
based on a queryset. Requires `.queryset` or `.get_queryset()`
to be defined in the view.
"""
perms_map = { perms_map = {
'GET': [can_see_api, lambda model: model.can_view_all], 'GET': [can_see_api, lambda model: model.can_view_all],
'OPTIONS': [can_see_api, lambda model: model.can_view_all], 'OPTIONS': [can_see_api, lambda model: model.can_view_all],
@ -87,9 +167,20 @@ class AutodetectACLPermission(permissions.BasePermission):
} }
def get_required_permissions(self, method, model): def get_required_permissions(self, method, model):
""" """Build the list of model-based permissions required for the
Given a model and an HTTP method, return the list of acl request to be accepted.
functions that the user is required to verify.
Args:
method: The HTTP method name used for the request.
view: The view which is responding to the request.
Returns:
The list of ACL functions to apply to a user in order to check
if he has the right permissions.
Raises:
rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view.
""" """
if method not in self.perms_map: if method not in self.perms_map:
raise exceptions.MethodNotAllowed(method) raise exceptions.MethodNotAllowed(method)
@ -97,9 +188,20 @@ class AutodetectACLPermission(permissions.BasePermission):
return [perm(model) for perm in self.perms_map[method]] return [perm(model) for perm in self.perms_map[method]]
def get_required_object_permissions(self, method, obj): def get_required_object_permissions(self, method, obj):
""" """Build the list of object-based permissions required for the
Given an object and an HTTP method, return the list of acl request to be accepted.
functions that the user is required to verify.
Args:
method: The HTTP method name used for the request.
view: The view which is responding to the request.
Returns:
The list of ACL functions to apply to a user in order to check
if he has the right permissions.
Raises:
rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view.
""" """
if method not in self.perms_obj_map: if method not in self.perms_obj_map:
raise exceptions.MethodNotAllowed(method) raise exceptions.MethodNotAllowed(method)
@ -107,13 +209,26 @@ class AutodetectACLPermission(permissions.BasePermission):
return [perm(obj) for perm in self.perms_obj_map[method]] return [perm(obj) for perm in self.perms_obj_map[method]]
def _queryset(self, view): def _queryset(self, view):
"""
Return the queryset associated with view and raise an error
is there is none.
"""
return _get_param_in_view(view, 'queryset') return _get_param_in_view(view, 'queryset')
def has_permission(self, request, view): def has_permission(self, request, view):
"""Check that the user has the model-based permissions to perform
the request.
Args:
request: The request performed.
view: The view which is responding to the request.
Returns:
A boolean indicating if the user has the permission to
perform the request.
Raises:
AssertionError: None of `.get_queryset()` or `.queryset` are
defined in the view.
rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view.
"""
# Workaround to ensure ACLPermissions are not applied # Workaround to ensure ACLPermissions are not applied
# to the root view when using DefaultRouter. # to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False): if getattr(view, '_ignore_model_permissions', False):
@ -128,8 +243,22 @@ class AutodetectACLPermission(permissions.BasePermission):
return all(perm(request.user)[0] for perm in perms) return all(perm(request.user)[0] for perm in perms)
def has_object_permission(self, request, view, obj): def has_object_permission(self, request, view, obj):
"""Check that the user has the object-based permissions to perform
the request.
Args:
request: The request performed.
view: The view which is responding to the request.
Returns:
A boolean indicating if the user has the permission to
perform the request.
Raises:
rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view.
"""
# authentication checks have already executed via has_permission # authentication checks have already executed via has_permission
queryset = self._queryset(view)
user = request.user user = request.user
perms = self.get_required_object_permissions(request.method, obj) perms = self.get_required_object_permissions(request.method, obj)

View file

@ -2,7 +2,7 @@
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2018 Mael Kervella # Copyright © 2018 Mael Kervella
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -17,12 +17,12 @@
# You should have received a copy of the GNU General Public License along # 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., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""api.routers
Definition of the custom routers to generate the URLs of the API """Defines the custom routers to generate the URLs of the API.
""" """
from collections import OrderedDict from collections import OrderedDict
from django.conf.urls import url, include from django.conf.urls import url, include
from django.core.urlresolvers import NoReverseMatch from django.core.urlresolvers import NoReverseMatch
from rest_framework import views from rest_framework import views
@ -32,32 +32,60 @@ from rest_framework.reverse import reverse
from rest_framework.schemas import SchemaGenerator from rest_framework.schemas import SchemaGenerator
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
class AllViewsRouter(DefaultRouter): class AllViewsRouter(DefaultRouter):
"""A router that can register both viewsets and views and generates
a full API root page with all the generated URLs.
"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.view_registry = [] self.view_registry = []
super(AllViewsRouter, self).__init__(*args, **kwargs) super(AllViewsRouter, self).__init__(*args, **kwargs)
def register_viewset(self, *args, **kwargs): def register_viewset(self, *args, **kwargs):
""" """Register a viewset in the router. Alias of `register` for
Register a viewset in the router convenience.
Alias of `register` for convenience
See `register` in the base class for details.
""" """
return self.register(*args, **kwargs) return self.register(*args, **kwargs)
def register_view(self, pattern, view, name=None): def register_view(self, pattern, view, name=None):
""" """Register a view in the router.
Register a view in the router
Args:
pattern: The URL pattern to use for this view.
view: The class-based view to register.
name: An optional name for the route generated. Defaults is
based on the pattern last section (delimited by '/').
""" """
if name is None: if name is None:
name = self.get_default_name(pattern) name = self.get_default_name(pattern)
self.view_registry.append((pattern, view, name)) self.view_registry.append((pattern, view, name))
def get_default_name(self, pattern): def get_default_name(self, pattern):
"""Returns the name to use for the route if none was specified.
Args:
pattern: The pattern for this route.
Returns:
The name to use for this route.
"""
return pattern.split('/')[-1] return pattern.split('/')[-1]
def get_api_root_view(self, schema_urls=None): def get_api_root_view(self, schema_urls=None):
""" """Create a class-based view to use as the API root.
Return a view to use as the API root.
Highly inspired by the base class. See details on the implementation
in the base class. The only difference is that registered view URLs
are added after the registered viewset URLs on this root API page.
Args:
schema_urls: A schema to use for the URLs.
Returns:
The view to use to display the root API page.
""" """
api_root_dict = OrderedDict() api_root_dict = OrderedDict()
list_name = self.routes[0].name list_name = self.routes[0].name
@ -115,6 +143,12 @@ class AllViewsRouter(DefaultRouter):
return APIRoot.as_view() return APIRoot.as_view()
def get_urls(self): def get_urls(self):
"""Builds the list of URLs to register.
Returns:
A list of the URLs generated based on the viewsets registered
followed by the URLs generated based on the views registered.
"""
urls = super(AllViewsRouter, self).get_urls() urls = super(AllViewsRouter, self).get_urls()
for pattern, view, name in self.view_registry: for pattern, view, name in self.view_registry:

View file

@ -2,7 +2,7 @@
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2018 Mael Kervella # Copyright © 2018 Maël Kervella
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,8 +18,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
""" """Defines the serializers of the API
Serializers for the API app
""" """
from rest_framework import serializers from rest_framework import serializers
@ -31,12 +30,15 @@ import topologie.models as topologie
import users.models as users import users.models as users
# The namespace used for the API. It must match the namespace used in the
# urlpatterns to include the API URLs.
API_NAMESPACE = 'api' API_NAMESPACE = 'api'
class NamespacedHRField(serializers.HyperlinkedRelatedField): class NamespacedHRField(serializers.HyperlinkedRelatedField):
""" A HyperlinkedRelatedField subclass to automatically prefix """A `rest_framework.serializers.HyperlinkedRelatedField` subclass to
view names with a namespace """ automatically prefix view names with the API namespace.
"""
def __init__(self, view_name=None, **kwargs): def __init__(self, view_name=None, **kwargs):
if view_name is not None: if view_name is not None:
view_name = '%s:%s' % (API_NAMESPACE, view_name) view_name = '%s:%s' % (API_NAMESPACE, view_name)
@ -44,8 +46,9 @@ class NamespacedHRField(serializers.HyperlinkedRelatedField):
class NamespacedHIField(serializers.HyperlinkedIdentityField): class NamespacedHIField(serializers.HyperlinkedIdentityField):
""" A HyperlinkedIdentityField subclass to automatically prefix """A `rest_framework.serializers.HyperlinkedIdentityField` subclass to
view names with a namespace """ automatically prefix view names with teh API namespace.
"""
def __init__(self, view_name=None, **kwargs): def __init__(self, view_name=None, **kwargs):
if view_name is not None: if view_name is not None:
view_name = '%s:%s' % (API_NAMESPACE, view_name) view_name = '%s:%s' % (API_NAMESPACE, view_name)
@ -53,16 +56,19 @@ class NamespacedHIField(serializers.HyperlinkedIdentityField):
class NamespacedHMSerializer(serializers.HyperlinkedModelSerializer): class NamespacedHMSerializer(serializers.HyperlinkedModelSerializer):
""" A HyperlinkedModelSerializer subclass to use `NamespacedHRField` as """A `rest_framework.serializers.HyperlinkedModelSerializer` subclass to
field and automatically prefix view names with a namespace """ automatically prefix view names with the API namespace.
"""
serializer_related_field = NamespacedHRField serializer_related_field = NamespacedHRField
serializer_url_field = NamespacedHIField serializer_url_field = NamespacedHIField
# COTISATIONS APP # COTISATIONS
class FactureSerializer(NamespacedHMSerializer): class FactureSerializer(NamespacedHMSerializer):
"""Serialize `cotisations.models.Facture` objects.
"""
class Meta: class Meta:
model = cotisations.Facture model = cotisations.Facture
fields = ('user', 'paiement', 'banque', 'cheque', 'date', 'valid', fields = ('user', 'paiement', 'banque', 'cheque', 'date', 'valid',
@ -70,6 +76,8 @@ class FactureSerializer(NamespacedHMSerializer):
class VenteSerializer(NamespacedHMSerializer): class VenteSerializer(NamespacedHMSerializer):
"""Serialize `cotisations.models.Vente` objects.
"""
class Meta: class Meta:
model = cotisations.Vente model = cotisations.Vente
fields = ('facture', 'number', 'name', 'prix', 'duration', fields = ('facture', 'number', 'name', 'prix', 'duration',
@ -77,6 +85,8 @@ class VenteSerializer(NamespacedHMSerializer):
class ArticleSerializer(NamespacedHMSerializer): class ArticleSerializer(NamespacedHMSerializer):
"""Serialize `cotisations.models.Article` objects.
"""
class Meta: class Meta:
model = cotisations.Article model = cotisations.Article
fields = ('name', 'prix', 'duration', 'type_user', fields = ('name', 'prix', 'duration', 'type_user',
@ -84,40 +94,52 @@ class ArticleSerializer(NamespacedHMSerializer):
class BanqueSerializer(NamespacedHMSerializer): class BanqueSerializer(NamespacedHMSerializer):
"""Serialize `cotisations.models.Banque` objects.
"""
class Meta: class Meta:
model = cotisations.Banque model = cotisations.Banque
fields = ('name', 'api_url') fields = ('name', 'api_url')
class PaiementSerializer(NamespacedHMSerializer): class PaiementSerializer(NamespacedHMSerializer):
"""Serialize `cotisations.models.Paiement` objects.
"""
class Meta: class Meta:
model = cotisations.Paiement model = cotisations.Paiement
fields = ('moyen', 'type_paiement', 'api_url') fields = ('moyen', 'type_paiement', 'api_url')
class CotisationSerializer(NamespacedHMSerializer): class CotisationSerializer(NamespacedHMSerializer):
"""Serialize `cotisations.models.Cotisation` objects.
"""
class Meta: class Meta:
model = cotisations.Cotisation model = cotisations.Cotisation
fields = ('vente', 'type_cotisation', 'date_start', 'date_end', fields = ('vente', 'type_cotisation', 'date_start', 'date_end',
'api_url') 'api_url')
# MACHINES APP # MACHINES
class MachineSerializer(NamespacedHMSerializer): class MachineSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Machine` objects.
"""
class Meta: class Meta:
model = machines.Machine model = machines.Machine
fields = ('user', 'name', 'active', 'api_url') fields = ('user', 'name', 'active', 'api_url')
class MachineTypeSerializer(NamespacedHMSerializer): class MachineTypeSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.MachineType` objects.
"""
class Meta: class Meta:
model = machines.MachineType model = machines.MachineType
fields = ('type', 'ip_type', 'api_url') fields = ('type', 'ip_type', 'api_url')
class IpTypeSerializer(NamespacedHMSerializer): class IpTypeSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.IpType` objects.
"""
class Meta: class Meta:
model = machines.IpType model = machines.IpType
fields = ('type', 'extension', 'need_infra', 'domaine_ip_start', fields = ('type', 'extension', 'need_infra', 'domaine_ip_start',
@ -126,12 +148,16 @@ class IpTypeSerializer(NamespacedHMSerializer):
class VlanSerializer(NamespacedHMSerializer): class VlanSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Vlan` objects.
"""
class Meta: class Meta:
model = machines.Vlan model = machines.Vlan
fields = ('vlan_id', 'name', 'comment', 'api_url') fields = ('vlan_id', 'name', 'comment', 'api_url')
class NasSerializer(NamespacedHMSerializer): class NasSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Nas` objects.
"""
class Meta: class Meta:
model = machines.Nas model = machines.Nas
fields = ('name', 'nas_type', 'machine_type', 'port_access_mode', fields = ('name', 'nas_type', 'machine_type', 'port_access_mode',
@ -139,6 +165,8 @@ class NasSerializer(NamespacedHMSerializer):
class SOASerializer(NamespacedHMSerializer): class SOASerializer(NamespacedHMSerializer):
"""Serialize `machines.models.SOA` objects.
"""
class Meta: class Meta:
model = machines.SOA model = machines.SOA
fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl', fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl',
@ -146,6 +174,8 @@ class SOASerializer(NamespacedHMSerializer):
class ExtensionSerializer(NamespacedHMSerializer): class ExtensionSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Extension` objects.
"""
class Meta: class Meta:
model = machines.Extension model = machines.Extension
fields = ('name', 'need_infra', 'origin', 'origin_v6', 'soa', fields = ('name', 'need_infra', 'origin', 'origin_v6', 'soa',
@ -153,24 +183,32 @@ class ExtensionSerializer(NamespacedHMSerializer):
class MxSerializer(NamespacedHMSerializer): class MxSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Mx` objects.
"""
class Meta: class Meta:
model = machines.Mx model = machines.Mx
fields = ('zone', 'priority', 'name', 'api_url') fields = ('zone', 'priority', 'name', 'api_url')
class NsSerializer(NamespacedHMSerializer): class NsSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Ns` objects.
"""
class Meta: class Meta:
model = machines.Ns model = machines.Ns
fields = ('zone', 'ns', 'api_url') fields = ('zone', 'ns', 'api_url')
class TxtSerializer(NamespacedHMSerializer): class TxtSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Txt` objects.
"""
class Meta: class Meta:
model = machines.Txt model = machines.Txt
fields = ('zone', 'field1', 'field2', 'api_url') fields = ('zone', 'field1', 'field2', 'api_url')
class SrvSerializer(NamespacedHMSerializer): class SrvSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Srv` objects.
"""
class Meta: class Meta:
model = machines.Srv model = machines.Srv
fields = ('service', 'protocole', 'extension', 'ttl', 'priority', fields = ('service', 'protocole', 'extension', 'ttl', 'priority',
@ -178,6 +216,8 @@ class SrvSerializer(NamespacedHMSerializer):
class InterfaceSerializer(NamespacedHMSerializer): class InterfaceSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Interface` objects.
"""
mac_address = serializers.CharField() mac_address = serializers.CharField()
active = serializers.BooleanField(source='is_active') active = serializers.BooleanField(source='is_active')
@ -188,12 +228,16 @@ class InterfaceSerializer(NamespacedHMSerializer):
class Ipv6ListSerializer(NamespacedHMSerializer): class Ipv6ListSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Ipv6List` objects.
"""
class Meta: class Meta:
model = machines.Ipv6List model = machines.Ipv6List
fields = ('ipv6', 'interface', 'slaac_ip', 'api_url') fields = ('ipv6', 'interface', 'slaac_ip', 'api_url')
class DomainSerializer(NamespacedHMSerializer): class DomainSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Domain` objects.
"""
class Meta: class Meta:
model = machines.Domain model = machines.Domain
fields = ('interface_parent', 'name', 'extension', 'cname', fields = ('interface_parent', 'name', 'extension', 'cname',
@ -201,12 +245,16 @@ class DomainSerializer(NamespacedHMSerializer):
class IpListSerializer(NamespacedHMSerializer): class IpListSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.IpList` objects.
"""
class Meta: class Meta:
model = machines.IpList model = machines.IpList
fields = ('ipv4', 'ip_type', 'need_infra', 'api_url') fields = ('ipv4', 'ip_type', 'need_infra', 'api_url')
class ServiceSerializer(NamespacedHMSerializer): class ServiceSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Service` objects.
"""
class Meta: class Meta:
model = machines.Service model = machines.Service
fields = ('service_type', 'min_time_regen', 'regular_time_regen', fields = ('service_type', 'min_time_regen', 'regular_time_regen',
@ -214,6 +262,8 @@ class ServiceSerializer(NamespacedHMSerializer):
class ServiceLinkSerializer(NamespacedHMSerializer): class ServiceLinkSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.Service_link` objects.
"""
class Meta: class Meta:
model = machines.Service_link model = machines.Service_link
fields = ('service', 'server', 'last_regen', 'asked_regen', fields = ('service', 'server', 'last_regen', 'asked_regen',
@ -224,6 +274,8 @@ class ServiceLinkSerializer(NamespacedHMSerializer):
class OuverturePortListSerializer(NamespacedHMSerializer): class OuverturePortListSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.OuverturePortList` objects.
"""
class Meta: class Meta:
model = machines.OuverturePortList model = machines.OuverturePortList
fields = ('name', 'tcp_ports_in', 'udp_ports_in', 'tcp_ports_out', fields = ('name', 'tcp_ports_in', 'udp_ports_in', 'tcp_ports_out',
@ -231,15 +283,19 @@ class OuverturePortListSerializer(NamespacedHMSerializer):
class OuverturePortSerializer(NamespacedHMSerializer): class OuverturePortSerializer(NamespacedHMSerializer):
"""Serialize `machines.models.OuverturePort` objects.
"""
class Meta: class Meta:
model = machines.OuverturePort model = machines.OuverturePort
fields = ('begin', 'end', 'port_list', 'protocole', 'io', 'api_url') fields = ('begin', 'end', 'port_list', 'protocole', 'io', 'api_url')
# PREFERENCES APP # PREFERENCES
class OptionalUserSerializer(NamespacedHMSerializer): class OptionalUserSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.OptionalUser` objects.
"""
tel_mandatory = serializers.BooleanField(source='is_tel_mandatory') tel_mandatory = serializers.BooleanField(source='is_tel_mandatory')
class Meta: class Meta:
@ -250,6 +306,8 @@ class OptionalUserSerializer(NamespacedHMSerializer):
class OptionalMachineSerializer(NamespacedHMSerializer): class OptionalMachineSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.OptionalMachine` objects.
"""
class Meta: class Meta:
model = preferences.OptionalMachine model = preferences.OptionalMachine
fields = ('password_machine', 'max_lambdauser_interfaces', fields = ('password_machine', 'max_lambdauser_interfaces',
@ -258,6 +316,8 @@ class OptionalMachineSerializer(NamespacedHMSerializer):
class OptionalTopologieSerializer(NamespacedHMSerializer): class OptionalTopologieSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.OptionalTopologie` objects.
"""
class Meta: class Meta:
model = preferences.OptionalTopologie model = preferences.OptionalTopologie
fields = ('radius_general_policy', 'vlan_decision_ok', fields = ('radius_general_policy', 'vlan_decision_ok',
@ -265,6 +325,8 @@ class OptionalTopologieSerializer(NamespacedHMSerializer):
class GeneralOptionSerializer(NamespacedHMSerializer): class GeneralOptionSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.GeneralOption` objects.
"""
class Meta: class Meta:
model = preferences.GeneralOption model = preferences.GeneralOption
fields = ('general_message', 'search_display_page', fields = ('general_message', 'search_display_page',
@ -274,12 +336,16 @@ class GeneralOptionSerializer(NamespacedHMSerializer):
class ServiceSerializer(NamespacedHMSerializer): class ServiceSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.Service` objects.
"""
class Meta: class Meta:
model = preferences.Service model = preferences.Service
fields = ('name', 'url', 'description', 'image', 'api_url') fields = ('name', 'url', 'description', 'image', 'api_url')
class AssoOptionSerializer(NamespacedHMSerializer): class AssoOptionSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.AssoOption` objects.
"""
class Meta: class Meta:
model = preferences.AssoOption model = preferences.AssoOption
fields = ('name', 'siret', 'adresse1', 'adresse2', 'contact', fields = ('name', 'siret', 'adresse1', 'adresse2', 'contact',
@ -288,22 +354,28 @@ class AssoOptionSerializer(NamespacedHMSerializer):
class HomeOptionSerializer(NamespacedHMSerializer): class HomeOptionSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.HomeOption` objects.
"""
class Meta: class Meta:
model = preferences.HomeOption model = preferences.HomeOption
fields = ('facebook_url', 'twitter_url', 'twitter_account_name') fields = ('facebook_url', 'twitter_url', 'twitter_account_name')
class MailMessageOptionSerializer(NamespacedHMSerializer): class MailMessageOptionSerializer(NamespacedHMSerializer):
"""Serialize `preferences.models.MailMessageOption` objects.
"""
class Meta: class Meta:
model = preferences.MailMessageOption model = preferences.MailMessageOption
fields = ('welcome_mail_fr', 'welcome_mail_en') fields = ('welcome_mail_fr', 'welcome_mail_en')
# TOPOLOGIE APP # TOPOLOGIE
class StackSerializer(NamespacedHMSerializer): class StackSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.Stack` objects
"""
class Meta: class Meta:
model = topologie.Stack model = topologie.Stack
fields = ('name', 'stack_id', 'details', 'member_id_min', fields = ('name', 'stack_id', 'details', 'member_id_min',
@ -311,12 +383,16 @@ class StackSerializer(NamespacedHMSerializer):
class AccessPointSerializer(NamespacedHMSerializer): class AccessPointSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.AccessPoint` objects
"""
class Meta: class Meta:
model = topologie.AccessPoint model = topologie.AccessPoint
fields = ('user', 'name', 'active', 'location', 'api_url') fields = ('user', 'name', 'active', 'location', 'api_url')
class SwitchSerializer(NamespacedHMSerializer): class SwitchSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.Switch` objects
"""
port_amount = serializers.IntegerField(source='number') port_amount = serializers.IntegerField(source='number')
class Meta: class Meta:
model = topologie.Switch model = topologie.Switch
@ -325,30 +401,40 @@ class SwitchSerializer(NamespacedHMSerializer):
class ModelSwitchSerializer(NamespacedHMSerializer): class ModelSwitchSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.ModelSwitch` objects
"""
class Meta: class Meta:
model = topologie.ModelSwitch model = topologie.ModelSwitch
fields = ('reference', 'constructor', 'api_url') fields = ('reference', 'constructor', 'api_url')
class ConstructorSwitchSerializer(NamespacedHMSerializer): class ConstructorSwitchSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.ConstructorSwitch` objects
"""
class Meta: class Meta:
model = topologie.ConstructorSwitch model = topologie.ConstructorSwitch
fields = ('name', 'api_url') fields = ('name', 'api_url')
class SwitchBaySerializer(NamespacedHMSerializer): class SwitchBaySerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.SwitchBay` objects
"""
class Meta: class Meta:
model = topologie.SwitchBay model = topologie.SwitchBay
fields = ('name', 'building', 'info', 'api_url') fields = ('name', 'building', 'info', 'api_url')
class BuildingSerializer(NamespacedHMSerializer): class BuildingSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.Building` objects
"""
class Meta: class Meta:
model = topologie.Building model = topologie.Building
fields = ('name', 'api_url') fields = ('name', 'api_url')
class SwitchPortSerializer(NamespacedHMSerializer): class SwitchPortSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.Port` objects
"""
class Meta: class Meta:
model = topologie.Port model = topologie.Port
fields = ('switch', 'port', 'room', 'machine_interface', 'related', fields = ('switch', 'port', 'room', 'machine_interface', 'related',
@ -360,15 +446,19 @@ class SwitchPortSerializer(NamespacedHMSerializer):
class RoomSerializer(NamespacedHMSerializer): class RoomSerializer(NamespacedHMSerializer):
"""Serialize `topologie.models.Room` objects
"""
class Meta: class Meta:
model = topologie.Room model = topologie.Room
fields = ('name', 'details', 'api_url') fields = ('name', 'details', 'api_url')
# USERS APP # USERS
class UserSerializer(NamespacedHMSerializer): class UserSerializer(NamespacedHMSerializer):
"""Serialize `users.models.User` objects.
"""
access = serializers.BooleanField(source='has_access') access = serializers.BooleanField(source='has_access')
uid = serializers.IntegerField(source='uid_number') uid = serializers.IntegerField(source='uid_number')
@ -383,6 +473,8 @@ class UserSerializer(NamespacedHMSerializer):
class ClubSerializer(NamespacedHMSerializer): class ClubSerializer(NamespacedHMSerializer):
"""Serialize `users.models.Club` objects.
"""
name = serializers.CharField(source='surname') name = serializers.CharField(source='surname')
access = serializers.BooleanField(source='has_access') access = serializers.BooleanField(source='has_access')
uid = serializers.IntegerField(source='uid_number') uid = serializers.IntegerField(source='uid_number')
@ -399,6 +491,8 @@ class ClubSerializer(NamespacedHMSerializer):
class AdherentSerializer(NamespacedHMSerializer): class AdherentSerializer(NamespacedHMSerializer):
"""Serialize `users.models.Adherent` objects.
"""
access = serializers.BooleanField(source='has_access') access = serializers.BooleanField(source='has_access')
uid = serializers.IntegerField(source='uid_number') uid = serializers.IntegerField(source='uid_number')
@ -413,24 +507,32 @@ class AdherentSerializer(NamespacedHMSerializer):
class ServiceUserSerializer(NamespacedHMSerializer): class ServiceUserSerializer(NamespacedHMSerializer):
"""Serialize `users.models.ServiceUser` objects.
"""
class Meta: class Meta:
model = users.ServiceUser model = users.ServiceUser
fields = ('pseudo', 'access_group', 'comment', 'api_url') fields = ('pseudo', 'access_group', 'comment', 'api_url')
class SchoolSerializer(NamespacedHMSerializer): class SchoolSerializer(NamespacedHMSerializer):
"""Serialize `users.models.School` objects.
"""
class Meta: class Meta:
model = users.School model = users.School
fields = ('name', 'api_url') fields = ('name', 'api_url')
class ListRightSerializer(NamespacedHMSerializer): class ListRightSerializer(NamespacedHMSerializer):
"""Serialize `users.models.ListRight` objects.
"""
class Meta: class Meta:
model = users.ListRight model = users.ListRight
fields = ('unix_name', 'gid', 'critical', 'details', 'api_url') fields = ('unix_name', 'gid', 'critical', 'details', 'api_url')
class ShellSerializer(NamespacedHMSerializer): class ShellSerializer(NamespacedHMSerializer):
"""Serialize `users.models.ListShell` objects.
"""
class Meta: class Meta:
model = users.ListShell model = users.ListShell
fields = ('shell', 'api_url') fields = ('shell', 'api_url')
@ -440,6 +542,8 @@ class ShellSerializer(NamespacedHMSerializer):
class BanSerializer(NamespacedHMSerializer): class BanSerializer(NamespacedHMSerializer):
"""Serialize `users.models.Ban` objects.
"""
active = serializers.BooleanField(source='is_active') active = serializers.BooleanField(source='is_active')
class Meta: class Meta:
@ -449,6 +553,8 @@ class BanSerializer(NamespacedHMSerializer):
class WhitelistSerializer(NamespacedHMSerializer): class WhitelistSerializer(NamespacedHMSerializer):
"""Serialize `users.models.Whitelist` objects.
"""
active = serializers.BooleanField(source='is_active') active = serializers.BooleanField(source='is_active')
class Meta: class Meta:
@ -456,10 +562,12 @@ class WhitelistSerializer(NamespacedHMSerializer):
fields = ('user', 'raison', 'date_start', 'date_end', 'active', 'api_url') fields = ('user', 'raison', 'date_start', 'date_end', 'active', 'api_url')
# Services # SERVICE REGEN
class ServiceRegenSerializer(NamespacedHMSerializer): class ServiceRegenSerializer(NamespacedHMSerializer):
"""Serialize the data about the services to regen.
"""
hostname = serializers.CharField(source='server.domain.name', read_only=True) hostname = serializers.CharField(source='server.domain.name', read_only=True)
service_name = serializers.CharField(source='service.service_type', read_only=True) service_name = serializers.CharField(source='service.service_type', read_only=True)
need_regen = serializers.BooleanField() need_regen = serializers.BooleanField()
@ -476,6 +584,9 @@ class ServiceRegenSerializer(NamespacedHMSerializer):
class HostMacIpSerializer(serializers.ModelSerializer): class HostMacIpSerializer(serializers.ModelSerializer):
"""Serialize the data about the hostname-ipv4-mac address association
to build the DHCP lease files.
"""
hostname = serializers.CharField(source='domain.name', read_only=True) hostname = serializers.CharField(source='domain.name', read_only=True)
extension = serializers.CharField(source='domain.extension.name', read_only=True) extension = serializers.CharField(source='domain.extension.name', read_only=True)
mac_address = serializers.CharField(read_only=True) mac_address = serializers.CharField(read_only=True)
@ -490,22 +601,34 @@ class HostMacIpSerializer(serializers.ModelSerializer):
class SOARecordSerializer(SOASerializer): class SOARecordSerializer(SOASerializer):
"""Serialize `machines.models.SOA` objects with the data needed to
generate a SOA DNS record.
"""
class Meta: class Meta:
model = machines.SOA model = machines.SOA
fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl') fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl')
class OriginV4RecordSerializer(IpListSerializer): class OriginV4RecordSerializer(IpListSerializer):
"""Serialize `machines.models.IpList` objects with the data needed to
generate an IPv4 Origin DNS record.
"""
class Meta(IpListSerializer.Meta): class Meta(IpListSerializer.Meta):
fields = ('ipv4',) fields = ('ipv4',)
class OriginV6RecordSerializer(Ipv6ListSerializer): class OriginV6RecordSerializer(Ipv6ListSerializer):
"""Serialize `machines.models.Ipv6List` objects with the data needed to
generate an IPv6 Origin DNS record.
"""
class Meta(Ipv6ListSerializer.Meta): class Meta(Ipv6ListSerializer.Meta):
fields = ('ipv6',) fields = ('ipv6',)
class NSRecordSerializer(NsSerializer): class NSRecordSerializer(NsSerializer):
"""Serialize `machines.models.Ns` objects with the data needed to
generate a NS DNS record.
"""
target = serializers.CharField(source='ns.name', read_only=True) target = serializers.CharField(source='ns.name', read_only=True)
class Meta(NsSerializer.Meta): class Meta(NsSerializer.Meta):
@ -513,6 +636,9 @@ class NSRecordSerializer(NsSerializer):
class MXRecordSerializer(MxSerializer): class MXRecordSerializer(MxSerializer):
"""Serialize `machines.models.Mx` objects with the data needed to
generate a MX DNS record.
"""
target = serializers.CharField(source='name.name', read_only=True) target = serializers.CharField(source='name.name', read_only=True)
class Meta(MxSerializer.Meta): class Meta(MxSerializer.Meta):
@ -520,11 +646,17 @@ class MXRecordSerializer(MxSerializer):
class TXTRecordSerializer(TxtSerializer): class TXTRecordSerializer(TxtSerializer):
"""Serialize `machines.models.Txt` objects with the data needed to
generate a TXT DNS record.
"""
class Meta(TxtSerializer.Meta): class Meta(TxtSerializer.Meta):
fields = ('field1', 'field2') fields = ('field1', 'field2')
class SRVRecordSerializer(SrvSerializer): class SRVRecordSerializer(SrvSerializer):
"""Serialize `machines.models.Srv` objects with the data needed to
generate a SRV DNS record.
"""
target = serializers.CharField(source='target.name', read_only=True) target = serializers.CharField(source='target.name', read_only=True)
class Meta(SrvSerializer.Meta): class Meta(SrvSerializer.Meta):
@ -532,6 +664,9 @@ class SRVRecordSerializer(SrvSerializer):
class ARecordSerializer(serializers.ModelSerializer): class ARecordSerializer(serializers.ModelSerializer):
"""Serialize `machines.models.Interface` objects with the data needed to
generate a A DNS record.
"""
hostname = serializers.CharField(source='domain.name', read_only=True) hostname = serializers.CharField(source='domain.name', read_only=True)
ipv4 = serializers.CharField(source='ipv4.ipv4', read_only=True) ipv4 = serializers.CharField(source='ipv4.ipv4', read_only=True)
@ -541,6 +676,9 @@ class ARecordSerializer(serializers.ModelSerializer):
class AAAARecordSerializer(serializers.ModelSerializer): class AAAARecordSerializer(serializers.ModelSerializer):
"""Serialize `machines.models.Interface` objects with the data needed to
generate a AAAA DNS record.
"""
hostname = serializers.CharField(source='domain.name', read_only=True) hostname = serializers.CharField(source='domain.name', read_only=True)
ipv6 = Ipv6ListSerializer(many=True, read_only=True) ipv6 = Ipv6ListSerializer(many=True, read_only=True)
@ -550,6 +688,9 @@ class AAAARecordSerializer(serializers.ModelSerializer):
class CNAMERecordSerializer(serializers.ModelSerializer): class CNAMERecordSerializer(serializers.ModelSerializer):
"""Serialize `machines.models.Domain` objects with the data needed to
generate a CNAME DNS record.
"""
alias = serializers.CharField(source='cname.name', read_only=True) alias = serializers.CharField(source='cname.name', read_only=True)
hostname = serializers.CharField(source='name', read_only=True) hostname = serializers.CharField(source='name', read_only=True)
@ -559,6 +700,8 @@ class CNAMERecordSerializer(serializers.ModelSerializer):
class DNSZonesSerializer(serializers.ModelSerializer): class DNSZonesSerializer(serializers.ModelSerializer):
"""Serialize the data about DNS Zones.
"""
soa = SOARecordSerializer() soa = SOARecordSerializer()
ns_records = NSRecordSerializer(many=True, source='ns_set') ns_records = NSRecordSerializer(many=True, source='ns_set')
originv4 = OriginV4RecordSerializer(source='origin') originv4 = OriginV4RecordSerializer(source='origin')
@ -577,14 +720,18 @@ class DNSZonesSerializer(serializers.ModelSerializer):
'aaaa_records', 'cname_records') 'aaaa_records', 'cname_records')
# Mailing # MAILING
class MailingMemberSerializer(UserSerializer): class MailingMemberSerializer(UserSerializer):
"""Serialize the data about a mailing member.
"""
class Meta(UserSerializer.Meta): class Meta(UserSerializer.Meta):
fields = ('name', 'pseudo', 'email') fields = ('name', 'pseudo', 'email')
class MailingSerializer(ClubSerializer): class MailingSerializer(ClubSerializer):
"""Serialize the data about a mailing.
"""
members = MailingMemberSerializer(many=True) members = MailingMemberSerializer(many=True)
admins = MailingMemberSerializer(source='administrators', many=True) admins = MailingMemberSerializer(source='administrators', many=True)

View file

@ -1,11 +1,8 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2017 Gabriel Détraz # Copyright © 2018 Maël Kervella
# Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -21,8 +18,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""api.settings """Settings specific to the API.
Django settings specific to the API.
""" """
# RestFramework config for API # RestFramework config for API
@ -49,4 +45,6 @@ API_PERMISSION_CODENAME = 'use_api'
API_APPS = ( API_APPS = (
'rest_framework.authtoken', 'rest_framework.authtoken',
) )
# The expiration time for an authentication token
API_TOKEN_DURATION = 86400 # 24 hours API_TOKEN_DURATION = 86400 # 24 hours

View file

@ -2,9 +2,7 @@
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2017 Gabriel Détraz # Copyright © 2018 Maël Kervella
# Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -19,8 +17,7 @@
# You should have received a copy of the GNU General Public License along # 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., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""api.tests """Defines the test suite for the API
The tests for the API module.
""" """
import json import json
@ -34,13 +31,25 @@ import users.models as users
class APIEndpointsTestCase(APITestCase): class APIEndpointsTestCase(APITestCase):
# URLs that don't require to be authenticated """Test case to test that all endpoints are reachable with respects to
authentication and permission checks.
Attributes:
no_auth_endpoints: A list of endpoints that should be reachable
without authentication.
auth_no_perm_endpoints: A list of endpoints that should be reachable
when being authenticated but without permissions.
auth_perm_endpoints: A list of endpoints that should be reachable
when being authenticated and having the correct permissions.
stduser: A standard user with no permission used for the tests and
initialized at the beggining of this test case.
superuser: A superuser (with all permissions) used for the tests and
initialized at the beggining of this test case.
"""
no_auth_endpoints = [ no_auth_endpoints = [
'/api/' '/api/'
] ]
# URLs that require to be authenticated and have no special permissions
auth_no_perm_endpoints = [] auth_no_perm_endpoints = []
# URLs that require to be authenticated and have special permissions
auth_perm_endpoints = [ auth_perm_endpoints = [
'/api/cotisations/articles/', '/api/cotisations/articles/',
# '/api/cotisations/articles/<pk>/', # '/api/cotisations/articles/<pk>/',
@ -160,49 +169,62 @@ class APIEndpointsTestCase(APITestCase):
cls.superuser.delete() cls.superuser.delete()
super().tearDownClass() super().tearDownClass()
def check_responses_code(self, urls, expected_code, formats=[None], def check_responses_code(self, urls, expected_code, formats=None,
assert_more=None): assert_more=None):
""" """Utility function to test if a list of urls answer an expected code.
Utility function to test if a list of urls answer an expected code
:param urls: (list) The list of urls to test Args:
:param expected_code: (int) The HTTP return code expected urls: The list of urls to test
:param formats: (list) The list of formats to use for the request expected_code: The HTTP return code expected
(Default: [None]) formats: The list of formats to use for the request. Default is to
:param assert_more: (func) A function to assert more specific data only test `None` format.
in the same test. It is evaluated with the responsem object, the assert_more: An optional function to assert more specific data in
url and the format used. the same test. The response object, the url and the format
used are passed as arguments.
Raises:
AssertionError: The response got did not have the expected status
code.
Any exception raised in the evalutation of `assert_more`.
""" """
if formats is None:
formats = [None]
for url in urls: for url in urls:
for format in formats: for format in formats:
with self.subTest(url=url, format=format): with self.subTest(url=url, format=format):
response = self.client.get(url, format=format) response = self.client.get(url, format=format)
assert response.status_code == expected_code assert response.status_code == expected_code
if assert_more: if assert_more is not None:
assert_more(response, url, format) assert_more(response, url, format)
def test_no_auth_endpoints_with_no_auth(self): def test_no_auth_endpoints_with_no_auth(self):
""" """Tests that every endpoint that does not require to be
Test that every endpoint that does not require to be authenticated, authenticated, returns a Ok (200) response when not authenticated.
returns a Ok (200) response when not authenticated.
Raises:
AssertionError: An endpoint did not have a 200 status code.
""" """
urls = [endpoint.replace('<pk>', '1') urls = [endpoint.replace('<pk>', '1')
for endpoint in self.no_auth_endpoints] for endpoint in self.no_auth_endpoints]
self.check_responses_code(urls, codes.ok) self.check_responses_code(urls, codes.ok)
def test_auth_endpoints_with_no_auth(self): def test_auth_endpoints_with_no_auth(self):
""" """Tests that every endpoint that does require to be authenticated,
Test that every endpoint that does require to be authenticated,
returns a Unauthorized (401) response when not authenticated. returns a Unauthorized (401) response when not authenticated.
Raises:
AssertionError: An endpoint did not have a 401 status code.
""" """
urls = [endpoint.replace('<pk>', '1') for endpoint in \ urls = [endpoint.replace('<pk>', '1') for endpoint in \
self.auth_no_perm_endpoints + self.auth_perm_endpoints] self.auth_no_perm_endpoints + self.auth_perm_endpoints]
self.check_responses_code(urls, codes.unauthorized) self.check_responses_code(urls, codes.unauthorized)
def test_no_auth_endpoints_with_auth(self): def test_no_auth_endpoints_with_auth(self):
""" """Tests that every endpoint that does not require to be
Test that every endpoint that does not require to be authenticated, authenticated, returns a Ok (200) response when authenticated.
returns a Ok (200) response when authenticated.
Raises:
AssertionError: An endpoint did not have a 200 status code.
""" """
self.client.force_authenticate(user=self.stduser) self.client.force_authenticate(user=self.stduser)
urls = [endpoint.replace('<pk>', '1') urls = [endpoint.replace('<pk>', '1')
@ -210,10 +232,12 @@ class APIEndpointsTestCase(APITestCase):
self.check_responses_code(urls, codes.ok) self.check_responses_code(urls, codes.ok)
def test_auth_no_perm_endpoints_with_auth_and_no_perm(self): def test_auth_no_perm_endpoints_with_auth_and_no_perm(self):
""" """Tests that every endpoint that does require to be authenticated and
Test that every endpoint that does require to be authenticated and no special permissions, returns a Ok (200) response when authenticated
no special permissions, returns a Ok (200) response when but without permissions.
authenticated but without permissions.
Raises:
AssertionError: An endpoint did not have a 200 status code.
""" """
self.client.force_authenticate(user=self.stduser) self.client.force_authenticate(user=self.stduser)
urls = [endpoint.replace('<pk>', '1') urls = [endpoint.replace('<pk>', '1')
@ -221,10 +245,12 @@ class APIEndpointsTestCase(APITestCase):
self.check_responses_code(urls, codes.ok) self.check_responses_code(urls, codes.ok)
def test_auth_perm_endpoints_with_auth_and_no_perm(self): def test_auth_perm_endpoints_with_auth_and_no_perm(self):
""" """Tests that every endpoint that does require to be authenticated and
Test that every endpoint that does require to be authenticated and
special permissions, returns a Forbidden (403) response when special permissions, returns a Forbidden (403) response when
authenticated but without permissions. authenticated but without permissions.
Raises:
AssertionError: An endpoint did not have a 403 status code.
""" """
self.client.force_authenticate(user=self.stduser) self.client.force_authenticate(user=self.stduser)
urls = [endpoint.replace('<pk>', '1') urls = [endpoint.replace('<pk>', '1')
@ -232,9 +258,11 @@ class APIEndpointsTestCase(APITestCase):
self.check_responses_code(urls, codes.forbidden) self.check_responses_code(urls, codes.forbidden)
def test_auth_endpoints_with_auth_and_perm(self): def test_auth_endpoints_with_auth_and_perm(self):
""" """Tests that every endpoint that does require to be authenticated,
Test that every endpoint that does require to be authenticated, returns a Ok (200) response when authenticated with all permissions.
returns a Ok (200) response when authenticated with all permissions
Raises:
AssertionError: An endpoint did not have a 200 status code.
""" """
self.client.force_authenticate(user=self.superuser) self.client.force_authenticate(user=self.superuser)
urls = [endpoint.replace('<pk>', '1') for endpoint \ urls = [endpoint.replace('<pk>', '1') for endpoint \
@ -242,10 +270,12 @@ class APIEndpointsTestCase(APITestCase):
self.check_responses_code(urls, codes.ok) self.check_responses_code(urls, codes.ok)
def test_endpoints_not_found(self): def test_endpoints_not_found(self):
""" """Tests that every endpoint that uses a primary key parameter,
Test that every endpoint that uses a primary key parameter,
returns a Not Found (404) response when queried with non-existing returns a Not Found (404) response when queried with non-existing
primary key primary key.
Raises:
AssertionError: An endpoint did not have a 404 status code.
""" """
self.client.force_authenticate(user=self.superuser) self.client.force_authenticate(user=self.superuser)
# Select only the URLs with '<pk>' and replace it with '42' # Select only the URLs with '<pk>' and replace it with '42'
@ -255,9 +285,12 @@ class APIEndpointsTestCase(APITestCase):
self.check_responses_code(urls, codes.not_found) self.check_responses_code(urls, codes.not_found)
def test_formats(self): def test_formats(self):
""" """Tests that every endpoint returns a Ok (200) response when using
Test that every endpoint returns a Ok (200) response when using different formats. Also checks that 'json' format returns a valid
different formats. Also checks that 'json' format returns a valid json JSON object.
Raises:
AssertionError: An endpoint did not have a 200 status code.
""" """
self.client.force_authenticate(user=self.superuser) self.client.force_authenticate(user=self.superuser)
@ -275,6 +308,14 @@ class APIEndpointsTestCase(APITestCase):
assert_more=assert_more) assert_more=assert_more)
class APIPaginationTestCase(APITestCase): class APIPaginationTestCase(APITestCase):
"""Test case to check that the pagination is used on all endpoints that
should use it.
Attributes:
endpoints: A list of endpoints that should use the pagination.
superuser: A superuser used in the tests to access the endpoints.
"""
endpoints = [ endpoints = [
'/api/cotisations/articles/', '/api/cotisations/articles/',
'/api/cotisations/banques/', '/api/cotisations/banques/',
@ -338,8 +379,12 @@ class APIPaginationTestCase(APITestCase):
super().tearDownClass() super().tearDownClass()
def test_pagination(self): def test_pagination(self):
""" """Tests that every endpoint is using the pagination correctly.
Test that every endpoint is using the pagination correctly
Raises:
AssertionError: An endpoint did not have one the following keyword
in the JSOn response: 'count', 'next', 'previous', 'results'
or more that 100 results were returned.
""" """
self.client.force_authenticate(self.superuser) self.client.force_authenticate(self.superuser)
for url in self.endpoints: for url in self.endpoints:

View file

@ -2,7 +2,7 @@
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2018 Mael Kervella # Copyright © 2018 Maël Kervella
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -17,27 +17,30 @@
# You should have received a copy of the GNU General Public License along # 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., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""api.urls
Urls de l'api, pointant vers les fonctions de views """Defines the URLs of the API
A custom router is used to register all the routes. That allows to register
all the URL patterns from the viewsets as a standard router but, the views
can also be register. That way a complete API root page presenting all URLs
can be generated automatically.
""" """
from __future__ import unicode_literals
from django.conf.urls import url, include from django.conf.urls import url, include
from .routers import AllViewsRouter
from . import views from . import views
from .routers import AllViewsRouter
router = AllViewsRouter() router = AllViewsRouter()
# COTISATIONS APP # COTISATIONS
router.register_viewset(r'cotisations/factures', views.FactureViewSet) router.register_viewset(r'cotisations/factures', views.FactureViewSet)
router.register_viewset(r'cotisations/ventes', views.VenteViewSet) router.register_viewset(r'cotisations/ventes', views.VenteViewSet)
router.register_viewset(r'cotisations/articles', views.ArticleViewSet) router.register_viewset(r'cotisations/articles', views.ArticleViewSet)
router.register_viewset(r'cotisations/banques', views.BanqueViewSet) router.register_viewset(r'cotisations/banques', views.BanqueViewSet)
router.register_viewset(r'cotisations/paiements', views.PaiementViewSet) router.register_viewset(r'cotisations/paiements', views.PaiementViewSet)
router.register_viewset(r'cotisations/cotisations', views.CotisationViewSet) router.register_viewset(r'cotisations/cotisations', views.CotisationViewSet)
# MACHINES APP # MACHINES
router.register_viewset(r'machines/machines', views.MachineViewSet) router.register_viewset(r'machines/machines', views.MachineViewSet)
router.register_viewset(r'machines/machinetypes', views.MachineTypeViewSet) router.register_viewset(r'machines/machinetypes', views.MachineTypeViewSet)
router.register_viewset(r'machines/iptypes', views.IpTypeViewSet) router.register_viewset(r'machines/iptypes', views.IpTypeViewSet)
@ -57,7 +60,7 @@ router.register_viewset(r'machines/services', views.ServiceViewSet)
router.register_viewset(r'machines/servicelinks', views.ServiceLinkViewSet, base_name='servicelink') router.register_viewset(r'machines/servicelinks', views.ServiceLinkViewSet, base_name='servicelink')
router.register_viewset(r'machines/ouvertureportlists', views.OuverturePortListViewSet) router.register_viewset(r'machines/ouvertureportlists', views.OuverturePortListViewSet)
router.register_viewset(r'machines/ouvertureports', views.OuverturePortViewSet) router.register_viewset(r'machines/ouvertureports', views.OuverturePortViewSet)
# PREFERENCES APP # PREFERENCES
router.register_viewset(r'preferences/service', views.ServiceViewSet), router.register_viewset(r'preferences/service', views.ServiceViewSet),
router.register_view(r'preferences/optionaluser', views.OptionalUserView), router.register_view(r'preferences/optionaluser', views.OptionalUserView),
router.register_view(r'preferences/optionalmachine', views.OptionalMachineView), router.register_view(r'preferences/optionalmachine', views.OptionalMachineView),
@ -66,7 +69,7 @@ router.register_view(r'preferences/generaloption', views.GeneralOptionView),
router.register_view(r'preferences/assooption', views.AssoOptionView), router.register_view(r'preferences/assooption', views.AssoOptionView),
router.register_view(r'preferences/homeoption', views.HomeOptionView), router.register_view(r'preferences/homeoption', views.HomeOptionView),
router.register_view(r'preferences/mailmessageoption', views.MailMessageOptionView), router.register_view(r'preferences/mailmessageoption', views.MailMessageOptionView),
# TOPOLOGIE APP # TOPOLOGIE
router.register_viewset(r'topologie/stack', views.StackViewSet) router.register_viewset(r'topologie/stack', views.StackViewSet)
router.register_viewset(r'topologie/acesspoint', views.AccessPointViewSet) router.register_viewset(r'topologie/acesspoint', views.AccessPointViewSet)
router.register_viewset(r'topologie/switch', views.SwitchViewSet) router.register_viewset(r'topologie/switch', views.SwitchViewSet)
@ -76,7 +79,7 @@ router.register_viewset(r'topologie/switchbay', views.SwitchBayViewSet)
router.register_viewset(r'topologie/building', views.BuildingViewSet) router.register_viewset(r'topologie/building', views.BuildingViewSet)
router.register_viewset(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport') router.register_viewset(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport')
router.register_viewset(r'topologie/room', views.RoomViewSet) router.register_viewset(r'topologie/room', views.RoomViewSet)
# USERS APP # USERS
router.register_viewset(r'users/users', views.UserViewSet) router.register_viewset(r'users/users', views.UserViewSet)
router.register_viewset(r'users/clubs', views.ClubViewSet) router.register_viewset(r'users/clubs', views.ClubViewSet)
router.register_viewset(r'users/adherents', views.AdherentViewSet) router.register_viewset(r'users/adherents', views.AdherentViewSet)
@ -86,7 +89,7 @@ router.register_viewset(r'users/listrights', views.ListRightViewSet)
router.register_viewset(r'users/shells', views.ShellViewSet, base_name='shell') router.register_viewset(r'users/shells', views.ShellViewSet, base_name='shell')
router.register_viewset(r'users/bans', views.BanViewSet) router.register_viewset(r'users/bans', views.BanViewSet)
router.register_viewset(r'users/whitelists', views.WhitelistViewSet) router.register_viewset(r'users/whitelists', views.WhitelistViewSet)
# SERVICES REGEN # SERVICE REGEN
router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen') router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen')
# DHCP # DHCP
router.register_view(r'dhcp/hostmacip', views.HostMacIpView), router.register_view(r'dhcp/hostmacip', views.HostMacIpView),
@ -95,7 +98,7 @@ router.register_view(r'dns/zones', views.DNSZonesView),
# MAILING # MAILING
router.register_view(r'mailing/standard', views.StandardMailingView), router.register_view(r'mailing/standard', views.StandardMailingView),
router.register_view(r'mailing/club', views.ClubMailingView), router.register_view(r'mailing/club', views.ClubMailingView),
# TOKEN-AUTH # TOKEN AUTHENTICATION
router.register_view(r'token-auth', views.ObtainExpiringAuthToken) router.register_view(r'token-auth', views.ObtainExpiringAuthToken)

View file

@ -18,16 +18,16 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""api.views """Defines the views of the API
The views for the API app. They should all return JSON data and not fallback on All views inherits the `rest_framework.views.APIview` to respect the
HTML pages such as the login and index pages for a better integration. REST API requirements such as dealing with HTTP status code, format of
the response (JSON or other), the CSRF exempting, ...
""" """
import datetime import datetime
from django.conf import settings from django.conf import settings
from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from rest_framework.response import Response from rest_framework.response import Response
@ -38,7 +38,6 @@ import machines.models as machines
import preferences.models as preferences import preferences.models as preferences
import topologie.models as topologie import topologie.models as topologie
import users.models as users import users.models as users
from re2o.utils import all_active_interfaces, all_has_access from re2o.utils import all_active_interfaces, all_has_access
from . import serializers from . import serializers
@ -46,142 +45,195 @@ from .pagination import PageSizedPagination
from .permissions import ACLPermission from .permissions import ACLPermission
# COTISATIONS APP # COTISATIONS
class FactureViewSet(viewsets.ReadOnlyModelViewSet): class FactureViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Facture` objects.
"""
queryset = cotisations.Facture.objects.all() queryset = cotisations.Facture.objects.all()
serializer_class = serializers.FactureSerializer serializer_class = serializers.FactureSerializer
class VenteViewSet(viewsets.ReadOnlyModelViewSet): class VenteViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Vente` objects.
"""
queryset = cotisations.Vente.objects.all() queryset = cotisations.Vente.objects.all()
serializer_class = serializers.VenteSerializer serializer_class = serializers.VenteSerializer
class ArticleViewSet(viewsets.ReadOnlyModelViewSet): class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Article` objects.
"""
queryset = cotisations.Article.objects.all() queryset = cotisations.Article.objects.all()
serializer_class = serializers.ArticleSerializer serializer_class = serializers.ArticleSerializer
class BanqueViewSet(viewsets.ReadOnlyModelViewSet): class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Banque` objects.
"""
queryset = cotisations.Banque.objects.all() queryset = cotisations.Banque.objects.all()
serializer_class = serializers.BanqueSerializer serializer_class = serializers.BanqueSerializer
class PaiementViewSet(viewsets.ReadOnlyModelViewSet): class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Paiement` objects.
"""
queryset = cotisations.Paiement.objects.all() queryset = cotisations.Paiement.objects.all()
serializer_class = serializers.PaiementSerializer serializer_class = serializers.PaiementSerializer
class CotisationViewSet(viewsets.ReadOnlyModelViewSet): class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Cotisation` objects.
"""
queryset = cotisations.Cotisation.objects.all() queryset = cotisations.Cotisation.objects.all()
serializer_class = serializers.CotisationSerializer serializer_class = serializers.CotisationSerializer
# MACHINES APP # MACHINES
class MachineViewSet(viewsets.ReadOnlyModelViewSet): class MachineViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Machine` objects.
"""
queryset = machines.Machine.objects.all() queryset = machines.Machine.objects.all()
serializer_class = serializers.MachineSerializer serializer_class = serializers.MachineSerializer
class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet): class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.MachineType` objects.
"""
queryset = machines.MachineType.objects.all() queryset = machines.MachineType.objects.all()
serializer_class = serializers.MachineTypeSerializer serializer_class = serializers.MachineTypeSerializer
class IpTypeViewSet(viewsets.ReadOnlyModelViewSet): class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.IpType` objects.
"""
queryset = machines.IpType.objects.all() queryset = machines.IpType.objects.all()
serializer_class = serializers.IpTypeSerializer serializer_class = serializers.IpTypeSerializer
class VlanViewSet(viewsets.ReadOnlyModelViewSet): class VlanViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Vlan` objects.
"""
queryset = machines.Vlan.objects.all() queryset = machines.Vlan.objects.all()
serializer_class = serializers.VlanSerializer serializer_class = serializers.VlanSerializer
class NasViewSet(viewsets.ReadOnlyModelViewSet): class NasViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Nas` objects.
"""
queryset = machines.Nas.objects.all() queryset = machines.Nas.objects.all()
serializer_class = serializers.NasSerializer serializer_class = serializers.NasSerializer
class SOAViewSet(viewsets.ReadOnlyModelViewSet): class SOAViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.SOA` objects.
"""
queryset = machines.SOA.objects.all() queryset = machines.SOA.objects.all()
serializer_class = serializers.SOASerializer serializer_class = serializers.SOASerializer
class ExtensionViewSet(viewsets.ReadOnlyModelViewSet): class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Extension` objects.
"""
queryset = machines.Extension.objects.all() queryset = machines.Extension.objects.all()
serializer_class = serializers.ExtensionSerializer serializer_class = serializers.ExtensionSerializer
class MxViewSet(viewsets.ReadOnlyModelViewSet): class MxViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Mx` objects.
"""
queryset = machines.Mx.objects.all() queryset = machines.Mx.objects.all()
serializer_class = serializers.MxSerializer serializer_class = serializers.MxSerializer
class NsViewSet(viewsets.ReadOnlyModelViewSet): class NsViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Ns` objects.
"""
queryset = machines.Ns.objects.all() queryset = machines.Ns.objects.all()
serializer_class = serializers.NsSerializer serializer_class = serializers.NsSerializer
class TxtViewSet(viewsets.ReadOnlyModelViewSet): class TxtViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Txt` objects.
"""
queryset = machines.Txt.objects.all() queryset = machines.Txt.objects.all()
serializer_class = serializers.TxtSerializer serializer_class = serializers.TxtSerializer
class SrvViewSet(viewsets.ReadOnlyModelViewSet): class SrvViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Srv` objects.
"""
queryset = machines.Srv.objects.all() queryset = machines.Srv.objects.all()
serializer_class = serializers.SrvSerializer serializer_class = serializers.SrvSerializer
class InterfaceViewSet(viewsets.ReadOnlyModelViewSet): class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Interface` objects.
"""
queryset = machines.Interface.objects.all() queryset = machines.Interface.objects.all()
serializer_class = serializers.InterfaceSerializer serializer_class = serializers.InterfaceSerializer
class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet): class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Ipv6List` objects.
"""
queryset = machines.Ipv6List.objects.all() queryset = machines.Ipv6List.objects.all()
serializer_class = serializers.Ipv6ListSerializer serializer_class = serializers.Ipv6ListSerializer
class DomainViewSet(viewsets.ReadOnlyModelViewSet): class DomainViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Domain` objects.
"""
queryset = machines.Domain.objects.all() queryset = machines.Domain.objects.all()
serializer_class = serializers.DomainSerializer serializer_class = serializers.DomainSerializer
class IpListViewSet(viewsets.ReadOnlyModelViewSet): class IpListViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.IpList` objects.
"""
queryset = machines.IpList.objects.all() queryset = machines.IpList.objects.all()
serializer_class = serializers.IpListSerializer serializer_class = serializers.IpListSerializer
class ServiceViewSet(viewsets.ReadOnlyModelViewSet): class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Service` objects.
"""
queryset = machines.Service.objects.all() queryset = machines.Service.objects.all()
serializer_class = serializers.ServiceSerializer serializer_class = serializers.ServiceSerializer
class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet): class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Service_link` objects.
"""
queryset = machines.Service_link.objects.all() queryset = machines.Service_link.objects.all()
serializer_class = serializers.ServiceLinkSerializer serializer_class = serializers.ServiceLinkSerializer
class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet): class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.OuverturePortList`
objects.
"""
queryset = machines.OuverturePortList.objects.all() queryset = machines.OuverturePortList.objects.all()
serializer_class = serializers.OuverturePortListSerializer serializer_class = serializers.OuverturePortListSerializer
class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet): class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.OuverturePort` objects.
"""
queryset = machines.OuverturePort.objects.all() queryset = machines.OuverturePort.objects.all()
serializer_class = serializers.OuverturePortSerializer serializer_class = serializers.OuverturePortSerializer
# PREFERENCES APP # PREFERENCES
# Those views differ a bit because there is only one object # Those views differ a bit because there is only one object
# to display, so we don't bother with the listing part # to display, so we don't bother with the listing part
class OptionalUserView(generics.RetrieveAPIView): class OptionalUserView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.OptionalUser.can_view_all]} perms_map = {'GET' : [preferences.OptionalUser.can_view_all]}
serializer_class = serializers.OptionalUserSerializer serializer_class = serializers.OptionalUserSerializer
@ -191,6 +243,8 @@ class OptionalUserView(generics.RetrieveAPIView):
class OptionalMachineView(generics.RetrieveAPIView): class OptionalMachineView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.OptionalMachine` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.OptionalMachine.can_view_all]} perms_map = {'GET' : [preferences.OptionalMachine.can_view_all]}
serializer_class = serializers.OptionalMachineSerializer serializer_class = serializers.OptionalMachineSerializer
@ -200,6 +254,8 @@ class OptionalMachineView(generics.RetrieveAPIView):
class OptionalTopologieView(generics.RetrieveAPIView): class OptionalTopologieView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.OptionalTopologie` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.OptionalTopologie.can_view_all]} perms_map = {'GET' : [preferences.OptionalTopologie.can_view_all]}
serializer_class = serializers.OptionalTopologieSerializer serializer_class = serializers.OptionalTopologieSerializer
@ -209,6 +265,8 @@ class OptionalTopologieView(generics.RetrieveAPIView):
class GeneralOptionView(generics.RetrieveAPIView): class GeneralOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.GeneralOption` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.GeneralOption.can_view_all]} perms_map = {'GET' : [preferences.GeneralOption.can_view_all]}
serializer_class = serializers.GeneralOptionSerializer serializer_class = serializers.GeneralOptionSerializer
@ -218,11 +276,15 @@ class GeneralOptionView(generics.RetrieveAPIView):
class ServiceViewSet(viewsets.ReadOnlyModelViewSet): class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `preferences.models.Service` objects.
"""
queryset = preferences.Service.objects.all() queryset = preferences.Service.objects.all()
serializer_class = serializers.ServiceSerializer serializer_class = serializers.ServiceSerializer
class AssoOptionView(generics.RetrieveAPIView): class AssoOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.AssoOption` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.AssoOption.can_view_all]} perms_map = {'GET' : [preferences.AssoOption.can_view_all]}
serializer_class = serializers.AssoOptionSerializer serializer_class = serializers.AssoOptionSerializer
@ -232,6 +294,8 @@ class AssoOptionView(generics.RetrieveAPIView):
class HomeOptionView(generics.RetrieveAPIView): class HomeOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.HomeOption` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.HomeOption.can_view_all]} perms_map = {'GET' : [preferences.HomeOption.can_view_all]}
serializer_class = serializers.HomeOptionSerializer serializer_class = serializers.HomeOptionSerializer
@ -241,6 +305,8 @@ class HomeOptionView(generics.RetrieveAPIView):
class MailMessageOptionView(generics.RetrieveAPIView): class MailMessageOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.MailMessageOption` settings.
"""
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [preferences.MailMessageOption.can_view_all]} perms_map = {'GET' : [preferences.MailMessageOption.can_view_all]}
serializer_class = serializers.MailMessageOptionSerializer serializer_class = serializers.MailMessageOptionSerializer
@ -249,106 +315,145 @@ class MailMessageOptionView(generics.RetrieveAPIView):
return preferences.MailMessageOption.objects.first() return preferences.MailMessageOption.objects.first()
# TOPOLOGIE APP # TOPOLOGIE
class StackViewSet(viewsets.ReadOnlyModelViewSet): class StackViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Stack` objects.
"""
queryset = topologie.Stack.objects.all() queryset = topologie.Stack.objects.all()
serializer_class = serializers.StackSerializer serializer_class = serializers.StackSerializer
class AccessPointViewSet(viewsets.ReadOnlyModelViewSet): class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.AccessPoint` objects.
"""
queryset = topologie.AccessPoint.objects.all() queryset = topologie.AccessPoint.objects.all()
serializer_class = serializers.AccessPointSerializer serializer_class = serializers.AccessPointSerializer
class SwitchViewSet(viewsets.ReadOnlyModelViewSet): class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Switch` objects.
"""
queryset = topologie.Switch.objects.all() queryset = topologie.Switch.objects.all()
serializer_class = serializers.SwitchSerializer serializer_class = serializers.SwitchSerializer
class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet): class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.ModelSwitch` objects.
"""
queryset = topologie.ModelSwitch.objects.all() queryset = topologie.ModelSwitch.objects.all()
serializer_class = serializers.ModelSwitchSerializer serializer_class = serializers.ModelSwitchSerializer
class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet): class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.ConstructorSwitch`
objects.
"""
queryset = topologie.ConstructorSwitch.objects.all() queryset = topologie.ConstructorSwitch.objects.all()
serializer_class = serializers.ConstructorSwitchSerializer serializer_class = serializers.ConstructorSwitchSerializer
class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet): class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.SwitchBay` objects.
"""
queryset = topologie.SwitchBay.objects.all() queryset = topologie.SwitchBay.objects.all()
serializer_class = serializers.SwitchBaySerializer serializer_class = serializers.SwitchBaySerializer
class BuildingViewSet(viewsets.ReadOnlyModelViewSet): class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Building` objects.
"""
queryset = topologie.Building.objects.all() queryset = topologie.Building.objects.all()
serializer_class = serializers.BuildingSerializer serializer_class = serializers.BuildingSerializer
class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet): class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Port` objects.
"""
queryset = topologie.Port.objects.all() queryset = topologie.Port.objects.all()
serializer_class = serializers.SwitchPortSerializer serializer_class = serializers.SwitchPortSerializer
class RoomViewSet(viewsets.ReadOnlyModelViewSet): class RoomViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Room` objects.
"""
queryset = topologie.Room.objects.all() queryset = topologie.Room.objects.all()
serializer_class = serializers.RoomSerializer serializer_class = serializers.RoomSerializer
# USER APP # USER
class UserViewSet(viewsets.ReadOnlyModelViewSet): class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Users` objects.
"""
queryset = users.User.objects.all() queryset = users.User.objects.all()
serializer_class = serializers.UserSerializer serializer_class = serializers.UserSerializer
class ClubViewSet(viewsets.ReadOnlyModelViewSet): class ClubViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Club` objects.
"""
queryset = users.Club.objects.all() queryset = users.Club.objects.all()
serializer_class = serializers.ClubSerializer serializer_class = serializers.ClubSerializer
class AdherentViewSet(viewsets.ReadOnlyModelViewSet): class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Adherent` objects.
"""
queryset = users.Adherent.objects.all() queryset = users.Adherent.objects.all()
serializer_class = serializers.AdherentSerializer serializer_class = serializers.AdherentSerializer
class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet): class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.ServiceUser` objects.
"""
queryset = users.ServiceUser.objects.all() queryset = users.ServiceUser.objects.all()
serializer_class = serializers.ServiceUserSerializer serializer_class = serializers.ServiceUserSerializer
class SchoolViewSet(viewsets.ReadOnlyModelViewSet): class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.School` objects.
"""
queryset = users.School.objects.all() queryset = users.School.objects.all()
serializer_class = serializers.SchoolSerializer serializer_class = serializers.SchoolSerializer
class ListRightViewSet(viewsets.ReadOnlyModelViewSet): class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.ListRight` objects.
"""
queryset = users.ListRight.objects.all() queryset = users.ListRight.objects.all()
serializer_class = serializers.ListRightSerializer serializer_class = serializers.ListRightSerializer
class ShellViewSet(viewsets.ReadOnlyModelViewSet): class ShellViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.ListShell` objects.
"""
queryset = users.ListShell.objects.all() queryset = users.ListShell.objects.all()
serializer_class = serializers.ShellSerializer serializer_class = serializers.ShellSerializer
class BanViewSet(viewsets.ReadOnlyModelViewSet): class BanViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Ban` objects.
"""
queryset = users.Ban.objects.all() queryset = users.Ban.objects.all()
serializer_class = serializers.BanSerializer serializer_class = serializers.BanSerializer
class WhitelistViewSet(viewsets.ReadOnlyModelViewSet): class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Whitelist` objects.
"""
queryset = users.Whitelist.objects.all() queryset = users.Whitelist.objects.all()
serializer_class = serializers.WhitelistSerializer serializer_class = serializers.WhitelistSerializer
# Services views # SERVICE REGEN
class ServiceRegenViewSet(viewsets.ModelViewSet): class ServiceRegenViewSet(viewsets.ModelViewSet):
"""Exposes list and details of the services to regen
"""
serializer_class = serializers.ServiceRegenSerializer serializer_class = serializers.ServiceRegenSerializer
def get_queryset(self): def get_queryset(self):
@ -363,24 +468,33 @@ class ServiceRegenViewSet(viewsets.ModelViewSet):
return queryset return queryset
# DHCP views # DHCP
class HostMacIpView(generics.ListAPIView): class HostMacIpView(generics.ListAPIView):
"""Exposes the associations between hostname, mac address and IPv4 in
order to build the DHCP lease files.
"""
queryset = all_active_interfaces() queryset = all_active_interfaces()
serializer_class = serializers.HostMacIpSerializer serializer_class = serializers.HostMacIpSerializer
# DNS views # DNS
class DNSZonesView(generics.ListAPIView): class DNSZonesView(generics.ListAPIView):
"""Exposes the detailed information about each extension (hostnames,
IPs, DNS records, etc.) in order to build the DNS zone files.
"""
queryset = machines.Extension.objects.all() queryset = machines.Extension.objects.all()
serializer_class = serializers.DNSZonesSerializer serializer_class = serializers.DNSZonesSerializer
# Mailing views # MAILING
class StandardMailingView(views.APIView): class StandardMailingView(views.APIView):
"""Exposes list and details of standard mailings (name and members) in
order to building the corresponding mailing lists.
"""
pagination_class = PageSizedPagination pagination_class = PageSizedPagination
permission_classes = (ACLPermission, ) permission_classes = (ACLPermission, )
perms_map = {'GET' : [users.User.can_view_all]} perms_map = {'GET' : [users.User.can_view_all]}
@ -394,13 +508,23 @@ class StandardMailingView(views.APIView):
class ClubMailingView(generics.ListAPIView): class ClubMailingView(generics.ListAPIView):
"""Exposes list and details of club mailings (name, members and admins) in
order to build the corresponding mailing lists.
"""
queryset = users.Club.objects.all() queryset = users.Club.objects.all()
serializer_class = serializers.MailingSerializer serializer_class = serializers.MailingSerializer
# Subclass the standard rest_framework.auth_token.views.ObtainAuthToken # TOKEN AUTHENTICATION
# in order to renew the lease of the token and add expiration time
class ObtainExpiringAuthToken(ObtainAuthToken): class ObtainExpiringAuthToken(ObtainAuthToken):
"""Exposes a view to obtain a authentication token.
This view as the same behavior as the
`rest_framework.auth_token.views.ObtainAuthToken` view except that the
expiration time is send along with the token as an addtional information.
"""
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)