Commit 56fdfca1 authored by klafyvel's avatar klafyvel

Release : 2.8

parents 2eeeb0c1 d1d35428
Pipeline #2350 passed with stage
in 3 minutes and 42 seconds
......@@ -178,3 +178,28 @@ Be carefull, you need the proper rights to edit a DocumentTemplate.
Re2o now sends subscription voucher when an invoice is controlled. It uses one
of the templates. You also need to set the name of the president of your association
to be set in your settings.
## MR 427: Tickets
Manually edit `settings_local.py` to provide the new `OPTIONNAL_APPS` lists:
```python
OPTIONNAL_APPS_RE2O = ('tickets',)
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + (...,...,)
```
Don't forget to run migrations afterwards.
## MR 433 : upgrade django-ldapdb to 1.3.0
Uninstall the existing django-ldapdb installation
pip3 uninstall django-ldapdb
Install debian(buster) supported version
apt install python3-django-ldapdb
If you use MySQL, please run
```
SET GLOBAL SQL_MODE=ANSI_QUOTES;
```
......@@ -33,21 +33,21 @@ from django.utils.translation import ugettext as _
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
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
codename=settings.API_PERMISSION_CODENAME,
)
if created:
api_permission.save()
......@@ -67,9 +67,13 @@ def can_view(user):
viewing is granted and msg is a message (can be None).
"""
kwargs = {
'app_label': settings.API_CONTENT_TYPE_APP_LABEL,
'codename': settings.API_PERMISSION_CODENAME
"app_label": settings.API_CONTENT_TYPE_APP_LABEL,
"codename": settings.API_PERMISSION_CODENAME,
}
can = user.has_perm('%(app_label)s.%(codename)s' % kwargs)
return can, None if can else _("You don't have the right to see this"
" application.")
permission = "%(app_label)s.%(codename)s" % kwargs
can = user.has_perm(permission)
return (
can,
None if can else _("You don't have the right to view this application."),
(permission,),
)
......@@ -41,9 +41,7 @@ class ExpiringTokenAuthentication(TokenAuthentication):
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
)
token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION)
utc_now = datetime.datetime.now(datetime.timezone.utc)
if token.created < utc_now - token_duration:
raise exceptions.AuthenticationFailed(_("The token has expired."))
......
......@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-01-08 23:06+0100\n"
"POT-Creation-Date: 2019-11-19 23:43+0100\n"
"PO-Revision-Date: 2019-01-07 01:37+0100\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n"
......@@ -31,10 +31,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: acl.py:74
msgid "You don't have the right to see this application."
#: api/acl.py:77
msgid "You don't have the right to view this application."
msgstr "Vous n'avez pas le droit de voir cette application."
#: authentication.py:49
#: api/authentication.py:47
msgid "The token has expired."
msgstr "Le jeton a expiré."
......@@ -38,8 +38,9 @@ class PageSizedPagination(pagination.PageNumberPagination):
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',)
page_size_query_param = "page_size"
all_pages_strings = ("all",)
max_page_size = 10000
def get_page_size(self, request):
......
......@@ -55,17 +55,21 @@ def _get_param_in_view(view, param_name):
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 '
'`.{}` or have a `.get_{}()` method.'
).format(self.__class__.__name__, param_name, param_name)
if hasattr(view, 'get_' + param_name):
param = getattr(view, 'get_' + param_name)()
assert param is not None, (
'{}.get_{}() returned None'
).format(view.__class__.__name__, param_name)
assert (
hasattr(view, "get_" + param_name)
or getattr(view, param_name, None) is not None
), (
"cannot apply {} on a view that does not set "
"`.{}` or have a `.get_{}()` method."
).format(
self.__class__.__name__, param_name, param_name
)
if hasattr(view, "get_" + param_name):
param = getattr(view, "get_" + param_name)()
assert param is not None, ("{}.get_{}() returned None").format(
view.__class__.__name__, param_name
)
return param
return getattr(view, param_name)
......@@ -97,7 +101,7 @@ class ACLPermission(permissions.BasePermission):
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")
if method not in perms_map:
raise exceptions.MethodNotAllowed(method)
......@@ -123,7 +127,7 @@ class ACLPermission(permissions.BasePermission):
"""
# Workaround to ensure ACLPermissions are not applied
# to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False):
if getattr(view, "_ignore_model_permissions", False):
return True
if not request.user or not request.user.is_authenticated:
......@@ -148,22 +152,22 @@ class AutodetectACLPermission(permissions.BasePermission):
"""
perms_map = {
'GET': [can_see_api, lambda model: model.can_view_all],
'OPTIONS': [can_see_api, lambda model: model.can_view_all],
'HEAD': [can_see_api, lambda model: model.can_view_all],
'POST': [can_see_api, lambda model: model.can_create],
'PUT': [], # No restrictions, apply to objects
'PATCH': [], # No restrictions, apply to objects
'DELETE': [], # No restrictions, apply to objects
"GET": [can_see_api, lambda model: model.can_view_all],
"OPTIONS": [can_see_api, lambda model: model.can_view_all],
"HEAD": [can_see_api, lambda model: model.can_view_all],
"POST": [can_see_api, lambda model: model.can_create],
"PUT": [], # No restrictions, apply to objects
"PATCH": [], # No restrictions, apply to objects
"DELETE": [], # No restrictions, apply to objects
}
perms_obj_map = {
'GET': [can_see_api, lambda obj: obj.can_view],
'OPTIONS': [can_see_api, lambda obj: obj.can_view],
'HEAD': [can_see_api, lambda obj: obj.can_view],
'POST': [], # No restrictions, apply to models
'PUT': [can_see_api, lambda obj: obj.can_edit],
'PATCH': [can_see_api, lambda obj: obj.can_edit],
'DELETE': [can_see_api, lambda obj: obj.can_delete],
"GET": [can_see_api, lambda obj: obj.can_view],
"OPTIONS": [can_see_api, lambda obj: obj.can_view],
"HEAD": [can_see_api, lambda obj: obj.can_view],
"POST": [], # No restrictions, apply to models
"PUT": [can_see_api, lambda obj: obj.can_edit],
"PATCH": [can_see_api, lambda obj: obj.can_edit],
"DELETE": [can_see_api, lambda obj: obj.can_delete],
}
def get_required_permissions(self, method, model):
......@@ -210,7 +214,7 @@ class AutodetectACLPermission(permissions.BasePermission):
@staticmethod
def _queryset(view):
return _get_param_in_view(view, 'queryset')
return _get_param_in_view(view, "queryset")
def has_permission(self, request, view):
"""Check that the user has the model-based permissions to perform
......@@ -232,7 +236,7 @@ class AutodetectACLPermission(permissions.BasePermission):
"""
# Workaround to ensure ACLPermissions are not applied
# to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False):
if getattr(view, "_ignore_model_permissions", False):
return True
if not request.user or not request.user.is_authenticated:
......@@ -274,7 +278,7 @@ class AutodetectACLPermission(permissions.BasePermission):
# to make another lookup.
raise Http404
read_perms = self.get_required_object_permissions('GET', obj)
read_perms = self.get_required_object_permissions("GET", obj)
if not read_perms(request.user)[0]:
raise Http404
......
......@@ -74,9 +74,9 @@ class AllViewsRouter(DefaultRouter):
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, api_urls=None):
"""Create a class-based view to use as the API root.
Highly inspired by the base class. See details on the implementation
......@@ -102,12 +102,10 @@ class AllViewsRouter(DefaultRouter):
if schema_urls and self.schema_title:
view_renderers += list(self.schema_renderers)
schema_generator = SchemaGenerator(
title=self.schema_title,
patterns=schema_urls
title=self.schema_title, patterns=schema_urls
)
schema_media_types = [
renderer.media_type
for renderer in self.schema_renderers
renderer.media_type for renderer in self.schema_renderers
]
class APIRoot(views.APIView):
......@@ -128,14 +126,14 @@ class AllViewsRouter(DefaultRouter):
namespace = request.resolver_match.namespace
for key, url_name in api_root_dict.items():
if namespace:
url_name = namespace + ':' + url_name
url_name = namespace + ":" + url_name
try:
ret[key] = reverse(
url_name,
args=args,
kwargs=kwargs,
request=request,
format=kwargs.get('format', None)
format=kwargs.get("format", None),
)
except NoReverseMatch:
# Don't bail out if eg. no list routes exist, only detail routes.
......
This diff is collapsed.
......@@ -24,28 +24,24 @@
# RestFramework config for API
REST_FRAMEWORK = {
'URL_FIELD_NAME': 'api_url',
'DEFAULT_AUTHENTICATION_CLASSES': (
'api.authentication.ExpiringTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
"URL_FIELD_NAME": "api_url",
"DEFAULT_AUTHENTICATION_CLASSES": (
"api.authentication.ExpiringTokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
),
'DEFAULT_PERMISSION_CLASSES': (
'api.permissions.AutodetectACLPermission',
),
'DEFAULT_PAGINATION_CLASS': 'api.pagination.PageSizedPagination',
'PAGE_SIZE': 100
"DEFAULT_PERMISSION_CLASSES": ("api.permissions.AutodetectACLPermission",),
"DEFAULT_PAGINATION_CLASS": "api.pagination.PageSizedPagination",
"PAGE_SIZE": 100,
}
# API permission settings
API_CONTENT_TYPE_APP_LABEL = 'api'
API_CONTENT_TYPE_MODEL = 'api'
API_PERMISSION_NAME = 'Can use the API'
API_PERMISSION_CODENAME = 'use_api'
API_CONTENT_TYPE_APP_LABEL = "api"
API_CONTENT_TYPE_MODEL = "api"
API_PERMISSION_NAME = "Can use the API"
API_PERMISSION_CODENAME = "use_api"
# Activate token authentication
API_APPS = (
'rest_framework.authtoken',
)
API_APPS = ("rest_framework.authtoken",)
# The expiration time for an authentication token
API_TOKEN_DURATION = 86400 # 24 hours
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
python-django
python-dateutil
texlive-latex-base
texlive-fonts-recommended
python-djangorestframework
python-django-reversion
python-pip
libsasl2-dev libldap2-dev
libssl-dev
python-crypto
python-git
javascript-common
libjs-jquery
libjs-jquery-ui
libjs-jquery-timepicker
libjs-bootstrap
fonts-font-awesome
graphviz
git
gettext
freeradius-common
freeradius-python2
python-mysqldb
......@@ -4,7 +4,7 @@
# quelques clics.
#
# Copyright © 2017 Gabriel Détraz