mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-08-19 21:53:41 +00:00
Docstrings, docstrings everywhere
This commit is contained in:
parent
374dd8da1e
commit
ecc5ed0b22
10 changed files with 716 additions and 165 deletions
52
api/acl.py
52
api/acl.py
|
@ -1,9 +1,8 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# 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
|
||||
# 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
|
||||
|
@ -19,34 +18,41 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 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.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
# Creates the 'use_api' permission if not created
|
||||
# The 'use_api' is a fake permission in the sense
|
||||
# it is not associated with an existing model and
|
||||
# this ensure the permission is created every tun
|
||||
api_content_type, created = ContentType.objects.get_or_create(
|
||||
app_label=settings.API_CONTENT_TYPE_APP_LABEL,
|
||||
model=settings.API_CONTENT_TYPE_MODEL
|
||||
)
|
||||
if created:
|
||||
api_content_type.save()
|
||||
api_permission, created = Permission.objects.get_or_create(
|
||||
name=settings.API_PERMISSION_NAME,
|
||||
content_type=api_content_type,
|
||||
codename=settings.API_PERMISSION_CODENAME
|
||||
)
|
||||
if created:
|
||||
api_permission.save()
|
||||
def _create_api_permission():
|
||||
"""Creates the 'use_api' permission if not created.
|
||||
|
||||
The 'use_api' is a fake permission in the sense it is not associated with an
|
||||
existing model and this ensure the permission is created every time this file
|
||||
is imported.
|
||||
"""
|
||||
api_content_type, created = ContentType.objects.get_or_create(
|
||||
app_label=settings.API_CONTENT_TYPE_APP_LABEL,
|
||||
model=settings.API_CONTENT_TYPE_MODEL
|
||||
)
|
||||
if created:
|
||||
api_content_type.save()
|
||||
api_permission, created = Permission.objects.get_or_create(
|
||||
name=settings.API_PERMISSION_NAME,
|
||||
content_type=api_content_type,
|
||||
codename=settings.API_PERMISSION_CODENAME
|
||||
)
|
||||
if created:
|
||||
api_permission.save()
|
||||
|
||||
|
||||
_create_api_permission()
|
||||
|
||||
|
||||
def can_view(user):
|
||||
|
@ -64,4 +70,4 @@ def can_view(user):
|
|||
'codename': settings.API_PERMISSION_CODENAME
|
||||
}
|
||||
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.")
|
||||
|
|
|
@ -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
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.authentication import TokenAuthentication
|
||||
from rest_framework import exceptions
|
||||
|
||||
class ExpiringTokenAuthentication(TokenAuthentication):
|
||||
"""Authenticate a user if the provided token is valid and not expired.
|
||||
"""
|
||||
def authenticate_credentials(self, key):
|
||||
model = self.get_model()
|
||||
try:
|
||||
token = model.objects.select_related('user').get(key=key)
|
||||
except model.DoesNotExist:
|
||||
raise exceptions.AuthenticationFailed(_('Invalid token.'))
|
||||
|
||||
if not token.user.is_active:
|
||||
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
|
||||
"""See base class. Add the verification the token is not expired.
|
||||
"""
|
||||
base = super(ExpiringTokenAuthentication, self)
|
||||
user, token = base.authenticate_credentials(key)
|
||||
|
||||
# Check that the genration time of the token is not too old
|
||||
token_duration = datetime.timedelta(
|
||||
seconds=settings.API_TOKEN_DURATION
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
class PageSizedPagination(pagination.PageNumberPagination):
|
||||
"""
|
||||
Pagination subclass to all to control the page size
|
||||
"""Provide the possibility to control the page size by using the
|
||||
'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'
|
||||
all_pages_strings = ('all',)
|
||||
max_page_size = 10000
|
||||
|
||||
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:
|
||||
page_size_str = request.query_params[self.page_size_query_param]
|
||||
if page_size_str in self.all_pages_strings:
|
||||
|
|
|
@ -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 re2o.acl import can_create, can_edit, can_delete, can_view_all
|
||||
|
||||
from . import acl
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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) \
|
||||
or getattr(view, param_name, None) is not None, (
|
||||
'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):
|
||||
"""
|
||||
Permission subclass for views that requires a specific model-based
|
||||
permission or don't define a queryset
|
||||
"""A permission class used to check the ACL to validate the permissions
|
||||
of a user.
|
||||
|
||||
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):
|
||||
"""
|
||||
Given a list of models and an HTTP method, return the list
|
||||
of acl functions that the user is required to verify.
|
||||
"""Build the list of permissions required for the request to be
|
||||
accepted.
|
||||
|
||||
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')
|
||||
|
||||
|
@ -42,6 +105,22 @@ class ACLPermission(permissions.BasePermission):
|
|||
return [can_see_api()] + list(perms_map[method])
|
||||
|
||||
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
|
||||
# to the root view when using DefaultRouter.
|
||||
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)
|
||||
|
||||
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):
|
||||
"""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 = {
|
||||
'GET': [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):
|
||||
"""
|
||||
Given a model and an HTTP method, return the list of acl
|
||||
functions that the user is required to verify.
|
||||
"""Build the list of model-based permissions required for the
|
||||
request to be accepted.
|
||||
|
||||
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:
|
||||
raise exceptions.MethodNotAllowed(method)
|
||||
|
@ -97,9 +188,20 @@ class AutodetectACLPermission(permissions.BasePermission):
|
|||
return [perm(model) for perm in self.perms_map[method]]
|
||||
|
||||
def get_required_object_permissions(self, method, obj):
|
||||
"""
|
||||
Given an object and an HTTP method, return the list of acl
|
||||
functions that the user is required to verify.
|
||||
"""Build the list of object-based permissions required for the
|
||||
request to be accepted.
|
||||
|
||||
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:
|
||||
raise exceptions.MethodNotAllowed(method)
|
||||
|
@ -107,13 +209,26 @@ class AutodetectACLPermission(permissions.BasePermission):
|
|||
return [perm(obj) for perm in self.perms_obj_map[method]]
|
||||
|
||||
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')
|
||||
|
||||
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
|
||||
# to the root view when using DefaultRouter.
|
||||
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)
|
||||
|
||||
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
|
||||
queryset = self._queryset(view)
|
||||
user = request.user
|
||||
|
||||
perms = self.get_required_object_permissions(request.method, obj)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2018 Mael Kervella
|
||||
# Copyright © 2018 Mael 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
|
||||
|
@ -17,12 +17,12 @@
|
|||
# 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.
|
||||
"""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 django.conf.urls import url, include
|
||||
from django.core.urlresolvers import NoReverseMatch
|
||||
from rest_framework import views
|
||||
|
@ -32,32 +32,60 @@ from rest_framework.reverse import reverse
|
|||
from rest_framework.schemas import SchemaGenerator
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
|
||||
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):
|
||||
self.view_registry = []
|
||||
super(AllViewsRouter, self).__init__(*args, **kwargs)
|
||||
|
||||
def register_viewset(self, *args, **kwargs):
|
||||
"""
|
||||
Register a viewset in the router
|
||||
Alias of `register` for convenience
|
||||
"""Register a viewset in the router. Alias of `register` for
|
||||
convenience.
|
||||
|
||||
See `register` in the base class for details.
|
||||
"""
|
||||
return self.register(*args, **kwargs)
|
||||
|
||||
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:
|
||||
name = self.get_default_name(pattern)
|
||||
self.view_registry.append((pattern, view, name))
|
||||
|
||||
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]
|
||||
|
||||
def get_api_root_view(self, schema_urls=None):
|
||||
"""
|
||||
Return a view to use as the API root.
|
||||
"""Create a class-based 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()
|
||||
list_name = self.routes[0].name
|
||||
|
@ -115,6 +143,12 @@ class AllViewsRouter(DefaultRouter):
|
|||
return APIRoot.as_view()
|
||||
|
||||
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()
|
||||
|
||||
for pattern, view, name in self.view_registry:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2018 Mael Kervella
|
||||
# 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
|
||||
|
@ -18,8 +18,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
"""
|
||||
Serializers for the API app
|
||||
"""Defines the serializers of the API
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
@ -31,12 +30,15 @@ import topologie.models as topologie
|
|||
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'
|
||||
|
||||
|
||||
class NamespacedHRField(serializers.HyperlinkedRelatedField):
|
||||
""" A HyperlinkedRelatedField subclass to automatically prefix
|
||||
view names with a namespace """
|
||||
"""A `rest_framework.serializers.HyperlinkedRelatedField` subclass to
|
||||
automatically prefix view names with the API namespace.
|
||||
"""
|
||||
def __init__(self, view_name=None, **kwargs):
|
||||
if view_name is not None:
|
||||
view_name = '%s:%s' % (API_NAMESPACE, view_name)
|
||||
|
@ -44,8 +46,9 @@ class NamespacedHRField(serializers.HyperlinkedRelatedField):
|
|||
|
||||
|
||||
class NamespacedHIField(serializers.HyperlinkedIdentityField):
|
||||
""" A HyperlinkedIdentityField subclass to automatically prefix
|
||||
view names with a namespace """
|
||||
"""A `rest_framework.serializers.HyperlinkedIdentityField` subclass to
|
||||
automatically prefix view names with teh API namespace.
|
||||
"""
|
||||
def __init__(self, view_name=None, **kwargs):
|
||||
if view_name is not None:
|
||||
view_name = '%s:%s' % (API_NAMESPACE, view_name)
|
||||
|
@ -53,16 +56,19 @@ class NamespacedHIField(serializers.HyperlinkedIdentityField):
|
|||
|
||||
|
||||
class NamespacedHMSerializer(serializers.HyperlinkedModelSerializer):
|
||||
""" A HyperlinkedModelSerializer subclass to use `NamespacedHRField` as
|
||||
field and automatically prefix view names with a namespace """
|
||||
"""A `rest_framework.serializers.HyperlinkedModelSerializer` subclass to
|
||||
automatically prefix view names with the API namespace.
|
||||
"""
|
||||
serializer_related_field = NamespacedHRField
|
||||
serializer_url_field = NamespacedHIField
|
||||
|
||||
|
||||
# COTISATIONS APP
|
||||
# COTISATIONS
|
||||
|
||||
|
||||
class FactureSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Facture` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = cotisations.Facture
|
||||
fields = ('user', 'paiement', 'banque', 'cheque', 'date', 'valid',
|
||||
|
@ -70,6 +76,8 @@ class FactureSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class VenteSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Vente` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = cotisations.Vente
|
||||
fields = ('facture', 'number', 'name', 'prix', 'duration',
|
||||
|
@ -77,6 +85,8 @@ class VenteSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ArticleSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Article` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = cotisations.Article
|
||||
fields = ('name', 'prix', 'duration', 'type_user',
|
||||
|
@ -84,40 +94,52 @@ class ArticleSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class BanqueSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Banque` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = cotisations.Banque
|
||||
fields = ('name', 'api_url')
|
||||
|
||||
|
||||
class PaiementSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Paiement` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = cotisations.Paiement
|
||||
fields = ('moyen', 'type_paiement', 'api_url')
|
||||
|
||||
|
||||
class CotisationSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Cotisation` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = cotisations.Cotisation
|
||||
fields = ('vente', 'type_cotisation', 'date_start', 'date_end',
|
||||
'api_url')
|
||||
|
||||
|
||||
# MACHINES APP
|
||||
# MACHINES
|
||||
|
||||
|
||||
class MachineSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Machine` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Machine
|
||||
fields = ('user', 'name', 'active', 'api_url')
|
||||
|
||||
|
||||
class MachineTypeSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.MachineType` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.MachineType
|
||||
fields = ('type', 'ip_type', 'api_url')
|
||||
|
||||
|
||||
class IpTypeSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.IpType` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.IpType
|
||||
fields = ('type', 'extension', 'need_infra', 'domaine_ip_start',
|
||||
|
@ -126,12 +148,16 @@ class IpTypeSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class VlanSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Vlan` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Vlan
|
||||
fields = ('vlan_id', 'name', 'comment', 'api_url')
|
||||
|
||||
|
||||
class NasSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Nas` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Nas
|
||||
fields = ('name', 'nas_type', 'machine_type', 'port_access_mode',
|
||||
|
@ -139,6 +165,8 @@ class NasSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class SOASerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.SOA` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.SOA
|
||||
fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl',
|
||||
|
@ -146,6 +174,8 @@ class SOASerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ExtensionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Extension` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Extension
|
||||
fields = ('name', 'need_infra', 'origin', 'origin_v6', 'soa',
|
||||
|
@ -153,24 +183,32 @@ class ExtensionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class MxSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Mx` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Mx
|
||||
fields = ('zone', 'priority', 'name', 'api_url')
|
||||
|
||||
|
||||
class NsSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Ns` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Ns
|
||||
fields = ('zone', 'ns', 'api_url')
|
||||
|
||||
|
||||
class TxtSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Txt` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Txt
|
||||
fields = ('zone', 'field1', 'field2', 'api_url')
|
||||
|
||||
|
||||
class SrvSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Srv` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Srv
|
||||
fields = ('service', 'protocole', 'extension', 'ttl', 'priority',
|
||||
|
@ -178,6 +216,8 @@ class SrvSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class InterfaceSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Interface` objects.
|
||||
"""
|
||||
mac_address = serializers.CharField()
|
||||
active = serializers.BooleanField(source='is_active')
|
||||
|
||||
|
@ -188,12 +228,16 @@ class InterfaceSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class Ipv6ListSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Ipv6List` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Ipv6List
|
||||
fields = ('ipv6', 'interface', 'slaac_ip', 'api_url')
|
||||
|
||||
|
||||
class DomainSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Domain` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Domain
|
||||
fields = ('interface_parent', 'name', 'extension', 'cname',
|
||||
|
@ -201,12 +245,16 @@ class DomainSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class IpListSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.IpList` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.IpList
|
||||
fields = ('ipv4', 'ip_type', 'need_infra', 'api_url')
|
||||
|
||||
|
||||
class ServiceSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Service` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Service
|
||||
fields = ('service_type', 'min_time_regen', 'regular_time_regen',
|
||||
|
@ -214,6 +262,8 @@ class ServiceSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ServiceLinkSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Service_link` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.Service_link
|
||||
fields = ('service', 'server', 'last_regen', 'asked_regen',
|
||||
|
@ -224,6 +274,8 @@ class ServiceLinkSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OuverturePortListSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePortList` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.OuverturePortList
|
||||
fields = ('name', 'tcp_ports_in', 'udp_ports_in', 'tcp_ports_out',
|
||||
|
@ -231,15 +283,19 @@ class OuverturePortListSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OuverturePortSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.OuverturePort
|
||||
fields = ('begin', 'end', 'port_list', 'protocole', 'io', 'api_url')
|
||||
|
||||
|
||||
# PREFERENCES APP
|
||||
# PREFERENCES
|
||||
|
||||
|
||||
class OptionalUserSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalUser` objects.
|
||||
"""
|
||||
tel_mandatory = serializers.BooleanField(source='is_tel_mandatory')
|
||||
|
||||
class Meta:
|
||||
|
@ -250,6 +306,8 @@ class OptionalUserSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OptionalMachineSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalMachine` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.OptionalMachine
|
||||
fields = ('password_machine', 'max_lambdauser_interfaces',
|
||||
|
@ -258,6 +316,8 @@ class OptionalMachineSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OptionalTopologieSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalTopologie` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.OptionalTopologie
|
||||
fields = ('radius_general_policy', 'vlan_decision_ok',
|
||||
|
@ -265,6 +325,8 @@ class OptionalTopologieSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class GeneralOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.GeneralOption` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.GeneralOption
|
||||
fields = ('general_message', 'search_display_page',
|
||||
|
@ -274,12 +336,16 @@ class GeneralOptionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ServiceSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.Service` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.Service
|
||||
fields = ('name', 'url', 'description', 'image', 'api_url')
|
||||
|
||||
|
||||
class AssoOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.AssoOption` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.AssoOption
|
||||
fields = ('name', 'siret', 'adresse1', 'adresse2', 'contact',
|
||||
|
@ -288,22 +354,28 @@ class AssoOptionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class HomeOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.HomeOption` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.HomeOption
|
||||
fields = ('facebook_url', 'twitter_url', 'twitter_account_name')
|
||||
|
||||
|
||||
class MailMessageOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.MailMessageOption` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = preferences.MailMessageOption
|
||||
fields = ('welcome_mail_fr', 'welcome_mail_en')
|
||||
|
||||
|
||||
|
||||
# TOPOLOGIE APP
|
||||
# TOPOLOGIE
|
||||
|
||||
|
||||
class StackSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Stack` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.Stack
|
||||
fields = ('name', 'stack_id', 'details', 'member_id_min',
|
||||
|
@ -311,12 +383,16 @@ class StackSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class AccessPointSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.AccessPoint` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.AccessPoint
|
||||
fields = ('user', 'name', 'active', 'location', 'api_url')
|
||||
|
||||
|
||||
class SwitchSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Switch` objects
|
||||
"""
|
||||
port_amount = serializers.IntegerField(source='number')
|
||||
class Meta:
|
||||
model = topologie.Switch
|
||||
|
@ -325,30 +401,40 @@ class SwitchSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ModelSwitchSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.ModelSwitch` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.ModelSwitch
|
||||
fields = ('reference', 'constructor', 'api_url')
|
||||
|
||||
|
||||
class ConstructorSwitchSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.ConstructorSwitch` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.ConstructorSwitch
|
||||
fields = ('name', 'api_url')
|
||||
|
||||
|
||||
class SwitchBaySerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.SwitchBay` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.SwitchBay
|
||||
fields = ('name', 'building', 'info', 'api_url')
|
||||
|
||||
|
||||
class BuildingSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Building` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.Building
|
||||
fields = ('name', 'api_url')
|
||||
|
||||
|
||||
class SwitchPortSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Port` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.Port
|
||||
fields = ('switch', 'port', 'room', 'machine_interface', 'related',
|
||||
|
@ -360,15 +446,19 @@ class SwitchPortSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class RoomSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Room` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.Room
|
||||
fields = ('name', 'details', 'api_url')
|
||||
|
||||
|
||||
# USERS APP
|
||||
# USERS
|
||||
|
||||
|
||||
class UserSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.User` objects.
|
||||
"""
|
||||
access = serializers.BooleanField(source='has_access')
|
||||
uid = serializers.IntegerField(source='uid_number')
|
||||
|
||||
|
@ -383,6 +473,8 @@ class UserSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ClubSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.Club` objects.
|
||||
"""
|
||||
name = serializers.CharField(source='surname')
|
||||
access = serializers.BooleanField(source='has_access')
|
||||
uid = serializers.IntegerField(source='uid_number')
|
||||
|
@ -399,6 +491,8 @@ class ClubSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class AdherentSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.Adherent` objects.
|
||||
"""
|
||||
access = serializers.BooleanField(source='has_access')
|
||||
uid = serializers.IntegerField(source='uid_number')
|
||||
|
||||
|
@ -413,24 +507,32 @@ class AdherentSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ServiceUserSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.ServiceUser` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = users.ServiceUser
|
||||
fields = ('pseudo', 'access_group', 'comment', 'api_url')
|
||||
|
||||
|
||||
class SchoolSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.School` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = users.School
|
||||
fields = ('name', 'api_url')
|
||||
|
||||
|
||||
class ListRightSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.ListRight` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = users.ListRight
|
||||
fields = ('unix_name', 'gid', 'critical', 'details', 'api_url')
|
||||
|
||||
|
||||
class ShellSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.ListShell` objects.
|
||||
"""
|
||||
class Meta:
|
||||
model = users.ListShell
|
||||
fields = ('shell', 'api_url')
|
||||
|
@ -440,6 +542,8 @@ class ShellSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class BanSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.Ban` objects.
|
||||
"""
|
||||
active = serializers.BooleanField(source='is_active')
|
||||
|
||||
class Meta:
|
||||
|
@ -449,6 +553,8 @@ class BanSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class WhitelistSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `users.models.Whitelist` objects.
|
||||
"""
|
||||
active = serializers.BooleanField(source='is_active')
|
||||
|
||||
class Meta:
|
||||
|
@ -456,10 +562,12 @@ class WhitelistSerializer(NamespacedHMSerializer):
|
|||
fields = ('user', 'raison', 'date_start', 'date_end', 'active', 'api_url')
|
||||
|
||||
|
||||
# Services
|
||||
# SERVICE REGEN
|
||||
|
||||
|
||||
class ServiceRegenSerializer(NamespacedHMSerializer):
|
||||
"""Serialize the data about the services to regen.
|
||||
"""
|
||||
hostname = serializers.CharField(source='server.domain.name', read_only=True)
|
||||
service_name = serializers.CharField(source='service.service_type', read_only=True)
|
||||
need_regen = serializers.BooleanField()
|
||||
|
@ -476,6 +584,9 @@ class ServiceRegenSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
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)
|
||||
extension = serializers.CharField(source='domain.extension.name', read_only=True)
|
||||
mac_address = serializers.CharField(read_only=True)
|
||||
|
@ -490,22 +601,34 @@ class HostMacIpSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class SOARecordSerializer(SOASerializer):
|
||||
"""Serialize `machines.models.SOA` objects with the data needed to
|
||||
generate a SOA DNS record.
|
||||
"""
|
||||
class Meta:
|
||||
model = machines.SOA
|
||||
fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl')
|
||||
|
||||
|
||||
class OriginV4RecordSerializer(IpListSerializer):
|
||||
"""Serialize `machines.models.IpList` objects with the data needed to
|
||||
generate an IPv4 Origin DNS record.
|
||||
"""
|
||||
class Meta(IpListSerializer.Meta):
|
||||
fields = ('ipv4',)
|
||||
|
||||
|
||||
class OriginV6RecordSerializer(Ipv6ListSerializer):
|
||||
"""Serialize `machines.models.Ipv6List` objects with the data needed to
|
||||
generate an IPv6 Origin DNS record.
|
||||
"""
|
||||
class Meta(Ipv6ListSerializer.Meta):
|
||||
fields = ('ipv6',)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
class Meta(NsSerializer.Meta):
|
||||
|
@ -513,6 +636,9 @@ class NSRecordSerializer(NsSerializer):
|
|||
|
||||
|
||||
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)
|
||||
|
||||
class Meta(MxSerializer.Meta):
|
||||
|
@ -520,11 +646,17 @@ class MXRecordSerializer(MxSerializer):
|
|||
|
||||
|
||||
class TXTRecordSerializer(TxtSerializer):
|
||||
"""Serialize `machines.models.Txt` objects with the data needed to
|
||||
generate a TXT DNS record.
|
||||
"""
|
||||
class Meta(TxtSerializer.Meta):
|
||||
fields = ('field1', 'field2')
|
||||
|
||||
|
||||
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)
|
||||
|
||||
class Meta(SrvSerializer.Meta):
|
||||
|
@ -532,6 +664,9 @@ class SRVRecordSerializer(SrvSerializer):
|
|||
|
||||
|
||||
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)
|
||||
ipv4 = serializers.CharField(source='ipv4.ipv4', read_only=True)
|
||||
|
||||
|
@ -541,6 +676,9 @@ class ARecordSerializer(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)
|
||||
ipv6 = Ipv6ListSerializer(many=True, read_only=True)
|
||||
|
||||
|
@ -550,6 +688,9 @@ class AAAARecordSerializer(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)
|
||||
hostname = serializers.CharField(source='name', read_only=True)
|
||||
|
||||
|
@ -559,6 +700,8 @@ class CNAMERecordSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class DNSZonesSerializer(serializers.ModelSerializer):
|
||||
"""Serialize the data about DNS Zones.
|
||||
"""
|
||||
soa = SOARecordSerializer()
|
||||
ns_records = NSRecordSerializer(many=True, source='ns_set')
|
||||
originv4 = OriginV4RecordSerializer(source='origin')
|
||||
|
@ -577,14 +720,18 @@ class DNSZonesSerializer(serializers.ModelSerializer):
|
|||
'aaaa_records', 'cname_records')
|
||||
|
||||
|
||||
# Mailing
|
||||
# MAILING
|
||||
|
||||
|
||||
class MailingMemberSerializer(UserSerializer):
|
||||
"""Serialize the data about a mailing member.
|
||||
"""
|
||||
class Meta(UserSerializer.Meta):
|
||||
fields = ('name', 'pseudo', 'email')
|
||||
|
||||
class MailingSerializer(ClubSerializer):
|
||||
"""Serialize the data about a mailing.
|
||||
"""
|
||||
members = MailingMemberSerializer(many=True)
|
||||
admins = MailingMemberSerializer(source='administrators', many=True)
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# 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 © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
# 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
|
||||
|
@ -21,8 +18,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
"""api.settings
|
||||
Django settings specific to the API.
|
||||
"""Settings specific to the API.
|
||||
"""
|
||||
|
||||
# RestFramework config for API
|
||||
|
@ -49,4 +45,6 @@ API_PERMISSION_CODENAME = 'use_api'
|
|||
API_APPS = (
|
||||
'rest_framework.authtoken',
|
||||
)
|
||||
|
||||
# The expiration time for an authentication token
|
||||
API_TOKEN_DURATION = 86400 # 24 hours
|
||||
|
|
133
api/tests.py
133
api/tests.py
|
@ -2,9 +2,7 @@
|
|||
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
# 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
|
||||
|
@ -19,8 +17,7 @@
|
|||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
"""api.tests
|
||||
The tests for the API module.
|
||||
"""Defines the test suite for the API
|
||||
"""
|
||||
|
||||
import json
|
||||
|
@ -34,13 +31,25 @@ import users.models as users
|
|||
|
||||
|
||||
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 = [
|
||||
'/api/'
|
||||
]
|
||||
# URLs that require to be authenticated and have no special permissions
|
||||
auth_no_perm_endpoints = []
|
||||
# URLs that require to be authenticated and have special permissions
|
||||
auth_perm_endpoints = [
|
||||
'/api/cotisations/articles/',
|
||||
# '/api/cotisations/articles/<pk>/',
|
||||
|
@ -160,49 +169,62 @@ class APIEndpointsTestCase(APITestCase):
|
|||
cls.superuser.delete()
|
||||
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):
|
||||
"""
|
||||
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
|
||||
:param expected_code: (int) The HTTP return code expected
|
||||
:param formats: (list) The list of formats to use for the request
|
||||
(Default: [None])
|
||||
:param assert_more: (func) A function to assert more specific data
|
||||
in the same test. It is evaluated with the responsem object, the
|
||||
url and the format used.
|
||||
Args:
|
||||
urls: The list of urls to test
|
||||
expected_code: The HTTP return code expected
|
||||
formats: The list of formats to use for the request. Default is to
|
||||
only test `None` format.
|
||||
assert_more: An optional function to assert more specific data in
|
||||
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 format in formats:
|
||||
with self.subTest(url=url, format=format):
|
||||
response = self.client.get(url, format=format)
|
||||
assert response.status_code == expected_code
|
||||
if assert_more:
|
||||
if assert_more is not None:
|
||||
assert_more(response, url, format)
|
||||
|
||||
def test_no_auth_endpoints_with_no_auth(self):
|
||||
"""
|
||||
Test that every endpoint that does not require to be authenticated,
|
||||
returns a Ok (200) response when not authenticated.
|
||||
"""Tests that every endpoint that does not require to be
|
||||
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')
|
||||
for endpoint in self.no_auth_endpoints]
|
||||
self.check_responses_code(urls, codes.ok)
|
||||
|
||||
def test_auth_endpoints_with_no_auth(self):
|
||||
"""
|
||||
Test that every endpoint that does require to be authenticated,
|
||||
"""Tests that every endpoint that does require to be 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 \
|
||||
self.auth_no_perm_endpoints + self.auth_perm_endpoints]
|
||||
self.check_responses_code(urls, codes.unauthorized)
|
||||
|
||||
def test_no_auth_endpoints_with_auth(self):
|
||||
"""
|
||||
Test that every endpoint that does not require to be authenticated,
|
||||
returns a Ok (200) response when authenticated.
|
||||
"""Tests that every endpoint that does not require to be
|
||||
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)
|
||||
urls = [endpoint.replace('<pk>', '1')
|
||||
|
@ -210,10 +232,12 @@ class APIEndpointsTestCase(APITestCase):
|
|||
self.check_responses_code(urls, codes.ok)
|
||||
|
||||
def test_auth_no_perm_endpoints_with_auth_and_no_perm(self):
|
||||
"""
|
||||
Test that every endpoint that does require to be authenticated and
|
||||
no special permissions, returns a Ok (200) response when
|
||||
authenticated but without permissions.
|
||||
"""Tests that every endpoint that does require to be authenticated and
|
||||
no special permissions, returns a Ok (200) response when authenticated
|
||||
but without permissions.
|
||||
|
||||
Raises:
|
||||
AssertionError: An endpoint did not have a 200 status code.
|
||||
"""
|
||||
self.client.force_authenticate(user=self.stduser)
|
||||
urls = [endpoint.replace('<pk>', '1')
|
||||
|
@ -221,10 +245,12 @@ class APIEndpointsTestCase(APITestCase):
|
|||
self.check_responses_code(urls, codes.ok)
|
||||
|
||||
def test_auth_perm_endpoints_with_auth_and_no_perm(self):
|
||||
"""
|
||||
Test that every endpoint that does require to be authenticated and
|
||||
"""Tests that every endpoint that does require to be authenticated and
|
||||
special permissions, returns a Forbidden (403) response when
|
||||
authenticated but without permissions.
|
||||
|
||||
Raises:
|
||||
AssertionError: An endpoint did not have a 403 status code.
|
||||
"""
|
||||
self.client.force_authenticate(user=self.stduser)
|
||||
urls = [endpoint.replace('<pk>', '1')
|
||||
|
@ -232,9 +258,11 @@ class APIEndpointsTestCase(APITestCase):
|
|||
self.check_responses_code(urls, codes.forbidden)
|
||||
|
||||
def test_auth_endpoints_with_auth_and_perm(self):
|
||||
"""
|
||||
Test that every endpoint that does require to be authenticated,
|
||||
returns a Ok (200) response when authenticated with all permissions
|
||||
"""Tests that every endpoint that does require to be authenticated,
|
||||
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)
|
||||
urls = [endpoint.replace('<pk>', '1') for endpoint \
|
||||
|
@ -242,10 +270,12 @@ class APIEndpointsTestCase(APITestCase):
|
|||
self.check_responses_code(urls, codes.ok)
|
||||
|
||||
def test_endpoints_not_found(self):
|
||||
"""
|
||||
Test that every endpoint that uses a primary key parameter,
|
||||
"""Tests that every endpoint that uses a primary key parameter,
|
||||
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)
|
||||
# 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)
|
||||
|
||||
def test_formats(self):
|
||||
"""
|
||||
Test that every endpoint returns a Ok (200) response when using
|
||||
different formats. Also checks that 'json' format returns a valid json
|
||||
"""Tests that every endpoint returns a Ok (200) response when using
|
||||
different formats. Also checks that 'json' format returns a valid
|
||||
JSON object.
|
||||
|
||||
Raises:
|
||||
AssertionError: An endpoint did not have a 200 status code.
|
||||
"""
|
||||
self.client.force_authenticate(user=self.superuser)
|
||||
|
||||
|
@ -275,6 +308,14 @@ class APIEndpointsTestCase(APITestCase):
|
|||
assert_more=assert_more)
|
||||
|
||||
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 = [
|
||||
'/api/cotisations/articles/',
|
||||
'/api/cotisations/banques/',
|
||||
|
@ -338,8 +379,12 @@ class APIPaginationTestCase(APITestCase):
|
|||
super().tearDownClass()
|
||||
|
||||
def test_pagination(self):
|
||||
"""
|
||||
Test that every endpoint is using the pagination correctly
|
||||
"""Tests 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)
|
||||
for url in self.endpoints:
|
||||
|
|
29
api/urls.py
29
api/urls.py
|
@ -2,7 +2,7 @@
|
|||
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2018 Mael Kervella
|
||||
# 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
|
||||
|
@ -17,27 +17,30 @@
|
|||
# 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.
|
||||
"""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 .routers import AllViewsRouter
|
||||
from . import views
|
||||
from .routers import AllViewsRouter
|
||||
|
||||
|
||||
router = AllViewsRouter()
|
||||
# COTISATIONS APP
|
||||
# COTISATIONS
|
||||
router.register_viewset(r'cotisations/factures', views.FactureViewSet)
|
||||
router.register_viewset(r'cotisations/ventes', views.VenteViewSet)
|
||||
router.register_viewset(r'cotisations/articles', views.ArticleViewSet)
|
||||
router.register_viewset(r'cotisations/banques', views.BanqueViewSet)
|
||||
router.register_viewset(r'cotisations/paiements', views.PaiementViewSet)
|
||||
router.register_viewset(r'cotisations/cotisations', views.CotisationViewSet)
|
||||
# MACHINES APP
|
||||
# MACHINES
|
||||
router.register_viewset(r'machines/machines', views.MachineViewSet)
|
||||
router.register_viewset(r'machines/machinetypes', views.MachineTypeViewSet)
|
||||
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/ouvertureportlists', views.OuverturePortListViewSet)
|
||||
router.register_viewset(r'machines/ouvertureports', views.OuverturePortViewSet)
|
||||
# PREFERENCES APP
|
||||
# PREFERENCES
|
||||
router.register_viewset(r'preferences/service', views.ServiceViewSet),
|
||||
router.register_view(r'preferences/optionaluser', views.OptionalUserView),
|
||||
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/homeoption', views.HomeOptionView),
|
||||
router.register_view(r'preferences/mailmessageoption', views.MailMessageOptionView),
|
||||
# TOPOLOGIE APP
|
||||
# TOPOLOGIE
|
||||
router.register_viewset(r'topologie/stack', views.StackViewSet)
|
||||
router.register_viewset(r'topologie/acesspoint', views.AccessPointViewSet)
|
||||
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/switchport', views.SwitchPortViewSet, base_name='switchport')
|
||||
router.register_viewset(r'topologie/room', views.RoomViewSet)
|
||||
# USERS APP
|
||||
# USERS
|
||||
router.register_viewset(r'users/users', views.UserViewSet)
|
||||
router.register_viewset(r'users/clubs', views.ClubViewSet)
|
||||
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/bans', views.BanViewSet)
|
||||
router.register_viewset(r'users/whitelists', views.WhitelistViewSet)
|
||||
# SERVICES REGEN
|
||||
# SERVICE REGEN
|
||||
router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen')
|
||||
# DHCP
|
||||
router.register_view(r'dhcp/hostmacip', views.HostMacIpView),
|
||||
|
@ -95,7 +98,7 @@ router.register_view(r'dns/zones', views.DNSZonesView),
|
|||
# MAILING
|
||||
router.register_view(r'mailing/standard', views.StandardMailingView),
|
||||
router.register_view(r'mailing/club', views.ClubMailingView),
|
||||
# TOKEN-AUTH
|
||||
# TOKEN AUTHENTICATION
|
||||
router.register_view(r'token-auth', views.ObtainExpiringAuthToken)
|
||||
|
||||
|
||||
|
|
156
api/views.py
156
api/views.py
|
@ -18,16 +18,16 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 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
|
||||
HTML pages such as the login and index pages for a better integration.
|
||||
All views inherits the `rest_framework.views.APIview` to respect the
|
||||
REST API requirements such as dealing with HTTP status code, format of
|
||||
the response (JSON or other), the CSRF exempting, ...
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.response import Response
|
||||
|
@ -38,7 +38,6 @@ import machines.models as machines
|
|||
import preferences.models as preferences
|
||||
import topologie.models as topologie
|
||||
import users.models as users
|
||||
|
||||
from re2o.utils import all_active_interfaces, all_has_access
|
||||
|
||||
from . import serializers
|
||||
|
@ -46,142 +45,195 @@ from .pagination import PageSizedPagination
|
|||
from .permissions import ACLPermission
|
||||
|
||||
|
||||
# COTISATIONS APP
|
||||
# COTISATIONS
|
||||
|
||||
|
||||
class FactureViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects.
|
||||
"""
|
||||
queryset = cotisations.Facture.objects.all()
|
||||
serializer_class = serializers.FactureSerializer
|
||||
|
||||
|
||||
class VenteViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Vente` objects.
|
||||
"""
|
||||
queryset = cotisations.Vente.objects.all()
|
||||
serializer_class = serializers.VenteSerializer
|
||||
|
||||
|
||||
class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Article` objects.
|
||||
"""
|
||||
queryset = cotisations.Article.objects.all()
|
||||
serializer_class = serializers.ArticleSerializer
|
||||
|
||||
|
||||
class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Banque` objects.
|
||||
"""
|
||||
queryset = cotisations.Banque.objects.all()
|
||||
serializer_class = serializers.BanqueSerializer
|
||||
|
||||
|
||||
class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Paiement` objects.
|
||||
"""
|
||||
queryset = cotisations.Paiement.objects.all()
|
||||
serializer_class = serializers.PaiementSerializer
|
||||
|
||||
|
||||
class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Cotisation` objects.
|
||||
"""
|
||||
queryset = cotisations.Cotisation.objects.all()
|
||||
serializer_class = serializers.CotisationSerializer
|
||||
|
||||
|
||||
# MACHINES APP
|
||||
# MACHINES
|
||||
|
||||
|
||||
class MachineViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Machine` objects.
|
||||
"""
|
||||
queryset = machines.Machine.objects.all()
|
||||
serializer_class = serializers.MachineSerializer
|
||||
|
||||
|
||||
class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.MachineType` objects.
|
||||
"""
|
||||
queryset = machines.MachineType.objects.all()
|
||||
serializer_class = serializers.MachineTypeSerializer
|
||||
|
||||
|
||||
class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.IpType` objects.
|
||||
"""
|
||||
queryset = machines.IpType.objects.all()
|
||||
serializer_class = serializers.IpTypeSerializer
|
||||
|
||||
|
||||
class VlanViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Vlan` objects.
|
||||
"""
|
||||
queryset = machines.Vlan.objects.all()
|
||||
serializer_class = serializers.VlanSerializer
|
||||
|
||||
|
||||
class NasViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Nas` objects.
|
||||
"""
|
||||
queryset = machines.Nas.objects.all()
|
||||
serializer_class = serializers.NasSerializer
|
||||
|
||||
|
||||
class SOAViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.SOA` objects.
|
||||
"""
|
||||
queryset = machines.SOA.objects.all()
|
||||
serializer_class = serializers.SOASerializer
|
||||
|
||||
|
||||
class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Extension` objects.
|
||||
"""
|
||||
queryset = machines.Extension.objects.all()
|
||||
serializer_class = serializers.ExtensionSerializer
|
||||
|
||||
|
||||
class MxViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Mx` objects.
|
||||
"""
|
||||
queryset = machines.Mx.objects.all()
|
||||
serializer_class = serializers.MxSerializer
|
||||
|
||||
|
||||
class NsViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Ns` objects.
|
||||
"""
|
||||
queryset = machines.Ns.objects.all()
|
||||
serializer_class = serializers.NsSerializer
|
||||
|
||||
|
||||
class TxtViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Txt` objects.
|
||||
"""
|
||||
queryset = machines.Txt.objects.all()
|
||||
serializer_class = serializers.TxtSerializer
|
||||
|
||||
|
||||
class SrvViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Srv` objects.
|
||||
"""
|
||||
queryset = machines.Srv.objects.all()
|
||||
serializer_class = serializers.SrvSerializer
|
||||
|
||||
|
||||
class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Interface` objects.
|
||||
"""
|
||||
queryset = machines.Interface.objects.all()
|
||||
serializer_class = serializers.InterfaceSerializer
|
||||
|
||||
|
||||
class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Ipv6List` objects.
|
||||
"""
|
||||
queryset = machines.Ipv6List.objects.all()
|
||||
serializer_class = serializers.Ipv6ListSerializer
|
||||
|
||||
|
||||
class DomainViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Domain` objects.
|
||||
"""
|
||||
queryset = machines.Domain.objects.all()
|
||||
serializer_class = serializers.DomainSerializer
|
||||
|
||||
|
||||
class IpListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.IpList` objects.
|
||||
"""
|
||||
queryset = machines.IpList.objects.all()
|
||||
serializer_class = serializers.IpListSerializer
|
||||
|
||||
|
||||
class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Service` objects.
|
||||
"""
|
||||
queryset = machines.Service.objects.all()
|
||||
serializer_class = serializers.ServiceSerializer
|
||||
|
||||
|
||||
class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Service_link` objects.
|
||||
"""
|
||||
queryset = machines.Service_link.objects.all()
|
||||
serializer_class = serializers.ServiceLinkSerializer
|
||||
|
||||
|
||||
class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.OuverturePortList`
|
||||
objects.
|
||||
"""
|
||||
queryset = machines.OuverturePortList.objects.all()
|
||||
serializer_class = serializers.OuverturePortListSerializer
|
||||
|
||||
|
||||
class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
queryset = machines.OuverturePort.objects.all()
|
||||
serializer_class = serializers.OuverturePortSerializer
|
||||
|
||||
|
||||
# PREFERENCES APP
|
||||
# PREFERENCES
|
||||
# Those views differ a bit because there is only one object
|
||||
# to display, so we don't bother with the listing part
|
||||
|
||||
class OptionalUserView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.OptionalUser.can_view_all]}
|
||||
serializer_class = serializers.OptionalUserSerializer
|
||||
|
@ -191,6 +243,8 @@ class OptionalUserView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class OptionalMachineView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalMachine` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.OptionalMachine.can_view_all]}
|
||||
serializer_class = serializers.OptionalMachineSerializer
|
||||
|
@ -200,6 +254,8 @@ class OptionalMachineView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class OptionalTopologieView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.OptionalTopologie.can_view_all]}
|
||||
serializer_class = serializers.OptionalTopologieSerializer
|
||||
|
@ -209,6 +265,8 @@ class OptionalTopologieView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class GeneralOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.GeneralOption` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.GeneralOption.can_view_all]}
|
||||
serializer_class = serializers.GeneralOptionSerializer
|
||||
|
@ -218,11 +276,15 @@ class GeneralOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `preferences.models.Service` objects.
|
||||
"""
|
||||
queryset = preferences.Service.objects.all()
|
||||
serializer_class = serializers.ServiceSerializer
|
||||
|
||||
|
||||
class AssoOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.AssoOption` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.AssoOption.can_view_all]}
|
||||
serializer_class = serializers.AssoOptionSerializer
|
||||
|
@ -232,6 +294,8 @@ class AssoOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class HomeOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.HomeOption` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.HomeOption.can_view_all]}
|
||||
serializer_class = serializers.HomeOptionSerializer
|
||||
|
@ -241,6 +305,8 @@ class HomeOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class MailMessageOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.MailMessageOption` settings.
|
||||
"""
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [preferences.MailMessageOption.can_view_all]}
|
||||
serializer_class = serializers.MailMessageOptionSerializer
|
||||
|
@ -249,106 +315,145 @@ class MailMessageOptionView(generics.RetrieveAPIView):
|
|||
return preferences.MailMessageOption.objects.first()
|
||||
|
||||
|
||||
# TOPOLOGIE APP
|
||||
# TOPOLOGIE
|
||||
|
||||
|
||||
class StackViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Stack` objects.
|
||||
"""
|
||||
queryset = topologie.Stack.objects.all()
|
||||
serializer_class = serializers.StackSerializer
|
||||
|
||||
|
||||
class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.AccessPoint` objects.
|
||||
"""
|
||||
queryset = topologie.AccessPoint.objects.all()
|
||||
serializer_class = serializers.AccessPointSerializer
|
||||
|
||||
|
||||
class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Switch` objects.
|
||||
"""
|
||||
queryset = topologie.Switch.objects.all()
|
||||
serializer_class = serializers.SwitchSerializer
|
||||
|
||||
|
||||
class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.ModelSwitch` objects.
|
||||
"""
|
||||
queryset = topologie.ModelSwitch.objects.all()
|
||||
serializer_class = serializers.ModelSwitchSerializer
|
||||
|
||||
|
||||
class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.ConstructorSwitch`
|
||||
objects.
|
||||
"""
|
||||
queryset = topologie.ConstructorSwitch.objects.all()
|
||||
serializer_class = serializers.ConstructorSwitchSerializer
|
||||
|
||||
|
||||
class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.SwitchBay` objects.
|
||||
"""
|
||||
queryset = topologie.SwitchBay.objects.all()
|
||||
serializer_class = serializers.SwitchBaySerializer
|
||||
|
||||
|
||||
class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Building` objects.
|
||||
"""
|
||||
queryset = topologie.Building.objects.all()
|
||||
serializer_class = serializers.BuildingSerializer
|
||||
|
||||
|
||||
class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Port` objects.
|
||||
"""
|
||||
queryset = topologie.Port.objects.all()
|
||||
serializer_class = serializers.SwitchPortSerializer
|
||||
|
||||
|
||||
class RoomViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Room` objects.
|
||||
"""
|
||||
queryset = topologie.Room.objects.all()
|
||||
serializer_class = serializers.RoomSerializer
|
||||
|
||||
|
||||
# USER APP
|
||||
# USER
|
||||
|
||||
|
||||
class UserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Users` objects.
|
||||
"""
|
||||
queryset = users.User.objects.all()
|
||||
serializer_class = serializers.UserSerializer
|
||||
|
||||
|
||||
class ClubViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Club` objects.
|
||||
"""
|
||||
queryset = users.Club.objects.all()
|
||||
serializer_class = serializers.ClubSerializer
|
||||
|
||||
|
||||
class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Adherent` objects.
|
||||
"""
|
||||
queryset = users.Adherent.objects.all()
|
||||
serializer_class = serializers.AdherentSerializer
|
||||
|
||||
|
||||
class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.ServiceUser` objects.
|
||||
"""
|
||||
queryset = users.ServiceUser.objects.all()
|
||||
serializer_class = serializers.ServiceUserSerializer
|
||||
|
||||
|
||||
class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.School` objects.
|
||||
"""
|
||||
queryset = users.School.objects.all()
|
||||
serializer_class = serializers.SchoolSerializer
|
||||
|
||||
|
||||
class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.ListRight` objects.
|
||||
"""
|
||||
queryset = users.ListRight.objects.all()
|
||||
serializer_class = serializers.ListRightSerializer
|
||||
|
||||
|
||||
class ShellViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.ListShell` objects.
|
||||
"""
|
||||
queryset = users.ListShell.objects.all()
|
||||
serializer_class = serializers.ShellSerializer
|
||||
|
||||
|
||||
class BanViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Ban` objects.
|
||||
"""
|
||||
queryset = users.Ban.objects.all()
|
||||
serializer_class = serializers.BanSerializer
|
||||
|
||||
|
||||
class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Whitelist` objects.
|
||||
"""
|
||||
queryset = users.Whitelist.objects.all()
|
||||
serializer_class = serializers.WhitelistSerializer
|
||||
|
||||
|
||||
# Services views
|
||||
# SERVICE REGEN
|
||||
|
||||
|
||||
class ServiceRegenViewSet(viewsets.ModelViewSet):
|
||||
"""Exposes list and details of the services to regen
|
||||
"""
|
||||
serializer_class = serializers.ServiceRegenSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
@ -363,24 +468,33 @@ class ServiceRegenViewSet(viewsets.ModelViewSet):
|
|||
return queryset
|
||||
|
||||
|
||||
# DHCP views
|
||||
# DHCP
|
||||
|
||||
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()
|
||||
serializer_class = serializers.HostMacIpSerializer
|
||||
|
||||
|
||||
# DNS views
|
||||
# DNS
|
||||
|
||||
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()
|
||||
serializer_class = serializers.DNSZonesSerializer
|
||||
|
||||
|
||||
# Mailing views
|
||||
# MAILING
|
||||
|
||||
|
||||
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
|
||||
permission_classes = (ACLPermission, )
|
||||
perms_map = {'GET' : [users.User.can_view_all]}
|
||||
|
@ -394,13 +508,23 @@ class StandardMailingView(views.APIView):
|
|||
|
||||
|
||||
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()
|
||||
serializer_class = serializers.MailingSerializer
|
||||
|
||||
|
||||
# Subclass the standard rest_framework.auth_token.views.ObtainAuthToken
|
||||
# in order to renew the lease of the token and add expiration time
|
||||
# TOKEN AUTHENTICATION
|
||||
|
||||
|
||||
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):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
|
Loading…
Reference in a new issue