8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-22 11:23:10 +00:00

Merge branch '210-use-black-for-formatting' into 'dev'

Resolve "Use black for formatting"

See merge request federez/re2o!468
This commit is contained in:
chirac 2019-11-04 23:16:57 +01:00
commit 540a8d0531
515 changed files with 16814 additions and 13681 deletions

View file

@ -40,14 +40,14 @@ def _create_api_permission():
""" """
api_content_type, created = ContentType.objects.get_or_create( api_content_type, created = ContentType.objects.get_or_create(
app_label=settings.API_CONTENT_TYPE_APP_LABEL, app_label=settings.API_CONTENT_TYPE_APP_LABEL,
model=settings.API_CONTENT_TYPE_MODEL model=settings.API_CONTENT_TYPE_MODEL,
) )
if created: if created:
api_content_type.save() api_content_type.save()
api_permission, created = Permission.objects.get_or_create( api_permission, created = Permission.objects.get_or_create(
name=settings.API_PERMISSION_NAME, name=settings.API_PERMISSION_NAME,
content_type=api_content_type, content_type=api_content_type,
codename=settings.API_PERMISSION_CODENAME codename=settings.API_PERMISSION_CODENAME,
) )
if created: if created:
api_permission.save() api_permission.save()
@ -67,10 +67,13 @@ def can_view(user):
viewing is granted and msg is a message (can be None). viewing is granted and msg is a message (can be None).
""" """
kwargs = { kwargs = {
'app_label': settings.API_CONTENT_TYPE_APP_LABEL, "app_label": settings.API_CONTENT_TYPE_APP_LABEL,
'codename': settings.API_PERMISSION_CODENAME "codename": settings.API_PERMISSION_CODENAME,
} }
permission = '%(app_label)s.%(codename)s' % kwargs permission = "%(app_label)s.%(codename)s" % kwargs
can = user.has_perm(permission) can = user.has_perm(permission)
return can, None if can else _("You don't have the right to see this" return (
" application."), (permission,) can,
None if can else _("You don't have the right to see this" " application."),
(permission,),
)

View file

@ -41,9 +41,7 @@ class ExpiringTokenAuthentication(TokenAuthentication):
user, token = base.authenticate_credentials(key) user, token = base.authenticate_credentials(key)
# Check that the genration time of the token is not too old # Check that the genration time of the token is not too old
token_duration = datetime.timedelta( token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION)
seconds=settings.API_TOKEN_DURATION
)
utc_now = datetime.datetime.now(datetime.timezone.utc) utc_now = datetime.datetime.now(datetime.timezone.utc)
if token.created < utc_now - token_duration: if token.created < utc_now - token_duration:
raise exceptions.AuthenticationFailed(_("The token has expired.")) raise exceptions.AuthenticationFailed(_("The token has expired."))

View file

@ -38,8 +38,9 @@ class PageSizedPagination(pagination.PageNumberPagination):
max_page_size: The maximum number of results a page can output no max_page_size: The maximum number of results a page can output no
matter what is requested. 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 max_page_size = 10000
def get_page_size(self, request): def get_page_size(self, request):

View file

@ -55,17 +55,21 @@ def _get_param_in_view(view, param_name):
AssertionError: None of the getter function or the attribute are AssertionError: None of the getter function or the attribute are
defined in the view. defined in the view.
""" """
assert hasattr(view, 'get_' + param_name) \ assert (
or getattr(view, param_name, None) is not None, ( hasattr(view, "get_" + param_name)
'cannot apply {} on a view that does not set ' or getattr(view, param_name, None) is not None
'`.{}` or have a `.get_{}()` method.' ), (
).format(self.__class__.__name__, param_name, param_name) "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): if hasattr(view, "get_" + param_name):
param = getattr(view, 'get_' + param_name)() param = getattr(view, "get_" + param_name)()
assert param is not None, ( assert param is not None, ("{}.get_{}() returned None").format(
'{}.get_{}() returned None' view.__class__.__name__, param_name
).format(view.__class__.__name__, param_name) )
return param return param
return getattr(view, param_name) return getattr(view, param_name)
@ -97,7 +101,7 @@ class ACLPermission(permissions.BasePermission):
rest_framework.exception.MethodNotAllowed: The requested method rest_framework.exception.MethodNotAllowed: The requested method
is not allowed for this view. 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: if method not in perms_map:
raise exceptions.MethodNotAllowed(method) raise exceptions.MethodNotAllowed(method)
@ -123,7 +127,7 @@ class ACLPermission(permissions.BasePermission):
""" """
# Workaround to ensure ACLPermissions are not applied # Workaround to ensure ACLPermissions are not applied
# to the root view when using DefaultRouter. # to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False): if getattr(view, "_ignore_model_permissions", False):
return True return True
if not request.user or not request.user.is_authenticated: if not request.user or not request.user.is_authenticated:
@ -148,22 +152,22 @@ class AutodetectACLPermission(permissions.BasePermission):
""" """
perms_map = { perms_map = {
'GET': [can_see_api, lambda model: model.can_view_all], "GET": [can_see_api, lambda model: model.can_view_all],
'OPTIONS': [can_see_api, lambda model: model.can_view_all], "OPTIONS": [can_see_api, lambda model: model.can_view_all],
'HEAD': [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], "POST": [can_see_api, lambda model: model.can_create],
'PUT': [], # No restrictions, apply to objects "PUT": [], # No restrictions, apply to objects
'PATCH': [], # No restrictions, apply to objects "PATCH": [], # No restrictions, apply to objects
'DELETE': [], # No restrictions, apply to objects "DELETE": [], # No restrictions, apply to objects
} }
perms_obj_map = { perms_obj_map = {
'GET': [can_see_api, lambda obj: obj.can_view], "GET": [can_see_api, lambda obj: obj.can_view],
'OPTIONS': [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], "HEAD": [can_see_api, lambda obj: obj.can_view],
'POST': [], # No restrictions, apply to models "POST": [], # No restrictions, apply to models
'PUT': [can_see_api, lambda obj: obj.can_edit], "PUT": [can_see_api, lambda obj: obj.can_edit],
'PATCH': [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], "DELETE": [can_see_api, lambda obj: obj.can_delete],
} }
def get_required_permissions(self, method, model): def get_required_permissions(self, method, model):
@ -210,7 +214,7 @@ class AutodetectACLPermission(permissions.BasePermission):
@staticmethod @staticmethod
def _queryset(view): def _queryset(view):
return _get_param_in_view(view, 'queryset') return _get_param_in_view(view, "queryset")
def has_permission(self, request, view): def has_permission(self, request, view):
"""Check that the user has the model-based permissions to perform """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 # Workaround to ensure ACLPermissions are not applied
# to the root view when using DefaultRouter. # to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False): if getattr(view, "_ignore_model_permissions", False):
return True return True
if not request.user or not request.user.is_authenticated: if not request.user or not request.user.is_authenticated:
@ -274,7 +278,7 @@ class AutodetectACLPermission(permissions.BasePermission):
# to make another lookup. # to make another lookup.
raise Http404 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]: if not read_perms(request.user)[0]:
raise Http404 raise Http404

View file

@ -74,7 +74,7 @@ class AllViewsRouter(DefaultRouter):
Returns: Returns:
The name to use for this route. The name to use for this route.
""" """
return pattern.split('/')[-1] return pattern.split("/")[-1]
def get_api_root_view(self, schema_urls=None, api_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. """Create a class-based view to use as the API root.
@ -102,12 +102,10 @@ class AllViewsRouter(DefaultRouter):
if schema_urls and self.schema_title: if schema_urls and self.schema_title:
view_renderers += list(self.schema_renderers) view_renderers += list(self.schema_renderers)
schema_generator = SchemaGenerator( schema_generator = SchemaGenerator(
title=self.schema_title, title=self.schema_title, patterns=schema_urls
patterns=schema_urls
) )
schema_media_types = [ schema_media_types = [
renderer.media_type renderer.media_type for renderer in self.schema_renderers
for renderer in self.schema_renderers
] ]
class APIRoot(views.APIView): class APIRoot(views.APIView):
@ -128,14 +126,14 @@ class AllViewsRouter(DefaultRouter):
namespace = request.resolver_match.namespace namespace = request.resolver_match.namespace
for key, url_name in api_root_dict.items(): for key, url_name in api_root_dict.items():
if namespace: if namespace:
url_name = namespace + ':' + url_name url_name = namespace + ":" + url_name
try: try:
ret[key] = reverse( ret[key] = reverse(
url_name, url_name,
args=args, args=args,
kwargs=kwargs, kwargs=kwargs,
request=request, request=request,
format=kwargs.get('format', None) format=kwargs.get("format", None),
) )
except NoReverseMatch: except NoReverseMatch:
# Don't bail out if eg. no list routes exist, only detail routes. # Don't bail out if eg. no list routes exist, only detail routes.

File diff suppressed because it is too large Load diff

View file

@ -24,28 +24,24 @@
# RestFramework config for API # RestFramework config for API
REST_FRAMEWORK = { REST_FRAMEWORK = {
'URL_FIELD_NAME': 'api_url', "URL_FIELD_NAME": "api_url",
'DEFAULT_AUTHENTICATION_CLASSES': ( "DEFAULT_AUTHENTICATION_CLASSES": (
'api.authentication.ExpiringTokenAuthentication', "api.authentication.ExpiringTokenAuthentication",
'rest_framework.authentication.SessionAuthentication', "rest_framework.authentication.SessionAuthentication",
), ),
'DEFAULT_PERMISSION_CLASSES': ( "DEFAULT_PERMISSION_CLASSES": ("api.permissions.AutodetectACLPermission",),
'api.permissions.AutodetectACLPermission', "DEFAULT_PAGINATION_CLASS": "api.pagination.PageSizedPagination",
), "PAGE_SIZE": 100,
'DEFAULT_PAGINATION_CLASS': 'api.pagination.PageSizedPagination',
'PAGE_SIZE': 100
} }
# API permission settings # API permission settings
API_CONTENT_TYPE_APP_LABEL = 'api' API_CONTENT_TYPE_APP_LABEL = "api"
API_CONTENT_TYPE_MODEL = 'api' API_CONTENT_TYPE_MODEL = "api"
API_PERMISSION_NAME = 'Can use the API' API_PERMISSION_NAME = "Can use the API"
API_PERMISSION_CODENAME = 'use_api' API_PERMISSION_CODENAME = "use_api"
# Activate token authentication # Activate token authentication
API_APPS = ( API_APPS = ("rest_framework.authtoken",)
'rest_framework.authtoken',
)
# The expiration time for an authentication token # The expiration time for an authentication token
API_TOKEN_DURATION = 86400 # 24 hours API_TOKEN_DURATION = 86400 # 24 hours

View file

@ -50,171 +50,170 @@ class APIEndpointsTestCase(APITestCase):
superuser: A superuser (with all permissions) used for the tests and superuser: A superuser (with all permissions) used for the tests and
initialized at the beggining of this test case. initialized at the beggining of this test case.
""" """
no_auth_endpoints = [
'/api/' no_auth_endpoints = ["/api/"]
]
auth_no_perm_endpoints = [] auth_no_perm_endpoints = []
auth_perm_endpoints = [ auth_perm_endpoints = [
'/api/cotisations/article/', "/api/cotisations/article/",
'/api/cotisations/article/1/', "/api/cotisations/article/1/",
'/api/cotisations/banque/', "/api/cotisations/banque/",
'/api/cotisations/banque/1/', "/api/cotisations/banque/1/",
'/api/cotisations/cotisation/', "/api/cotisations/cotisation/",
'/api/cotisations/cotisation/1/', "/api/cotisations/cotisation/1/",
'/api/cotisations/facture/', "/api/cotisations/facture/",
'/api/cotisations/facture/1/', "/api/cotisations/facture/1/",
'/api/cotisations/paiement/', "/api/cotisations/paiement/",
'/api/cotisations/paiement/1/', "/api/cotisations/paiement/1/",
'/api/cotisations/vente/', "/api/cotisations/vente/",
'/api/cotisations/vente/1/', "/api/cotisations/vente/1/",
'/api/machines/domain/', "/api/machines/domain/",
'/api/machines/domain/1/', "/api/machines/domain/1/",
'/api/machines/extension/', "/api/machines/extension/",
'/api/machines/extension/1/', "/api/machines/extension/1/",
'/api/machines/interface/', "/api/machines/interface/",
'/api/machines/interface/1/', "/api/machines/interface/1/",
'/api/machines/iplist/', "/api/machines/iplist/",
'/api/machines/iplist/1/', "/api/machines/iplist/1/",
'/api/machines/iptype/', "/api/machines/iptype/",
'/api/machines/iptype/1/', "/api/machines/iptype/1/",
'/api/machines/ipv6list/', "/api/machines/ipv6list/",
'/api/machines/ipv6list/1/', "/api/machines/ipv6list/1/",
'/api/machines/machine/', "/api/machines/machine/",
'/api/machines/machine/1/', "/api/machines/machine/1/",
'/api/machines/machinetype/', "/api/machines/machinetype/",
'/api/machines/machinetype/1/', "/api/machines/machinetype/1/",
'/api/machines/mx/', "/api/machines/mx/",
'/api/machines/mx/1/', "/api/machines/mx/1/",
'/api/machines/nas/', "/api/machines/nas/",
'/api/machines/nas/1/', "/api/machines/nas/1/",
'/api/machines/ns/', "/api/machines/ns/",
'/api/machines/ns/1/', "/api/machines/ns/1/",
'/api/machines/ouvertureportlist/', "/api/machines/ouvertureportlist/",
'/api/machines/ouvertureportlist/1/', "/api/machines/ouvertureportlist/1/",
'/api/machines/ouvertureport/', "/api/machines/ouvertureport/",
'/api/machines/ouvertureport/1/', "/api/machines/ouvertureport/1/",
'/api/machines/servicelink/', "/api/machines/servicelink/",
'/api/machines/servicelink/1/', "/api/machines/servicelink/1/",
'/api/machines/service/', "/api/machines/service/",
'/api/machines/service/1/', "/api/machines/service/1/",
'/api/machines/soa/', "/api/machines/soa/",
'/api/machines/soa/1/', "/api/machines/soa/1/",
'/api/machines/srv/', "/api/machines/srv/",
'/api/machines/srv/1/', "/api/machines/srv/1/",
'/api/machines/txt/', "/api/machines/txt/",
'/api/machines/txt/1/', "/api/machines/txt/1/",
'/api/machines/vlan/', "/api/machines/vlan/",
'/api/machines/vlan/1/', "/api/machines/vlan/1/",
'/api/preferences/optionaluser/', "/api/preferences/optionaluser/",
'/api/preferences/optionalmachine/', "/api/preferences/optionalmachine/",
'/api/preferences/optionaltopologie/', "/api/preferences/optionaltopologie/",
'/api/preferences/generaloption/', "/api/preferences/generaloption/",
'/api/preferences/service/', "/api/preferences/service/",
'/api/preferences/service/1/', "/api/preferences/service/1/",
'/api/preferences/assooption/', "/api/preferences/assooption/",
'/api/preferences/homeoption/', "/api/preferences/homeoption/",
'/api/preferences/mailmessageoption/', "/api/preferences/mailmessageoption/",
'/api/topologie/acesspoint/', "/api/topologie/acesspoint/",
# 2nd machine to be create (machines_machine_1, topologie_accesspoint_1) # 2nd machine to be create (machines_machine_1, topologie_accesspoint_1)
'/api/topologie/acesspoint/2/', "/api/topologie/acesspoint/2/",
'/api/topologie/building/', "/api/topologie/building/",
'/api/topologie/building/1/', "/api/topologie/building/1/",
'/api/topologie/constructorswitch/', "/api/topologie/constructorswitch/",
'/api/topologie/constructorswitch/1/', "/api/topologie/constructorswitch/1/",
'/api/topologie/modelswitch/', "/api/topologie/modelswitch/",
'/api/topologie/modelswitch/1/', "/api/topologie/modelswitch/1/",
'/api/topologie/room/', "/api/topologie/room/",
'/api/topologie/room/1/', "/api/topologie/room/1/",
'/api/topologie/server/', "/api/topologie/server/",
# 3rd machine to be create (machines_machine_1, topologie_accesspoint_1, # 3rd machine to be create (machines_machine_1, topologie_accesspoint_1,
# topologie_server_1) # topologie_server_1)
'/api/topologie/server/3/', "/api/topologie/server/3/",
'/api/topologie/stack/', "/api/topologie/stack/",
'/api/topologie/stack/1/', "/api/topologie/stack/1/",
'/api/topologie/switch/', "/api/topologie/switch/",
# 4th machine to be create (machines_machine_1, topologie_accesspoint_1, # 4th machine to be create (machines_machine_1, topologie_accesspoint_1,
# topologie_server_1, topologie_switch_1) # topologie_server_1, topologie_switch_1)
'/api/topologie/switch/4/', "/api/topologie/switch/4/",
'/api/topologie/switchbay/', "/api/topologie/switchbay/",
'/api/topologie/switchbay/1/', "/api/topologie/switchbay/1/",
'/api/topologie/switchport/', "/api/topologie/switchport/",
'/api/topologie/switchport/1/', "/api/topologie/switchport/1/",
'/api/topologie/switchport/2/', "/api/topologie/switchport/2/",
'/api/topologie/switchport/3/', "/api/topologie/switchport/3/",
'/api/users/adherent/', "/api/users/adherent/",
# 3rd user to be create (stduser, superuser, users_adherent_1) # 3rd user to be create (stduser, superuser, users_adherent_1)
'/api/users/adherent/3/', "/api/users/adherent/3/",
'/api/users/ban/', "/api/users/ban/",
'/api/users/ban/1/', "/api/users/ban/1/",
'/api/users/club/', "/api/users/club/",
# 4th user to be create (stduser, superuser, users_adherent_1, # 4th user to be create (stduser, superuser, users_adherent_1,
# users_club_1) # users_club_1)
'/api/users/club/4/', "/api/users/club/4/",
'/api/users/listright/', "/api/users/listright/",
# TODO: Merge !145 # TODO: Merge !145
# '/api/users/listright/1/', # '/api/users/listright/1/',
'/api/users/school/', "/api/users/school/",
'/api/users/school/1/', "/api/users/school/1/",
'/api/users/serviceuser/', "/api/users/serviceuser/",
'/api/users/serviceuser/1/', "/api/users/serviceuser/1/",
'/api/users/shell/', "/api/users/shell/",
'/api/users/shell/1/', "/api/users/shell/1/",
'/api/users/user/', "/api/users/user/",
'/api/users/user/1/', "/api/users/user/1/",
'/api/users/whitelist/', "/api/users/whitelist/",
'/api/users/whitelist/1/', "/api/users/whitelist/1/",
'/api/dns/zones/', "/api/dns/zones/",
'/api/dhcp/hostmacip/', "/api/dhcp/hostmacip/",
'/api/mailing/standard', "/api/mailing/standard",
'/api/mailing/club', "/api/mailing/club",
'/api/services/regen/', "/api/services/regen/",
] ]
not_found_endpoints = [ not_found_endpoints = [
'/api/cotisations/article/4242/', "/api/cotisations/article/4242/",
'/api/cotisations/banque/4242/', "/api/cotisations/banque/4242/",
'/api/cotisations/cotisation/4242/', "/api/cotisations/cotisation/4242/",
'/api/cotisations/facture/4242/', "/api/cotisations/facture/4242/",
'/api/cotisations/paiement/4242/', "/api/cotisations/paiement/4242/",
'/api/cotisations/vente/4242/', "/api/cotisations/vente/4242/",
'/api/machines/domain/4242/', "/api/machines/domain/4242/",
'/api/machines/extension/4242/', "/api/machines/extension/4242/",
'/api/machines/interface/4242/', "/api/machines/interface/4242/",
'/api/machines/iplist/4242/', "/api/machines/iplist/4242/",
'/api/machines/iptype/4242/', "/api/machines/iptype/4242/",
'/api/machines/ipv6list/4242/', "/api/machines/ipv6list/4242/",
'/api/machines/machine/4242/', "/api/machines/machine/4242/",
'/api/machines/machinetype/4242/', "/api/machines/machinetype/4242/",
'/api/machines/mx/4242/', "/api/machines/mx/4242/",
'/api/machines/nas/4242/', "/api/machines/nas/4242/",
'/api/machines/ns/4242/', "/api/machines/ns/4242/",
'/api/machines/ouvertureportlist/4242/', "/api/machines/ouvertureportlist/4242/",
'/api/machines/ouvertureport/4242/', "/api/machines/ouvertureport/4242/",
'/api/machines/servicelink/4242/', "/api/machines/servicelink/4242/",
'/api/machines/service/4242/', "/api/machines/service/4242/",
'/api/machines/soa/4242/', "/api/machines/soa/4242/",
'/api/machines/srv/4242/', "/api/machines/srv/4242/",
'/api/machines/txt/4242/', "/api/machines/txt/4242/",
'/api/machines/vlan/4242/', "/api/machines/vlan/4242/",
'/api/preferences/service/4242/', "/api/preferences/service/4242/",
'/api/topologie/acesspoint/4242/', "/api/topologie/acesspoint/4242/",
'/api/topologie/building/4242/', "/api/topologie/building/4242/",
'/api/topologie/constructorswitch/4242/', "/api/topologie/constructorswitch/4242/",
'/api/topologie/modelswitch/4242/', "/api/topologie/modelswitch/4242/",
'/api/topologie/room/4242/', "/api/topologie/room/4242/",
'/api/topologie/server/4242/', "/api/topologie/server/4242/",
'/api/topologie/stack/4242/', "/api/topologie/stack/4242/",
'/api/topologie/switch/4242/', "/api/topologie/switch/4242/",
'/api/topologie/switchbay/4242/', "/api/topologie/switchbay/4242/",
'/api/topologie/switchport/4242/', "/api/topologie/switchport/4242/",
'/api/users/adherent/4242/', "/api/users/adherent/4242/",
'/api/users/ban/4242/', "/api/users/ban/4242/",
'/api/users/club/4242/', "/api/users/club/4242/",
'/api/users/listright/4242/', "/api/users/listright/4242/",
'/api/users/school/4242/', "/api/users/school/4242/",
'/api/users/serviceuser/4242/', "/api/users/serviceuser/4242/",
'/api/users/shell/4242/', "/api/users/shell/4242/",
'/api/users/user/4242/', "/api/users/user/4242/",
'/api/users/whitelist/4242/', "/api/users/whitelist/4242/",
] ]
stduser = None stduser = None
@ -232,26 +231,18 @@ class APIEndpointsTestCase(APITestCase):
# A user with no rights # A user with no rights
cls.stduser = users.User.objects.create_user( cls.stduser = users.User.objects.create_user(
"apistduser", "apistduser", "apistduser", "apistduser@example.net", "apistduser"
"apistduser",
"apistduser@example.net",
"apistduser"
) )
# A user with all the rights # A user with all the rights
cls.superuser = users.User.objects.create_superuser( cls.superuser = users.User.objects.create_superuser(
"apisuperuser", "apisuperuser", "apisuperuser", "apisuperuser@example.net", "apisuperuser"
"apisuperuser",
"apisuperuser@example.net",
"apisuperuser"
) )
# Creates 1 instance for each object so the "details" endpoints # Creates 1 instance for each object so the "details" endpoints
# can be tested too. Objects need to be created in the right order. # can be tested too. Objects need to be created in the right order.
# Dependencies (relatedFields, ...) are highlighted by a comment at # Dependencies (relatedFields, ...) are highlighted by a comment at
# the end of the concerned line (# Dep <model>). # the end of the concerned line (# Dep <model>).
cls.users_school_1 = users.School.objects.create( cls.users_school_1 = users.School.objects.create(name="users_school_1")
name="users_school_1"
)
cls.users_school_1.save() cls.users_school_1.save()
cls.users_listshell_1 = users.ListShell.objects.create( cls.users_listshell_1 = users.ListShell.objects.create(
shell="users_listshell_1" shell="users_listshell_1"
@ -270,7 +261,7 @@ class APIEndpointsTestCase(APITestCase):
registered=datetime.datetime.now(datetime.timezone.utc), registered=datetime.datetime.now(datetime.timezone.utc),
telephone="0123456789", telephone="0123456789",
uid_number=21102, uid_number=21102,
rezo_rez_uid=21102 rezo_rez_uid=21102,
) )
cls.users_user_1 = cls.users_adherent_1 cls.users_user_1 = cls.users_adherent_1
cls.cotisations_article_1 = cotisations.Article.objects.create( cls.cotisations_article_1 = cotisations.Article.objects.create(
@ -278,14 +269,14 @@ class APIEndpointsTestCase(APITestCase):
prix=10, prix=10,
duration=1, duration=1,
type_user=cotisations.Article.USER_TYPES[0][0], type_user=cotisations.Article.USER_TYPES[0][0],
type_cotisation=cotisations.Article.COTISATION_TYPE[0][0] type_cotisation=cotisations.Article.COTISATION_TYPE[0][0],
) )
cls.cotisations_banque_1 = cotisations.Banque.objects.create( cls.cotisations_banque_1 = cotisations.Banque.objects.create(
name="cotisations_banque_1" name="cotisations_banque_1"
) )
cls.cotisations_paiement_1 = cotisations.Paiement.objects.create( cls.cotisations_paiement_1 = cotisations.Paiement.objects.create(
moyen="cotisations_paiement_1", moyen="cotisations_paiement_1",
type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0] type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0],
) )
cls.cotisations_facture_1 = cotisations.Facture.objects.create( cls.cotisations_facture_1 = cotisations.Facture.objects.create(
user=cls.users_user_1, # Dep users.User user=cls.users_user_1, # Dep users.User
@ -294,7 +285,7 @@ class APIEndpointsTestCase(APITestCase):
cheque="1234567890", cheque="1234567890",
date=datetime.datetime.now(datetime.timezone.utc), date=datetime.datetime.now(datetime.timezone.utc),
valid=True, valid=True,
control=False control=False,
) )
cls.cotisations_vente_1 = cotisations.Vente.objects.create( cls.cotisations_vente_1 = cotisations.Vente.objects.create(
facture=cls.cotisations_facture_1, # Dep cotisations.Facture facture=cls.cotisations_facture_1, # Dep cotisations.Facture
@ -302,18 +293,18 @@ class APIEndpointsTestCase(APITestCase):
name="cotisations_vente_1", name="cotisations_vente_1",
prix=10, prix=10,
duration=1, duration=1,
type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0] type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0],
) )
# A cotisation is automatically created by the Vente object and # A cotisation is automatically created by the Vente object and
# trying to create another cotisation associated with this vente # trying to create another cotisation associated with this vente
# will fail so we simply retrieve it so it can be used in the tests # will fail so we simply retrieve it so it can be used in the tests
cls.cotisations_cotisation_1 = cotisations.Cotisation.objects.get( cls.cotisations_cotisation_1 = cotisations.Cotisation.objects.get(
vente=cls.cotisations_vente_1, # Dep cotisations.Vente vente=cls.cotisations_vente_1 # Dep cotisations.Vente
) )
cls.machines_machine_1 = machines.Machine.objects.create( cls.machines_machine_1 = machines.Machine.objects.create(
user=cls.users_user_1, # Dep users.User user=cls.users_user_1, # Dep users.User
name="machines_machine_1", name="machines_machine_1",
active=True active=True,
) )
cls.machines_ouvertureportlist_1 = machines.OuverturePortList.objects.create( cls.machines_ouvertureportlist_1 = machines.OuverturePortList.objects.create(
name="machines_ouvertureportlist_1" name="machines_ouvertureportlist_1"
@ -324,19 +315,17 @@ class APIEndpointsTestCase(APITestCase):
refresh=86400, refresh=86400,
retry=7200, retry=7200,
expire=3600000, expire=3600000,
ttl=172800 ttl=172800,
) )
cls.machines_extension_1 = machines.Extension.objects.create( cls.machines_extension_1 = machines.Extension.objects.create(
name="machines_extension_1", name="machines_extension_1",
need_infra=False, need_infra=False,
# Do not set origin because of circular dependency # Do not set origin because of circular dependency
origin_v6="2001:db8:1234::", origin_v6="2001:db8:1234::",
soa=cls.machines_soa_1 # Dep machines.SOA soa=cls.machines_soa_1, # Dep machines.SOA
) )
cls.machines_vlan_1 = machines.Vlan.objects.create( cls.machines_vlan_1 = machines.Vlan.objects.create(
vlan_id=0, vlan_id=0, name="machines_vlan_1", comment="machines Vlan 1"
name="machines_vlan_1",
comment="machines Vlan 1"
) )
cls.machines_iptype_1 = machines.IpType.objects.create( cls.machines_iptype_1 = machines.IpType.objects.create(
type="machines_iptype_1", type="machines_iptype_1",
@ -346,13 +335,12 @@ class APIEndpointsTestCase(APITestCase):
domaine_ip_stop="10.0.0.255", domaine_ip_stop="10.0.0.255",
prefix_v6="2001:db8:1234::", prefix_v6="2001:db8:1234::",
vlan=cls.machines_vlan_1, # Dep machines.Vlan vlan=cls.machines_vlan_1, # Dep machines.Vlan
ouverture_ports=cls.machines_ouvertureportlist_1 # Dep machines.OuverturePortList ouverture_ports=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList
) )
# All IPs in the IpType range are autocreated so we can't create # All IPs in the IpType range are autocreated so we can't create
# new ones and thus we only retrieve it if needed in the tests # new ones and thus we only retrieve it if needed in the tests
cls.machines_iplist_1 = machines.IpList.objects.get( cls.machines_iplist_1 = machines.IpList.objects.get(
ipv4="10.0.0.1", ipv4="10.0.0.1", ip_type=cls.machines_iptype_1 # Dep machines.IpType
ip_type=cls.machines_iptype_1, # Dep machines.IpType
) )
cls.machines_machinetype_1 = machines.MachineType.objects.create( cls.machines_machinetype_1 = machines.MachineType.objects.create(
type="machines_machinetype_1", type="machines_machinetype_1",
@ -375,16 +363,16 @@ class APIEndpointsTestCase(APITestCase):
cls.machines_mx_1 = machines.Mx.objects.create( cls.machines_mx_1 = machines.Mx.objects.create(
zone=cls.machines_extension_1, # Dep machines.Extension zone=cls.machines_extension_1, # Dep machines.Extension
priority=10, priority=10,
name=cls.machines_domain_1 # Dep machines.Domain name=cls.machines_domain_1, # Dep machines.Domain
) )
cls.machines_ns_1 = machines.Ns.objects.create( cls.machines_ns_1 = machines.Ns.objects.create(
zone=cls.machines_extension_1, # Dep machines.Extension zone=cls.machines_extension_1, # Dep machines.Extension
ns=cls.machines_domain_1 # Dep machines.Domain ns=cls.machines_domain_1, # Dep machines.Domain
) )
cls.machines_txt_1 = machines.Txt.objects.create( cls.machines_txt_1 = machines.Txt.objects.create(
zone=cls.machines_extension_1, # Dep machines.Extension zone=cls.machines_extension_1, # Dep machines.Extension
field1="machines_txt_1", field1="machines_txt_1",
field2="machies Txt 1" field2="machies Txt 1",
) )
cls.machines_srv_1 = machines.Srv.objects.create( cls.machines_srv_1 = machines.Srv.objects.create(
service="machines_srv_1", service="machines_srv_1",
@ -398,7 +386,7 @@ class APIEndpointsTestCase(APITestCase):
cls.machines_ipv6list_1 = machines.Ipv6List.objects.create( cls.machines_ipv6list_1 = machines.Ipv6List.objects.create(
ipv6="2001:db8:1234::", ipv6="2001:db8:1234::",
interface=cls.machines_interface_1, # Dep machines.Interface interface=cls.machines_interface_1, # Dep machines.Interface
slaac_ip=False slaac_ip=False,
) )
cls.machines_service_1 = machines.Service.objects.create( cls.machines_service_1 = machines.Service.objects.create(
service_type="machines_service_1", service_type="machines_service_1",
@ -410,45 +398,45 @@ class APIEndpointsTestCase(APITestCase):
service=cls.machines_service_1, # Dep machines.Service service=cls.machines_service_1, # Dep machines.Service
server=cls.machines_interface_1, # Dep machines.Interface server=cls.machines_interface_1, # Dep machines.Interface
last_regen=datetime.datetime.now(datetime.timezone.utc), last_regen=datetime.datetime.now(datetime.timezone.utc),
asked_regen=False asked_regen=False,
) )
cls.machines_ouvertureport_1 = machines.OuverturePort.objects.create( cls.machines_ouvertureport_1 = machines.OuverturePort.objects.create(
begin=1, begin=1,
end=2, end=2,
port_list=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList port_list=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList
protocole=machines.OuverturePort.TCP, protocole=machines.OuverturePort.TCP,
io=machines.OuverturePort.OUT io=machines.OuverturePort.OUT,
) )
cls.machines_nas_1 = machines.Nas.objects.create( cls.machines_nas_1 = machines.Nas.objects.create(
name="machines_nas_1", name="machines_nas_1",
nas_type=cls.machines_machinetype_1, # Dep machines.MachineType nas_type=cls.machines_machinetype_1, # Dep machines.MachineType
machine_type=cls.machines_machinetype_1, # Dep machines.MachineType machine_type=cls.machines_machinetype_1, # Dep machines.MachineType
port_access_mode=machines.Nas.AUTH[0][0], port_access_mode=machines.Nas.AUTH[0][0],
autocapture_mac=False autocapture_mac=False,
) )
cls.preferences_service_1 = preferences.Service.objects.create( cls.preferences_service_1 = preferences.Service.objects.create(
name="preferences_service_1", name="preferences_service_1",
url="https://example.net", url="https://example.net",
description="preferences Service 1", description="preferences Service 1",
image="/media/logo/none.png" image="/media/logo/none.png",
) )
cls.topologie_stack_1 = topologie.Stack.objects.create( cls.topologie_stack_1 = topologie.Stack.objects.create(
name="topologie_stack_1", name="topologie_stack_1",
stack_id="1", stack_id="1",
details="topologie Stack 1", details="topologie Stack 1",
member_id_min=1, member_id_min=1,
member_id_max=10 member_id_max=10,
) )
cls.topologie_accespoint_1 = topologie.AccessPoint.objects.create( cls.topologie_accespoint_1 = topologie.AccessPoint.objects.create(
user=cls.users_user_1, # Dep users.User user=cls.users_user_1, # Dep users.User
name="machines_machine_1", name="machines_machine_1",
active=True, active=True,
location="topologie AccessPoint 1" location="topologie AccessPoint 1",
) )
cls.topologie_server_1 = topologie.Server.objects.create( cls.topologie_server_1 = topologie.Server.objects.create(
user=cls.users_user_1, # Dep users.User user=cls.users_user_1, # Dep users.User
name="machines_machine_1", name="machines_machine_1",
active=True active=True,
) )
cls.topologie_building_1 = topologie.Building.objects.create( cls.topologie_building_1 = topologie.Building.objects.create(
name="topologie_building_1" name="topologie_building_1"
@ -456,14 +444,14 @@ class APIEndpointsTestCase(APITestCase):
cls.topologie_switchbay_1 = topologie.SwitchBay.objects.create( cls.topologie_switchbay_1 = topologie.SwitchBay.objects.create(
name="topologie_switchbay_1", name="topologie_switchbay_1",
building=cls.topologie_building_1, # Dep topologie.Building building=cls.topologie_building_1, # Dep topologie.Building
info="topologie SwitchBay 1" info="topologie SwitchBay 1",
) )
cls.topologie_constructorswitch_1 = topologie.ConstructorSwitch.objects.create( cls.topologie_constructorswitch_1 = topologie.ConstructorSwitch.objects.create(
name="topologie_constructorswitch_1" name="topologie_constructorswitch_1"
) )
cls.topologie_modelswitch_1 = topologie.ModelSwitch.objects.create( cls.topologie_modelswitch_1 = topologie.ModelSwitch.objects.create(
reference="topologie_modelswitch_1", reference="topologie_modelswitch_1",
constructor=cls.topologie_constructorswitch_1 # Dep topologie.ConstructorSwitch constructor=cls.topologie_constructorswitch_1, # Dep topologie.ConstructorSwitch
) )
cls.topologie_switch_1 = topologie.Switch.objects.create( cls.topologie_switch_1 = topologie.Switch.objects.create(
user=cls.users_user_1, # Dep users.User user=cls.users_user_1, # Dep users.User
@ -473,11 +461,10 @@ class APIEndpointsTestCase(APITestCase):
stack=cls.topologie_stack_1, # Dep topologie.Stack stack=cls.topologie_stack_1, # Dep topologie.Stack
stack_member_id=1, stack_member_id=1,
model=cls.topologie_modelswitch_1, # Dep topologie.ModelSwitch model=cls.topologie_modelswitch_1, # Dep topologie.ModelSwitch
switchbay=cls.topologie_switchbay_1 # Dep topologie.SwitchBay switchbay=cls.topologie_switchbay_1, # Dep topologie.SwitchBay
) )
cls.topologie_room_1 = topologie.Room.objects.create( cls.topologie_room_1 = topologie.Room.objects.create(
name="topologie_romm_1", name="topologie_romm_1", details="topologie Room 1"
details="topologie Room 1"
) )
cls.topologie_port_1 = topologie.Port.objects.create( cls.topologie_port_1 = topologie.Port.objects.create(
switch=cls.topologie_switch_1, # Dep topologie.Switch switch=cls.topologie_switch_1, # Dep topologie.Switch
@ -485,7 +472,7 @@ class APIEndpointsTestCase(APITestCase):
room=cls.topologie_room_1, # Dep topologie.Room room=cls.topologie_room_1, # Dep topologie.Room
radius=topologie.Port.STATES[0][0], radius=topologie.Port.STATES[0][0],
vlan_force=cls.machines_vlan_1, # Dep machines.Vlan vlan_force=cls.machines_vlan_1, # Dep machines.Vlan
details="topologie_switch_1" details="topologie_switch_1",
) )
cls.topologie_port_2 = topologie.Port.objects.create( cls.topologie_port_2 = topologie.Port.objects.create(
switch=cls.topologie_switch_1, # Dep topologie.Switch switch=cls.topologie_switch_1, # Dep topologie.Switch
@ -493,7 +480,7 @@ class APIEndpointsTestCase(APITestCase):
machine_interface=cls.machines_interface_1, # Dep machines.Interface machine_interface=cls.machines_interface_1, # Dep machines.Interface
radius=topologie.Port.STATES[0][0], radius=topologie.Port.STATES[0][0],
vlan_force=cls.machines_vlan_1, # Dep machines.Vlan vlan_force=cls.machines_vlan_1, # Dep machines.Vlan
details="topologie_switch_1" details="topologie_switch_1",
) )
cls.topologie_port_3 = topologie.Port.objects.create( cls.topologie_port_3 = topologie.Port.objects.create(
switch=cls.topologie_switch_1, # Dep topologie.Switch switch=cls.topologie_switch_1, # Dep topologie.Switch
@ -501,14 +488,15 @@ class APIEndpointsTestCase(APITestCase):
room=cls.topologie_room_1, # Dep topologie.Room room=cls.topologie_room_1, # Dep topologie.Room
radius=topologie.Port.STATES[0][0], radius=topologie.Port.STATES[0][0],
# Do not defines related because circular dependency # Dep machines.Vlan # Do not defines related because circular dependency # Dep machines.Vlan
details="topologie_switch_1" details="topologie_switch_1",
) )
cls.users_ban_1 = users.Ban.objects.create( cls.users_ban_1 = users.Ban.objects.create(
user=cls.users_user_1, # Dep users.User user=cls.users_user_1, # Dep users.User
raison="users Ban 1", raison="users Ban 1",
date_start=datetime.datetime.now(datetime.timezone.utc), date_start=datetime.datetime.now(datetime.timezone.utc),
date_end=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1), date_end=datetime.datetime.now(datetime.timezone.utc)
state=users.Ban.STATES[0][0] + datetime.timedelta(days=1),
state=users.Ban.STATES[0][0],
) )
cls.users_club_1 = users.Club.objects.create( cls.users_club_1 = users.Club.objects.create(
password="password", password="password",
@ -524,7 +512,7 @@ class APIEndpointsTestCase(APITestCase):
registered=datetime.datetime.now(datetime.timezone.utc), registered=datetime.datetime.now(datetime.timezone.utc),
telephone="0123456789", telephone="0123456789",
uid_number=21103, uid_number=21103,
rezo_rez_uid=21103 rezo_rez_uid=21103,
) )
# Need merge of MR145 to work # Need merge of MR145 to work
# TODO: Merge !145 # TODO: Merge !145
@ -539,17 +527,17 @@ class APIEndpointsTestCase(APITestCase):
last_login=datetime.datetime.now(datetime.timezone.utc), last_login=datetime.datetime.now(datetime.timezone.utc),
pseudo="usersserviceuser1", pseudo="usersserviceuser1",
access_group=users.ServiceUser.ACCESS[0][0], access_group=users.ServiceUser.ACCESS[0][0],
comment="users ServiceUser 1" comment="users ServiceUser 1",
) )
cls.users_whitelist_1 = users.Whitelist.objects.create( cls.users_whitelist_1 = users.Whitelist.objects.create(
user=cls.users_user_1, user=cls.users_user_1,
raison="users Whitelist 1", raison="users Whitelist 1",
date_start=datetime.datetime.now(datetime.timezone.utc), date_start=datetime.datetime.now(datetime.timezone.utc),
date_end=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1) date_end=datetime.datetime.now(datetime.timezone.utc)
+ datetime.timedelta(days=1),
) )
def check_responses_code(self, urls, expected_code, formats=None, def check_responses_code(self, urls, expected_code, formats=None, assert_more=None):
assert_more=None):
"""Utility function to test if a list of urls answer an expected code. """Utility function to test if a list of urls answer an expected code.
Args: Args:
@ -665,17 +653,20 @@ class APIEndpointsTestCase(APITestCase):
""" """
self.client.force_authenticate(user=self.superuser) self.client.force_authenticate(user=self.superuser)
urls = self.no_auth_endpoints + self.auth_no_perm_endpoints + \ urls = (
self.auth_perm_endpoints self.no_auth_endpoints
+ self.auth_no_perm_endpoints
+ self.auth_perm_endpoints
)
def assert_more(response, url, format): def assert_more(response, url, format):
"""Assert the response is valid json when format is json""" """Assert the response is valid json when format is json"""
if format is 'json': if format is "json":
json.loads(response.content.decode()) json.loads(response.content.decode())
self.check_responses_code(urls, codes.ok, self.check_responses_code(
formats=[None, 'json', 'api'], urls, codes.ok, formats=[None, "json", "api"], assert_more=assert_more
assert_more=assert_more) )
class APIPaginationTestCase(APITestCase): class APIPaginationTestCase(APITestCase):
@ -688,56 +679,56 @@ class APIPaginationTestCase(APITestCase):
""" """
endpoints = [ endpoints = [
'/api/cotisations/article/', "/api/cotisations/article/",
'/api/cotisations/banque/', "/api/cotisations/banque/",
'/api/cotisations/cotisation/', "/api/cotisations/cotisation/",
'/api/cotisations/facture/', "/api/cotisations/facture/",
'/api/cotisations/paiement/', "/api/cotisations/paiement/",
'/api/cotisations/vente/', "/api/cotisations/vente/",
'/api/machines/domain/', "/api/machines/domain/",
'/api/machines/extension/', "/api/machines/extension/",
'/api/machines/interface/', "/api/machines/interface/",
'/api/machines/iplist/', "/api/machines/iplist/",
'/api/machines/iptype/', "/api/machines/iptype/",
'/api/machines/ipv6list/', "/api/machines/ipv6list/",
'/api/machines/machine/', "/api/machines/machine/",
'/api/machines/machinetype/', "/api/machines/machinetype/",
'/api/machines/mx/', "/api/machines/mx/",
'/api/machines/nas/', "/api/machines/nas/",
'/api/machines/ns/', "/api/machines/ns/",
'/api/machines/ouvertureportlist/', "/api/machines/ouvertureportlist/",
'/api/machines/ouvertureport/', "/api/machines/ouvertureport/",
'/api/machines/servicelink/', "/api/machines/servicelink/",
'/api/machines/service/', "/api/machines/service/",
'/api/machines/soa/', "/api/machines/soa/",
'/api/machines/srv/', "/api/machines/srv/",
'/api/machines/txt/', "/api/machines/txt/",
'/api/machines/vlan/', "/api/machines/vlan/",
'/api/preferences/service/', "/api/preferences/service/",
'/api/topologie/acesspoint/', "/api/topologie/acesspoint/",
'/api/topologie/building/', "/api/topologie/building/",
'/api/topologie/constructorswitch/', "/api/topologie/constructorswitch/",
'/api/topologie/modelswitch/', "/api/topologie/modelswitch/",
'/api/topologie/room/', "/api/topologie/room/",
'/api/topologie/server/', "/api/topologie/server/",
'/api/topologie/stack/', "/api/topologie/stack/",
'/api/topologie/switch/', "/api/topologie/switch/",
'/api/topologie/switchbay/', "/api/topologie/switchbay/",
'/api/topologie/switchport/', "/api/topologie/switchport/",
'/api/users/adherent/', "/api/users/adherent/",
'/api/users/ban/', "/api/users/ban/",
'/api/users/club/', "/api/users/club/",
'/api/users/listright/', "/api/users/listright/",
'/api/users/school/', "/api/users/school/",
'/api/users/serviceuser/', "/api/users/serviceuser/",
'/api/users/shell/', "/api/users/shell/",
'/api/users/user/', "/api/users/user/",
'/api/users/whitelist/', "/api/users/whitelist/",
'/api/dns/zones/', "/api/dns/zones/",
'/api/dhcp/hostmacip/', "/api/dhcp/hostmacip/",
'/api/mailing/standard', "/api/mailing/standard",
'/api/mailing/club', "/api/mailing/club",
'/api/services/regen/', "/api/services/regen/",
] ]
superuser = None superuser = None
@ -745,14 +736,14 @@ class APIPaginationTestCase(APITestCase):
def setUpTestData(cls): def setUpTestData(cls):
# A user with all the rights # A user with all the rights
# We need to use a different username than for the first # We need to use a different username than for the first
# test case because TestCase is using rollbacks which don't # test case because TestCase is using rollbacks which don't
# trigger the ldap_sync() thus the LDAP still have data about # trigger the ldap_sync() thus the LDAP still have data about
# the old users. # the old users.
cls.superuser = users.User.objects.create_superuser( cls.superuser = users.User.objects.create_superuser(
"apisuperuser2", "apisuperuser2",
"apisuperuser2", "apisuperuser2",
"apisuperuser2@example.net", "apisuperuser2@example.net",
"apisuperuser2" "apisuperuser2",
) )
@classmethod @classmethod
@ -771,10 +762,10 @@ class APIPaginationTestCase(APITestCase):
self.client.force_authenticate(self.superuser) self.client.force_authenticate(self.superuser)
for url in self.endpoints: for url in self.endpoints:
with self.subTest(url=url): with self.subTest(url=url):
response = self.client.get(url, format='json') response = self.client.get(url, format="json")
res_json = json.loads(response.content.decode()) res_json = json.loads(response.content.decode())
assert 'count' in res_json.keys() assert "count" in res_json.keys()
assert 'next' in res_json.keys() assert "next" in res_json.keys()
assert 'previous' in res_json.keys() assert "previous" in res_json.keys()
assert 'results' in res_json.keys() assert "results" in res_json.keys()
assert not len('results') > 100 assert not len("results") > 100

View file

@ -34,95 +34,109 @@ from .routers import AllViewsRouter
router = AllViewsRouter() router = AllViewsRouter()
# COTISATIONS # COTISATIONS
router.register_viewset(r'cotisations/facture', views.FactureViewSet) router.register_viewset(r"cotisations/facture", views.FactureViewSet)
router.register_viewset(r'cotisations/vente', views.VenteViewSet) router.register_viewset(r"cotisations/vente", views.VenteViewSet)
router.register_viewset(r'cotisations/article', views.ArticleViewSet) router.register_viewset(r"cotisations/article", views.ArticleViewSet)
router.register_viewset(r'cotisations/banque', views.BanqueViewSet) router.register_viewset(r"cotisations/banque", views.BanqueViewSet)
router.register_viewset(r'cotisations/paiement', views.PaiementViewSet) router.register_viewset(r"cotisations/paiement", views.PaiementViewSet)
router.register_viewset(r'cotisations/cotisation', views.CotisationViewSet) router.register_viewset(r"cotisations/cotisation", views.CotisationViewSet)
# MACHINES # MACHINES
router.register_viewset(r'machines/machine', views.MachineViewSet) router.register_viewset(r"machines/machine", views.MachineViewSet)
router.register_viewset(r'machines/machinetype', views.MachineTypeViewSet) router.register_viewset(r"machines/machinetype", views.MachineTypeViewSet)
router.register_viewset(r'machines/iptype', views.IpTypeViewSet) router.register_viewset(r"machines/iptype", views.IpTypeViewSet)
router.register_viewset(r'machines/vlan', views.VlanViewSet) router.register_viewset(r"machines/vlan", views.VlanViewSet)
router.register_viewset(r'machines/nas', views.NasViewSet) router.register_viewset(r"machines/nas", views.NasViewSet)
router.register_viewset(r'machines/soa', views.SOAViewSet) router.register_viewset(r"machines/soa", views.SOAViewSet)
router.register_viewset(r'machines/extension', views.ExtensionViewSet) router.register_viewset(r"machines/extension", views.ExtensionViewSet)
router.register_viewset(r'machines/mx', views.MxViewSet) router.register_viewset(r"machines/mx", views.MxViewSet)
router.register_viewset(r'machines/ns', views.NsViewSet) router.register_viewset(r"machines/ns", views.NsViewSet)
router.register_viewset(r'machines/txt', views.TxtViewSet) router.register_viewset(r"machines/txt", views.TxtViewSet)
router.register_viewset(r'machines/dname', views.DNameViewSet) router.register_viewset(r"machines/dname", views.DNameViewSet)
router.register_viewset(r'machines/srv', views.SrvViewSet) router.register_viewset(r"machines/srv", views.SrvViewSet)
router.register_viewset(r'machines/sshfp', views.SshFpViewSet) router.register_viewset(r"machines/sshfp", views.SshFpViewSet)
router.register_viewset(r'machines/interface', views.InterfaceViewSet) router.register_viewset(r"machines/interface", views.InterfaceViewSet)
router.register_viewset(r'machines/ipv6list', views.Ipv6ListViewSet) router.register_viewset(r"machines/ipv6list", views.Ipv6ListViewSet)
router.register_viewset(r'machines/domain', views.DomainViewSet) router.register_viewset(r"machines/domain", views.DomainViewSet)
router.register_viewset(r'machines/iplist', views.IpListViewSet) router.register_viewset(r"machines/iplist", views.IpListViewSet)
router.register_viewset(r'machines/service', views.ServiceViewSet) router.register_viewset(r"machines/service", views.ServiceViewSet)
router.register_viewset(r'machines/servicelink', views.ServiceLinkViewSet, base_name='servicelink') router.register_viewset(
router.register_viewset(r'machines/ouvertureportlist', views.OuverturePortListViewSet) r"machines/servicelink", views.ServiceLinkViewSet, base_name="servicelink"
router.register_viewset(r'machines/ouvertureport', views.OuverturePortViewSet) )
router.register_viewset(r'machines/role', views.RoleViewSet) router.register_viewset(r"machines/ouvertureportlist", views.OuverturePortListViewSet)
router.register_viewset(r"machines/ouvertureport", views.OuverturePortViewSet)
router.register_viewset(r"machines/role", views.RoleViewSet)
# PREFERENCES # PREFERENCES
router.register_view(r'preferences/optionaluser', views.OptionalUserView), router.register_view(r"preferences/optionaluser", views.OptionalUserView),
router.register_view(r'preferences/optionalmachine', views.OptionalMachineView), router.register_view(r"preferences/optionalmachine", views.OptionalMachineView),
router.register_view(r'preferences/optionaltopologie', views.OptionalTopologieView), router.register_view(r"preferences/optionaltopologie", views.OptionalTopologieView),
router.register_view(r'preferences/radiusoption', views.RadiusOptionView), router.register_view(r"preferences/radiusoption", views.RadiusOptionView),
router.register_view(r'preferences/generaloption', views.GeneralOptionView), router.register_view(r"preferences/generaloption", views.GeneralOptionView),
router.register_viewset(r'preferences/service', views.HomeServiceViewSet, base_name='homeservice'), router.register_viewset(
router.register_view(r'preferences/assooption', views.AssoOptionView), r"preferences/service", views.HomeServiceViewSet, base_name="homeservice"
router.register_view(r'preferences/homeoption', views.HomeOptionView), ),
router.register_view(r'preferences/mailmessageoption', views.MailMessageOptionView), 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 # TOPOLOGIE
router.register_viewset(r'topologie/stack', views.StackViewSet) router.register_viewset(r"topologie/stack", views.StackViewSet)
router.register_viewset(r'topologie/acesspoint', views.AccessPointViewSet) router.register_viewset(r"topologie/acesspoint", views.AccessPointViewSet)
router.register_viewset(r'topologie/switch', views.SwitchViewSet) router.register_viewset(r"topologie/switch", views.SwitchViewSet)
router.register_viewset(r'topologie/server', views.ServerViewSet) router.register_viewset(r"topologie/server", views.ServerViewSet)
router.register_viewset(r'topologie/modelswitch', views.ModelSwitchViewSet) router.register_viewset(r"topologie/modelswitch", views.ModelSwitchViewSet)
router.register_viewset(r'topologie/constructorswitch', views.ConstructorSwitchViewSet) router.register_viewset(r"topologie/constructorswitch", views.ConstructorSwitchViewSet)
router.register_viewset(r'topologie/switchbay', views.SwitchBayViewSet) router.register_viewset(r"topologie/switchbay", views.SwitchBayViewSet)
router.register_viewset(r'topologie/building', views.BuildingViewSet) router.register_viewset(r"topologie/building", views.BuildingViewSet)
router.register_viewset(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport') router.register_viewset(
router.register_viewset(r'topologie/portprofile', views.PortProfileViewSet, base_name='portprofile') r"topologie/switchport", views.SwitchPortViewSet, base_name="switchport"
router.register_viewset(r'topologie/room', views.RoomViewSet) )
router.register(r'topologie/portprofile', views.PortProfileViewSet) router.register_viewset(
r"topologie/portprofile", views.PortProfileViewSet, base_name="portprofile"
)
router.register_viewset(r"topologie/room", views.RoomViewSet)
router.register(r"topologie/portprofile", views.PortProfileViewSet)
# USERS # USERS
router.register_viewset(r'users/user', views.UserViewSet, base_name='user') router.register_viewset(r"users/user", views.UserViewSet, base_name="user")
router.register_viewset(r'users/homecreation', views.HomeCreationViewSet, base_name='homecreation') router.register_viewset(
router.register_viewset(r'users/normaluser', views.NormalUserViewSet, base_name='normaluser') r"users/homecreation", views.HomeCreationViewSet, base_name="homecreation"
router.register_viewset(r'users/criticaluser', views.CriticalUserViewSet, base_name='criticaluser') )
router.register_viewset(r'users/club', views.ClubViewSet) router.register_viewset(
router.register_viewset(r'users/adherent', views.AdherentViewSet) r"users/normaluser", views.NormalUserViewSet, base_name="normaluser"
router.register_viewset(r'users/serviceuser', views.ServiceUserViewSet) )
router.register_viewset(r'users/school', views.SchoolViewSet) router.register_viewset(
router.register_viewset(r'users/listright', views.ListRightViewSet) r"users/criticaluser", views.CriticalUserViewSet, base_name="criticaluser"
router.register_viewset(r'users/shell', views.ShellViewSet, base_name='shell') )
router.register_viewset(r'users/ban', views.BanViewSet) router.register_viewset(r"users/club", views.ClubViewSet)
router.register_viewset(r'users/whitelist', views.WhitelistViewSet) router.register_viewset(r"users/adherent", views.AdherentViewSet)
router.register_viewset(r'users/emailaddress', views.EMailAddressViewSet) router.register_viewset(r"users/serviceuser", views.ServiceUserViewSet)
router.register_viewset(r"users/school", views.SchoolViewSet)
router.register_viewset(r"users/listright", views.ListRightViewSet)
router.register_viewset(r"users/shell", views.ShellViewSet, base_name="shell")
router.register_viewset(r"users/ban", views.BanViewSet)
router.register_viewset(r"users/whitelist", views.WhitelistViewSet)
router.register_viewset(r"users/emailaddress", views.EMailAddressViewSet)
# SERVICE REGEN # SERVICE REGEN
router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen') router.register_viewset(
r"services/regen", views.ServiceRegenViewSet, base_name="serviceregen"
)
# DHCP # DHCP
router.register_view(r'dhcp/hostmacip', views.HostMacIpView), router.register_view(r"dhcp/hostmacip", views.HostMacIpView),
# LOCAL EMAILS # LOCAL EMAILS
router.register_view(r'localemail/users', views.LocalEmailUsersView), router.register_view(r"localemail/users", views.LocalEmailUsersView),
# Firewall # Firewall
router.register_view(r'firewall/subnet-ports', views.SubnetPortsOpenView), router.register_view(r"firewall/subnet-ports", views.SubnetPortsOpenView),
router.register_view(r'firewall/interface-ports', views.InterfacePortsOpenView), router.register_view(r"firewall/interface-ports", views.InterfacePortsOpenView),
# Switches config # Switches config
router.register_view(r'switchs/ports-config', views.SwitchPortView), router.register_view(r"switchs/ports-config", views.SwitchPortView),
router.register_view(r'switchs/role', views.RoleView), router.register_view(r"switchs/role", views.RoleView),
# Reminder # Reminder
router.register_view(r'reminder/get-users', views.ReminderView), router.register_view(r"reminder/get-users", views.ReminderView),
# DNS # DNS
router.register_view(r'dns/zones', views.DNSZonesView), router.register_view(r"dns/zones", views.DNSZonesView),
router.register_view(r'dns/reverse-zones', views.DNSReverseZonesView), router.register_view(r"dns/reverse-zones", views.DNSReverseZonesView),
# MAILING # MAILING
router.register_view(r'mailing/standard', views.StandardMailingView), router.register_view(r"mailing/standard", views.StandardMailingView),
router.register_view(r'mailing/club', views.ClubMailingView), router.register_view(r"mailing/club", views.ClubMailingView),
# TOKEN AUTHENTICATION # TOKEN AUTHENTICATION
router.register_view(r'token-auth', views.ObtainExpiringAuthToken) router.register_view(r"token-auth", views.ObtainExpiringAuthToken)
urlpatterns = [ urlpatterns = [url(r"^", include(router.urls))]
url(r'^', include(router.urls)),
]

View file

@ -52,12 +52,15 @@ from .permissions import ACLPermission
class FactureViewSet(viewsets.ReadOnlyModelViewSet): class FactureViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Facture` objects. """Exposes list and details of `cotisations.models.Facture` objects.
""" """
queryset = cotisations.Facture.objects.all() queryset = cotisations.Facture.objects.all()
serializer_class = serializers.FactureSerializer serializer_class = serializers.FactureSerializer
class FactureViewSet(viewsets.ReadOnlyModelViewSet): class FactureViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Facture` objects. """Exposes list and details of `cotisations.models.Facture` objects.
""" """
queryset = cotisations.BaseInvoice.objects.all() queryset = cotisations.BaseInvoice.objects.all()
serializer_class = serializers.BaseInvoiceSerializer serializer_class = serializers.BaseInvoiceSerializer
@ -65,6 +68,7 @@ class FactureViewSet(viewsets.ReadOnlyModelViewSet):
class VenteViewSet(viewsets.ReadOnlyModelViewSet): class VenteViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Vente` objects. """Exposes list and details of `cotisations.models.Vente` objects.
""" """
queryset = cotisations.Vente.objects.all() queryset = cotisations.Vente.objects.all()
serializer_class = serializers.VenteSerializer serializer_class = serializers.VenteSerializer
@ -72,6 +76,7 @@ class VenteViewSet(viewsets.ReadOnlyModelViewSet):
class ArticleViewSet(viewsets.ReadOnlyModelViewSet): class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Article` objects. """Exposes list and details of `cotisations.models.Article` objects.
""" """
queryset = cotisations.Article.objects.all() queryset = cotisations.Article.objects.all()
serializer_class = serializers.ArticleSerializer serializer_class = serializers.ArticleSerializer
@ -79,6 +84,7 @@ class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
class BanqueViewSet(viewsets.ReadOnlyModelViewSet): class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Banque` objects. """Exposes list and details of `cotisations.models.Banque` objects.
""" """
queryset = cotisations.Banque.objects.all() queryset = cotisations.Banque.objects.all()
serializer_class = serializers.BanqueSerializer serializer_class = serializers.BanqueSerializer
@ -86,6 +92,7 @@ class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
class PaiementViewSet(viewsets.ReadOnlyModelViewSet): class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Paiement` objects. """Exposes list and details of `cotisations.models.Paiement` objects.
""" """
queryset = cotisations.Paiement.objects.all() queryset = cotisations.Paiement.objects.all()
serializer_class = serializers.PaiementSerializer serializer_class = serializers.PaiementSerializer
@ -93,6 +100,7 @@ class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
class CotisationViewSet(viewsets.ReadOnlyModelViewSet): class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `cotisations.models.Cotisation` objects. """Exposes list and details of `cotisations.models.Cotisation` objects.
""" """
queryset = cotisations.Cotisation.objects.all() queryset = cotisations.Cotisation.objects.all()
serializer_class = serializers.CotisationSerializer serializer_class = serializers.CotisationSerializer
@ -103,6 +111,7 @@ class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
class MachineViewSet(viewsets.ReadOnlyModelViewSet): class MachineViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Machine` objects. """Exposes list and details of `machines.models.Machine` objects.
""" """
queryset = machines.Machine.objects.all() queryset = machines.Machine.objects.all()
serializer_class = serializers.MachineSerializer serializer_class = serializers.MachineSerializer
@ -110,6 +119,7 @@ class MachineViewSet(viewsets.ReadOnlyModelViewSet):
class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet): class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.MachineType` objects. """Exposes list and details of `machines.models.MachineType` objects.
""" """
queryset = machines.MachineType.objects.all() queryset = machines.MachineType.objects.all()
serializer_class = serializers.MachineTypeSerializer serializer_class = serializers.MachineTypeSerializer
@ -117,6 +127,7 @@ class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
class IpTypeViewSet(viewsets.ReadOnlyModelViewSet): class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.IpType` objects. """Exposes list and details of `machines.models.IpType` objects.
""" """
queryset = machines.IpType.objects.all() queryset = machines.IpType.objects.all()
serializer_class = serializers.IpTypeSerializer serializer_class = serializers.IpTypeSerializer
@ -124,6 +135,7 @@ class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
class VlanViewSet(viewsets.ReadOnlyModelViewSet): class VlanViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Vlan` objects. """Exposes list and details of `machines.models.Vlan` objects.
""" """
queryset = machines.Vlan.objects.all() queryset = machines.Vlan.objects.all()
serializer_class = serializers.VlanSerializer serializer_class = serializers.VlanSerializer
@ -131,6 +143,7 @@ class VlanViewSet(viewsets.ReadOnlyModelViewSet):
class NasViewSet(viewsets.ReadOnlyModelViewSet): class NasViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Nas` objects. """Exposes list and details of `machines.models.Nas` objects.
""" """
queryset = machines.Nas.objects.all() queryset = machines.Nas.objects.all()
serializer_class = serializers.NasSerializer serializer_class = serializers.NasSerializer
@ -138,6 +151,7 @@ class NasViewSet(viewsets.ReadOnlyModelViewSet):
class SOAViewSet(viewsets.ReadOnlyModelViewSet): class SOAViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.SOA` objects. """Exposes list and details of `machines.models.SOA` objects.
""" """
queryset = machines.SOA.objects.all() queryset = machines.SOA.objects.all()
serializer_class = serializers.SOASerializer serializer_class = serializers.SOASerializer
@ -145,6 +159,7 @@ class SOAViewSet(viewsets.ReadOnlyModelViewSet):
class ExtensionViewSet(viewsets.ReadOnlyModelViewSet): class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Extension` objects. """Exposes list and details of `machines.models.Extension` objects.
""" """
queryset = machines.Extension.objects.all() queryset = machines.Extension.objects.all()
serializer_class = serializers.ExtensionSerializer serializer_class = serializers.ExtensionSerializer
@ -152,6 +167,7 @@ class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
class MxViewSet(viewsets.ReadOnlyModelViewSet): class MxViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Mx` objects. """Exposes list and details of `machines.models.Mx` objects.
""" """
queryset = machines.Mx.objects.all() queryset = machines.Mx.objects.all()
serializer_class = serializers.MxSerializer serializer_class = serializers.MxSerializer
@ -159,6 +175,7 @@ class MxViewSet(viewsets.ReadOnlyModelViewSet):
class NsViewSet(viewsets.ReadOnlyModelViewSet): class NsViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Ns` objects. """Exposes list and details of `machines.models.Ns` objects.
""" """
queryset = machines.Ns.objects.all() queryset = machines.Ns.objects.all()
serializer_class = serializers.NsSerializer serializer_class = serializers.NsSerializer
@ -166,6 +183,7 @@ class NsViewSet(viewsets.ReadOnlyModelViewSet):
class TxtViewSet(viewsets.ReadOnlyModelViewSet): class TxtViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Txt` objects. """Exposes list and details of `machines.models.Txt` objects.
""" """
queryset = machines.Txt.objects.all() queryset = machines.Txt.objects.all()
serializer_class = serializers.TxtSerializer serializer_class = serializers.TxtSerializer
@ -173,6 +191,7 @@ class TxtViewSet(viewsets.ReadOnlyModelViewSet):
class DNameViewSet(viewsets.ReadOnlyModelViewSet): class DNameViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.DName` objects. """Exposes list and details of `machines.models.DName` objects.
""" """
queryset = machines.DName.objects.all() queryset = machines.DName.objects.all()
serializer_class = serializers.DNameSerializer serializer_class = serializers.DNameSerializer
@ -180,6 +199,7 @@ class DNameViewSet(viewsets.ReadOnlyModelViewSet):
class SrvViewSet(viewsets.ReadOnlyModelViewSet): class SrvViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Srv` objects. """Exposes list and details of `machines.models.Srv` objects.
""" """
queryset = machines.Srv.objects.all() queryset = machines.Srv.objects.all()
serializer_class = serializers.SrvSerializer serializer_class = serializers.SrvSerializer
@ -187,6 +207,7 @@ class SrvViewSet(viewsets.ReadOnlyModelViewSet):
class SshFpViewSet(viewsets.ReadOnlyModelViewSet): class SshFpViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.SshFp` objects. """Exposes list and details of `machines.models.SshFp` objects.
""" """
queryset = machines.SshFp.objects.all() queryset = machines.SshFp.objects.all()
serializer_class = serializers.SshFpSerializer serializer_class = serializers.SshFpSerializer
@ -194,6 +215,7 @@ class SshFpViewSet(viewsets.ReadOnlyModelViewSet):
class InterfaceViewSet(viewsets.ReadOnlyModelViewSet): class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Interface` objects. """Exposes list and details of `machines.models.Interface` objects.
""" """
queryset = machines.Interface.objects.all() queryset = machines.Interface.objects.all()
serializer_class = serializers.InterfaceSerializer serializer_class = serializers.InterfaceSerializer
@ -201,6 +223,7 @@ class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet): class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Ipv6List` objects. """Exposes list and details of `machines.models.Ipv6List` objects.
""" """
queryset = machines.Ipv6List.objects.all() queryset = machines.Ipv6List.objects.all()
serializer_class = serializers.Ipv6ListSerializer serializer_class = serializers.Ipv6ListSerializer
@ -208,6 +231,7 @@ class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
class DomainViewSet(viewsets.ReadOnlyModelViewSet): class DomainViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Domain` objects. """Exposes list and details of `machines.models.Domain` objects.
""" """
queryset = machines.Domain.objects.all() queryset = machines.Domain.objects.all()
serializer_class = serializers.DomainSerializer serializer_class = serializers.DomainSerializer
@ -215,6 +239,7 @@ class DomainViewSet(viewsets.ReadOnlyModelViewSet):
class IpListViewSet(viewsets.ReadOnlyModelViewSet): class IpListViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.IpList` objects. """Exposes list and details of `machines.models.IpList` objects.
""" """
queryset = machines.IpList.objects.all() queryset = machines.IpList.objects.all()
serializer_class = serializers.IpListSerializer serializer_class = serializers.IpListSerializer
@ -222,6 +247,7 @@ class IpListViewSet(viewsets.ReadOnlyModelViewSet):
class ServiceViewSet(viewsets.ReadOnlyModelViewSet): class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Service` objects. """Exposes list and details of `machines.models.Service` objects.
""" """
queryset = machines.Service.objects.all() queryset = machines.Service.objects.all()
serializer_class = serializers.ServiceSerializer serializer_class = serializers.ServiceSerializer
@ -229,6 +255,7 @@ class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet): class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Service_link` objects. """Exposes list and details of `machines.models.Service_link` objects.
""" """
queryset = machines.Service_link.objects.all() queryset = machines.Service_link.objects.all()
serializer_class = serializers.ServiceLinkSerializer serializer_class = serializers.ServiceLinkSerializer
@ -237,6 +264,7 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.OuverturePortList` """Exposes list and details of `machines.models.OuverturePortList`
objects. objects.
""" """
queryset = machines.OuverturePortList.objects.all() queryset = machines.OuverturePortList.objects.all()
serializer_class = serializers.OuverturePortListSerializer serializer_class = serializers.OuverturePortListSerializer
@ -244,6 +272,7 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet): class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.OuverturePort` objects. """Exposes list and details of `machines.models.OuverturePort` objects.
""" """
queryset = machines.OuverturePort.objects.all() queryset = machines.OuverturePort.objects.all()
serializer_class = serializers.OuverturePortSerializer serializer_class = serializers.OuverturePortSerializer
@ -251,6 +280,7 @@ class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
class RoleViewSet(viewsets.ReadOnlyModelViewSet): class RoleViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `machines.models.Machine` objects. """Exposes list and details of `machines.models.Machine` objects.
""" """
queryset = machines.Role.objects.all() queryset = machines.Role.objects.all()
serializer_class = serializers.RoleSerializer serializer_class = serializers.RoleSerializer
@ -259,11 +289,13 @@ class RoleViewSet(viewsets.ReadOnlyModelViewSet):
# Those views differ a bit because there is only one object # Those views differ a bit because there is only one object
# to display, so we don't bother with the listing part # to display, so we don't bother with the listing part
class OptionalUserView(generics.RetrieveAPIView): class OptionalUserView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.` settings. """Exposes details of `preferences.models.` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.OptionalUser.can_view_all]} perms_map = {"GET": [preferences.OptionalUser.can_view_all]}
serializer_class = serializers.OptionalUserSerializer serializer_class = serializers.OptionalUserSerializer
def get_object(self): def get_object(self):
@ -273,8 +305,9 @@ class OptionalUserView(generics.RetrieveAPIView):
class OptionalMachineView(generics.RetrieveAPIView): class OptionalMachineView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.OptionalMachine` settings. """Exposes details of `preferences.models.OptionalMachine` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.OptionalMachine.can_view_all]} perms_map = {"GET": [preferences.OptionalMachine.can_view_all]}
serializer_class = serializers.OptionalMachineSerializer serializer_class = serializers.OptionalMachineSerializer
def get_object(self): def get_object(self):
@ -284,8 +317,9 @@ class OptionalMachineView(generics.RetrieveAPIView):
class OptionalTopologieView(generics.RetrieveAPIView): class OptionalTopologieView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.OptionalTopologie` settings. """Exposes details of `preferences.models.OptionalTopologie` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.OptionalTopologie.can_view_all]} perms_map = {"GET": [preferences.OptionalTopologie.can_view_all]}
serializer_class = serializers.OptionalTopologieSerializer serializer_class = serializers.OptionalTopologieSerializer
def get_object(self): def get_object(self):
@ -295,8 +329,9 @@ class OptionalTopologieView(generics.RetrieveAPIView):
class RadiusOptionView(generics.RetrieveAPIView): class RadiusOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.OptionalTopologie` settings. """Exposes details of `preferences.models.OptionalTopologie` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.RadiusOption.can_view_all]} perms_map = {"GET": [preferences.RadiusOption.can_view_all]}
serializer_class = serializers.RadiusOptionSerializer serializer_class = serializers.RadiusOptionSerializer
def get_object(self): def get_object(self):
@ -306,8 +341,9 @@ class RadiusOptionView(generics.RetrieveAPIView):
class GeneralOptionView(generics.RetrieveAPIView): class GeneralOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.GeneralOption` settings. """Exposes details of `preferences.models.GeneralOption` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.GeneralOption.can_view_all]} perms_map = {"GET": [preferences.GeneralOption.can_view_all]}
serializer_class = serializers.GeneralOptionSerializer serializer_class = serializers.GeneralOptionSerializer
def get_object(self): def get_object(self):
@ -317,6 +353,7 @@ class GeneralOptionView(generics.RetrieveAPIView):
class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet): class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `preferences.models.Service` objects. """Exposes list and details of `preferences.models.Service` objects.
""" """
queryset = preferences.Service.objects.all() queryset = preferences.Service.objects.all()
serializer_class = serializers.HomeServiceSerializer serializer_class = serializers.HomeServiceSerializer
@ -324,8 +361,9 @@ class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet):
class AssoOptionView(generics.RetrieveAPIView): class AssoOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.AssoOption` settings. """Exposes details of `preferences.models.AssoOption` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.AssoOption.can_view_all]} perms_map = {"GET": [preferences.AssoOption.can_view_all]}
serializer_class = serializers.AssoOptionSerializer serializer_class = serializers.AssoOptionSerializer
def get_object(self): def get_object(self):
@ -335,8 +373,9 @@ class AssoOptionView(generics.RetrieveAPIView):
class HomeOptionView(generics.RetrieveAPIView): class HomeOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.HomeOption` settings. """Exposes details of `preferences.models.HomeOption` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.HomeOption.can_view_all]} perms_map = {"GET": [preferences.HomeOption.can_view_all]}
serializer_class = serializers.HomeOptionSerializer serializer_class = serializers.HomeOptionSerializer
def get_object(self): def get_object(self):
@ -346,8 +385,9 @@ class HomeOptionView(generics.RetrieveAPIView):
class MailMessageOptionView(generics.RetrieveAPIView): class MailMessageOptionView(generics.RetrieveAPIView):
"""Exposes details of `preferences.models.MailMessageOption` settings. """Exposes details of `preferences.models.MailMessageOption` settings.
""" """
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [preferences.MailMessageOption.can_view_all]} perms_map = {"GET": [preferences.MailMessageOption.can_view_all]}
serializer_class = serializers.MailMessageOptionSerializer serializer_class = serializers.MailMessageOptionSerializer
def get_object(self): def get_object(self):
@ -360,6 +400,7 @@ class MailMessageOptionView(generics.RetrieveAPIView):
class StackViewSet(viewsets.ReadOnlyModelViewSet): class StackViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Stack` objects. """Exposes list and details of `topologie.models.Stack` objects.
""" """
queryset = topologie.Stack.objects.all() queryset = topologie.Stack.objects.all()
serializer_class = serializers.StackSerializer serializer_class = serializers.StackSerializer
@ -367,6 +408,7 @@ class StackViewSet(viewsets.ReadOnlyModelViewSet):
class AccessPointViewSet(viewsets.ReadOnlyModelViewSet): class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.AccessPoint` objects. """Exposes list and details of `topologie.models.AccessPoint` objects.
""" """
queryset = topologie.AccessPoint.objects.all() queryset = topologie.AccessPoint.objects.all()
serializer_class = serializers.AccessPointSerializer serializer_class = serializers.AccessPointSerializer
@ -374,6 +416,7 @@ class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
class SwitchViewSet(viewsets.ReadOnlyModelViewSet): class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Switch` objects. """Exposes list and details of `topologie.models.Switch` objects.
""" """
queryset = topologie.Switch.objects.all() queryset = topologie.Switch.objects.all()
serializer_class = serializers.SwitchSerializer serializer_class = serializers.SwitchSerializer
@ -381,6 +424,7 @@ class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
class ServerViewSet(viewsets.ReadOnlyModelViewSet): class ServerViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Server` objects. """Exposes list and details of `topologie.models.Server` objects.
""" """
queryset = topologie.Server.objects.all() queryset = topologie.Server.objects.all()
serializer_class = serializers.ServerSerializer serializer_class = serializers.ServerSerializer
@ -388,6 +432,7 @@ class ServerViewSet(viewsets.ReadOnlyModelViewSet):
class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet): class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.ModelSwitch` objects. """Exposes list and details of `topologie.models.ModelSwitch` objects.
""" """
queryset = topologie.ModelSwitch.objects.all() queryset = topologie.ModelSwitch.objects.all()
serializer_class = serializers.ModelSwitchSerializer serializer_class = serializers.ModelSwitchSerializer
@ -396,6 +441,7 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.ConstructorSwitch` """Exposes list and details of `topologie.models.ConstructorSwitch`
objects. objects.
""" """
queryset = topologie.ConstructorSwitch.objects.all() queryset = topologie.ConstructorSwitch.objects.all()
serializer_class = serializers.ConstructorSwitchSerializer serializer_class = serializers.ConstructorSwitchSerializer
@ -403,6 +449,7 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet): class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.SwitchBay` objects. """Exposes list and details of `topologie.models.SwitchBay` objects.
""" """
queryset = topologie.SwitchBay.objects.all() queryset = topologie.SwitchBay.objects.all()
serializer_class = serializers.SwitchBaySerializer serializer_class = serializers.SwitchBaySerializer
@ -410,6 +457,7 @@ class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
class BuildingViewSet(viewsets.ReadOnlyModelViewSet): class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Building` objects. """Exposes list and details of `topologie.models.Building` objects.
""" """
queryset = topologie.Building.objects.all() queryset = topologie.Building.objects.all()
serializer_class = serializers.BuildingSerializer serializer_class = serializers.BuildingSerializer
@ -417,6 +465,7 @@ class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet): class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Port` objects. """Exposes list and details of `topologie.models.Port` objects.
""" """
queryset = topologie.Port.objects.all() queryset = topologie.Port.objects.all()
serializer_class = serializers.SwitchPortSerializer serializer_class = serializers.SwitchPortSerializer
@ -424,6 +473,7 @@ class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.PortProfile` objects. """Exposes list and details of `topologie.models.PortProfile` objects.
""" """
queryset = topologie.PortProfile.objects.all() queryset = topologie.PortProfile.objects.all()
serializer_class = serializers.PortProfileSerializer serializer_class = serializers.PortProfileSerializer
@ -431,6 +481,7 @@ class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
class RoomViewSet(viewsets.ReadOnlyModelViewSet): class RoomViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.Room` objects. """Exposes list and details of `topologie.models.Room` objects.
""" """
queryset = topologie.Room.objects.all() queryset = topologie.Room.objects.all()
serializer_class = serializers.RoomSerializer serializer_class = serializers.RoomSerializer
@ -438,6 +489,7 @@ class RoomViewSet(viewsets.ReadOnlyModelViewSet):
class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `topologie.models.PortProfile` objects. """Exposes list and details of `topologie.models.PortProfile` objects.
""" """
queryset = topologie.PortProfile.objects.all() queryset = topologie.PortProfile.objects.all()
serializer_class = serializers.PortProfileSerializer serializer_class = serializers.PortProfileSerializer
@ -448,6 +500,7 @@ class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
class UserViewSet(viewsets.ReadOnlyModelViewSet): class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Users` objects. """Exposes list and details of `users.models.Users` objects.
""" """
queryset = users.User.objects.all() queryset = users.User.objects.all()
serializer_class = serializers.UserSerializer serializer_class = serializers.UserSerializer
@ -455,18 +508,25 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet):
class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet): class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes infos of `users.models.Users` objects to create homes. """Exposes infos of `users.models.Users` objects to create homes.
""" """
queryset = users.User.objects.exclude(Q(state=users.User.STATE_DISABLED) | Q(state=users.User.STATE_NOT_YET_ACTIVE) | Q(state=users.User.STATE_FULL_ARCHIVE))
queryset = users.User.objects.exclude(
Q(state=users.User.STATE_DISABLED)
| Q(state=users.User.STATE_NOT_YET_ACTIVE)
| Q(state=users.User.STATE_FULL_ARCHIVE)
)
serializer_class = serializers.BasicUserSerializer serializer_class = serializers.BasicUserSerializer
class NormalUserViewSet(viewsets.ReadOnlyModelViewSet): class NormalUserViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes infos of `users.models.Users`without specific rights objects.""" """Exposes infos of `users.models.Users`without specific rights objects."""
queryset = users.User.objects.exclude(groups__listright__critical=True).distinct() queryset = users.User.objects.exclude(groups__listright__critical=True).distinct()
serializer_class = serializers.BasicUserSerializer serializer_class = serializers.BasicUserSerializer
class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet): class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes infos of `users.models.Users`without specific rights objects.""" """Exposes infos of `users.models.Users`without specific rights objects."""
queryset = users.User.objects.filter(groups__listright__critical=True).distinct() queryset = users.User.objects.filter(groups__listright__critical=True).distinct()
serializer_class = serializers.BasicUserSerializer serializer_class = serializers.BasicUserSerializer
@ -474,6 +534,7 @@ class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet):
class ClubViewSet(viewsets.ReadOnlyModelViewSet): class ClubViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Club` objects. """Exposes list and details of `users.models.Club` objects.
""" """
queryset = users.Club.objects.all() queryset = users.Club.objects.all()
serializer_class = serializers.ClubSerializer serializer_class = serializers.ClubSerializer
@ -481,6 +542,7 @@ class ClubViewSet(viewsets.ReadOnlyModelViewSet):
class AdherentViewSet(viewsets.ReadOnlyModelViewSet): class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Adherent` objects. """Exposes list and details of `users.models.Adherent` objects.
""" """
queryset = users.Adherent.objects.all() queryset = users.Adherent.objects.all()
serializer_class = serializers.AdherentSerializer serializer_class = serializers.AdherentSerializer
@ -488,6 +550,7 @@ class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet): class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.ServiceUser` objects. """Exposes list and details of `users.models.ServiceUser` objects.
""" """
queryset = users.ServiceUser.objects.all() queryset = users.ServiceUser.objects.all()
serializer_class = serializers.ServiceUserSerializer serializer_class = serializers.ServiceUserSerializer
@ -495,6 +558,7 @@ class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
class SchoolViewSet(viewsets.ReadOnlyModelViewSet): class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.School` objects. """Exposes list and details of `users.models.School` objects.
""" """
queryset = users.School.objects.all() queryset = users.School.objects.all()
serializer_class = serializers.SchoolSerializer serializer_class = serializers.SchoolSerializer
@ -502,6 +566,7 @@ class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
class ListRightViewSet(viewsets.ReadOnlyModelViewSet): class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.ListRight` objects. """Exposes list and details of `users.models.ListRight` objects.
""" """
queryset = users.ListRight.objects.all() queryset = users.ListRight.objects.all()
serializer_class = serializers.ListRightSerializer serializer_class = serializers.ListRightSerializer
@ -509,6 +574,7 @@ class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
class ShellViewSet(viewsets.ReadOnlyModelViewSet): class ShellViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.ListShell` objects. """Exposes list and details of `users.models.ListShell` objects.
""" """
queryset = users.ListShell.objects.all() queryset = users.ListShell.objects.all()
serializer_class = serializers.ShellSerializer serializer_class = serializers.ShellSerializer
@ -516,6 +582,7 @@ class ShellViewSet(viewsets.ReadOnlyModelViewSet):
class BanViewSet(viewsets.ReadOnlyModelViewSet): class BanViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Ban` objects. """Exposes list and details of `users.models.Ban` objects.
""" """
queryset = users.Ban.objects.all() queryset = users.Ban.objects.all()
serializer_class = serializers.BanSerializer serializer_class = serializers.BanSerializer
@ -523,6 +590,7 @@ class BanViewSet(viewsets.ReadOnlyModelViewSet):
class WhitelistViewSet(viewsets.ReadOnlyModelViewSet): class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.Whitelist` objects. """Exposes list and details of `users.models.Whitelist` objects.
""" """
queryset = users.Whitelist.objects.all() queryset = users.Whitelist.objects.all()
serializer_class = serializers.WhitelistSerializer serializer_class = serializers.WhitelistSerializer
@ -530,14 +598,13 @@ class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet): class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet):
"""Exposes list and details of `users.models.EMailAddress` objects. """Exposes list and details of `users.models.EMailAddress` objects.
""" """
serializer_class = serializers.EMailAddressSerializer serializer_class = serializers.EMailAddressSerializer
queryset = users.EMailAddress.objects.none() queryset = users.EMailAddress.objects.none()
def get_queryset(self): def get_queryset(self):
if preferences.OptionalUser.get_cached_value( if preferences.OptionalUser.get_cached_value("local_email_accounts_enabled"):
'local_email_accounts_enabled'): return users.EMailAddress.objects.filter(user__local_email_enabled=True)
return (users.EMailAddress.objects
.filter(user__local_email_enabled=True))
else: else:
return users.EMailAddress.objects.none() return users.EMailAddress.objects.none()
@ -548,34 +615,47 @@ class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet):
class ServiceRegenViewSet(viewsets.ModelViewSet): class ServiceRegenViewSet(viewsets.ModelViewSet):
"""Exposes list and details of the services to regen """Exposes list and details of the services to regen
""" """
serializer_class = serializers.ServiceRegenSerializer serializer_class = serializers.ServiceRegenSerializer
def get_queryset(self): def get_queryset(self):
queryset = machines.Service_link.objects.select_related( queryset = machines.Service_link.objects.select_related(
'server__domain' "server__domain"
).select_related( ).select_related("service")
'service' if "hostname" in self.request.GET:
) hostname = self.request.GET["hostname"]
if 'hostname' in self.request.GET:
hostname = self.request.GET['hostname']
queryset = queryset.filter(server__domain__name__iexact=hostname) queryset = queryset.filter(server__domain__name__iexact=hostname)
return queryset return queryset
# Config des switches # Config des switches
class SwitchPortView(generics.ListAPIView): class SwitchPortView(generics.ListAPIView):
"""Output each port of a switch, to be serialized with """Output each port of a switch, to be serialized with
additionnal informations (profiles etc) additionnal informations (profiles etc)
""" """
queryset = topologie.Switch.objects.all().select_related("switchbay").select_related("model__constructor").prefetch_related("ports__custom_profile__vlan_tagged").prefetch_related("ports__custom_profile__vlan_untagged").prefetch_related("ports__machine_interface__domain__extension").prefetch_related("ports__room")
queryset = (
topologie.Switch.objects.all()
.select_related("switchbay")
.select_related("model__constructor")
.prefetch_related("ports__custom_profile__vlan_tagged")
.prefetch_related("ports__custom_profile__vlan_untagged")
.prefetch_related("ports__machine_interface__domain__extension")
.prefetch_related("ports__room")
)
serializer_class = serializers.SwitchPortSerializer serializer_class = serializers.SwitchPortSerializer
# Rappel fin adhésion # Rappel fin adhésion
class ReminderView(generics.ListAPIView): class ReminderView(generics.ListAPIView):
"""Output for users to remind an end of their subscription. """Output for users to remind an end of their subscription.
""" """
queryset = preferences.Reminder.objects.all() queryset = preferences.Reminder.objects.all()
serializer_class = serializers.ReminderSerializer serializer_class = serializers.ReminderSerializer
@ -583,7 +663,8 @@ class ReminderView(generics.ListAPIView):
class RoleView(generics.ListAPIView): class RoleView(generics.ListAPIView):
"""Output of roles for each server """Output of roles for each server
""" """
queryset = machines.Role.objects.all().prefetch_related('servers')
queryset = machines.Role.objects.all().prefetch_related("servers")
serializer_class = serializers.RoleSerializer serializer_class = serializers.RoleSerializer
@ -593,13 +674,12 @@ class RoleView(generics.ListAPIView):
class LocalEmailUsersView(generics.ListAPIView): class LocalEmailUsersView(generics.ListAPIView):
"""Exposes all the aliases of the users that activated the internal address """Exposes all the aliases of the users that activated the internal address
""" """
serializer_class = serializers.LocalEmailUsersSerializer serializer_class = serializers.LocalEmailUsersSerializer
def get_queryset(self): def get_queryset(self):
if preferences.OptionalUser.get_cached_value( if preferences.OptionalUser.get_cached_value("local_email_accounts_enabled"):
'local_email_accounts_enabled'): return users.User.objects.filter(local_email_enabled=True)
return (users.User.objects
.filter(local_email_enabled=True))
else: else:
return users.User.objects.none() return users.User.objects.none()
@ -611,6 +691,7 @@ class HostMacIpView(generics.ListAPIView):
"""Exposes the associations between hostname, mac address and IPv4 in """Exposes the associations between hostname, mac address and IPv4 in
order to build the DHCP lease files. order to build the DHCP lease files.
""" """
serializer_class = serializers.HostMacIpSerializer serializer_class = serializers.HostMacIpSerializer
def get_queryset(self): def get_queryset(self):
@ -619,6 +700,7 @@ class HostMacIpView(generics.ListAPIView):
# Firewall # Firewall
class SubnetPortsOpenView(generics.ListAPIView): class SubnetPortsOpenView(generics.ListAPIView):
queryset = machines.IpType.objects.all() queryset = machines.IpType.objects.all()
serializer_class = serializers.SubnetPortsOpenSerializer serializer_class = serializers.SubnetPortsOpenSerializer
@ -636,14 +718,19 @@ class DNSZonesView(generics.ListAPIView):
"""Exposes the detailed information about each extension (hostnames, """Exposes the detailed information about each extension (hostnames,
IPs, DNS records, etc.) in order to build the DNS zone files. IPs, DNS records, etc.) in order to build the DNS zone files.
""" """
queryset = (machines.Extension.objects
.prefetch_related('soa') queryset = (
.prefetch_related('ns_set').prefetch_related('ns_set__ns') machines.Extension.objects.prefetch_related("soa")
.prefetch_related('origin') .prefetch_related("ns_set")
.prefetch_related('mx_set').prefetch_related('mx_set__name') .prefetch_related("ns_set__ns")
.prefetch_related('txt_set') .prefetch_related("origin")
.prefetch_related('srv_set').prefetch_related('srv_set__target') .prefetch_related("mx_set")
.all()) .prefetch_related("mx_set__name")
.prefetch_related("txt_set")
.prefetch_related("srv_set")
.prefetch_related("srv_set__target")
.all()
)
serializer_class = serializers.DNSZonesSerializer serializer_class = serializers.DNSZonesSerializer
@ -651,7 +738,8 @@ class DNSReverseZonesView(generics.ListAPIView):
"""Exposes the detailed information about each extension (hostnames, """Exposes the detailed information about each extension (hostnames,
IPs, DNS records, etc.) in order to build the DNS zone files. IPs, DNS records, etc.) in order to build the DNS zone files.
""" """
queryset = (machines.IpType.objects.all())
queryset = machines.IpType.objects.all()
serializer_class = serializers.DNSReverseZonesSerializer serializer_class = serializers.DNSReverseZonesSerializer
@ -662,13 +750,16 @@ class StandardMailingView(views.APIView):
"""Exposes list and details of standard mailings (name and members) in """Exposes list and details of standard mailings (name and members) in
order to building the corresponding mailing lists. order to building the corresponding mailing lists.
""" """
pagination_class = PageSizedPagination pagination_class = PageSizedPagination
permission_classes = (ACLPermission,) permission_classes = (ACLPermission,)
perms_map = {'GET': [users.User.can_view_all]} perms_map = {"GET": [users.User.can_view_all]}
def get(self, request, format=None): def get(self, request, format=None):
adherents_data = serializers.MailingMemberSerializer(all_has_access(), many=True).data adherents_data = serializers.MailingMemberSerializer(
data = [{'name': 'adherents', 'members': adherents_data}] all_has_access(), many=True
).data
data = [{"name": "adherents", "members": adherents_data}]
paginator = self.pagination_class() paginator = self.pagination_class()
paginator.paginate_queryset(data, request) paginator.paginate_queryset(data, request)
return paginator.get_paginated_response(data) return paginator.get_paginated_response(data)
@ -678,6 +769,7 @@ class ClubMailingView(generics.ListAPIView):
"""Exposes list and details of club mailings (name, members and admins) in """Exposes list and details of club mailings (name, members and admins) in
order to build the corresponding mailing lists. order to build the corresponding mailing lists.
""" """
queryset = users.Club.objects.all() queryset = users.Club.objects.all()
serializer_class = serializers.MailingSerializer serializer_class = serializers.MailingSerializer
@ -696,12 +788,10 @@ class ObtainExpiringAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data) serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user'] user = serializer.validated_data["user"]
token, created = Token.objects.get_or_create(user=user) token, created = Token.objects.get_or_create(user=user)
token_duration = datetime.timedelta( token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION)
seconds=settings.API_TOKEN_DURATION
)
utc_now = datetime.datetime.now(datetime.timezone.utc) utc_now = datetime.datetime.now(datetime.timezone.utc)
if not created and token.created < utc_now - token_duration: if not created and token.created < utc_now - token_duration:
token.delete() token.delete()
@ -709,7 +799,6 @@ class ObtainExpiringAuthToken(ObtainAuthToken):
token.created = datetime.datetime.utcnow() token.created = datetime.datetime.utcnow()
token.save() token.save()
return Response({ return Response(
'token': token.key, {"token": token.key, "expiration": token.created + token_duration}
'expiration': token.created + token_duration )
})

View file

@ -38,13 +38,12 @@ def can_view(user):
A couple (allowed, msg) where allowed is a boolean which is True if A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None). viewing is granted and msg is a message (can be None).
""" """
can = user.has_module_perms('cotisations') can = user.has_module_perms("cotisations")
if can: if can:
return can, None, ('cotisations',) return can, None, ("cotisations",)
else: else:
return ( return (
can, can,
_("You don't have the right to view this application."), _("You don't have the right to view this application."),
('cotisations',) ("cotisations",),
) )

View file

@ -35,42 +35,50 @@ from .models import CustomInvoice, CostEstimate
class FactureAdmin(VersionAdmin): class FactureAdmin(VersionAdmin):
"""Class admin d'une facture, tous les champs""" """Class admin d'une facture, tous les champs"""
pass pass
class CostEstimateAdmin(VersionAdmin): class CostEstimateAdmin(VersionAdmin):
"""Admin class for cost estimates.""" """Admin class for cost estimates."""
pass pass
class CustomInvoiceAdmin(VersionAdmin): class CustomInvoiceAdmin(VersionAdmin):
"""Admin class for custom invoices.""" """Admin class for custom invoices."""
pass pass
class VenteAdmin(VersionAdmin): class VenteAdmin(VersionAdmin):
"""Class admin d'une vente, tous les champs (facture related)""" """Class admin d'une vente, tous les champs (facture related)"""
pass pass
class ArticleAdmin(VersionAdmin): class ArticleAdmin(VersionAdmin):
"""Class admin d'un article en vente""" """Class admin d'un article en vente"""
pass pass
class BanqueAdmin(VersionAdmin): class BanqueAdmin(VersionAdmin):
"""Class admin de la liste des banques (facture related)""" """Class admin de la liste des banques (facture related)"""
pass pass
class PaiementAdmin(VersionAdmin): class PaiementAdmin(VersionAdmin):
"""Class admin d'un moyen de paiement (facture related""" """Class admin d'un moyen de paiement (facture related"""
pass pass
class CotisationAdmin(VersionAdmin): class CotisationAdmin(VersionAdmin):
"""Class admin d'une cotisation (date de debut et de fin), """Class admin d'une cotisation (date de debut et de fin),
Vente related""" Vente related"""
pass pass

View file

@ -47,8 +47,13 @@ from django.shortcuts import get_object_or_404
from re2o.field_permissions import FieldPermissionFormMixin from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin from re2o.mixins import FormRevMixin
from .models import ( from .models import (
Article, Paiement, Facture, Banque, Article,
CustomInvoice, Vente, CostEstimate, Paiement,
Facture,
Banque,
CustomInvoice,
Vente,
CostEstimate,
) )
from .payment_methods import balance from .payment_methods import balance
@ -59,31 +64,27 @@ class FactureForm(FieldPermissionFormMixin, FormRevMixin, ModelForm):
""" """
def __init__(self, *args, creation=False, **kwargs): def __init__(self, *args, creation=False, **kwargs):
user = kwargs['user'] user = kwargs["user"]
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(FactureForm, self).__init__(*args, prefix=prefix, **kwargs) super(FactureForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['paiement'].empty_label = \ self.fields["paiement"].empty_label = _("Select a payment method")
_("Select a payment method") self.fields["paiement"].queryset = Paiement.find_allowed_payments(user)
self.fields['paiement'].queryset = Paiement.find_allowed_payments(user)
if not creation: if not creation:
self.fields['user'].label = _("Member") self.fields["user"].label = _("Member")
self.fields['user'].empty_label = \ self.fields["user"].empty_label = _("Select the proprietary member")
_("Select the proprietary member") self.fields["valid"].label = _("Validated invoice")
self.fields['valid'].label = _("Validated invoice")
else: else:
self.fields = {'paiement': self.fields['paiement']} self.fields = {"paiement": self.fields["paiement"]}
class Meta: class Meta:
model = Facture model = Facture
fields = '__all__' fields = "__all__"
def clean(self): def clean(self):
cleaned_data = super(FactureForm, self).clean() cleaned_data = super(FactureForm, self).clean()
paiement = cleaned_data.get('paiement') paiement = cleaned_data.get("paiement")
if not paiement: if not paiement:
raise forms.ValidationError( raise forms.ValidationError(_("A payment method must be specified."))
_("A payment method must be specified.")
)
return cleaned_data return cleaned_data
@ -92,32 +93,30 @@ class SelectArticleForm(FormRevMixin, Form):
Form used to select an article during the creation of an invoice for a Form used to select an article during the creation of an invoice for a
member. member.
""" """
article = forms.ModelChoiceField( article = forms.ModelChoiceField(
queryset=Article.objects.none(), queryset=Article.objects.none(), label=_("Article"), required=True
label=_("Article"),
required=True
) )
quantity = forms.IntegerField( quantity = forms.IntegerField(
label=_("Quantity"), label=_("Quantity"), validators=[MinValueValidator(1)], required=True
validators=[MinValueValidator(1)],
required=True
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
user = kwargs.pop('user') user = kwargs.pop("user")
target_user = kwargs.pop('target_user', None) target_user = kwargs.pop("target_user", None)
super(SelectArticleForm, self).__init__(*args, **kwargs) super(SelectArticleForm, self).__init__(*args, **kwargs)
self.fields['article'].queryset = Article.find_allowed_articles( self.fields["article"].queryset = Article.find_allowed_articles(
user, target_user) user, target_user
)
class DiscountForm(Form): class DiscountForm(Form):
""" """
Form used in oder to create a discount on an invoice. Form used in oder to create a discount on an invoice.
""" """
is_relative = forms.BooleanField( is_relative = forms.BooleanField(
label=_("Discount is on percentage."), label=_("Discount is on percentage."), required=False
required=False,
) )
discount = forms.DecimalField( discount = forms.DecimalField(
label=_("Discount"), label=_("Discount"),
@ -130,53 +129,51 @@ class DiscountForm(Form):
def apply_to_invoice(self, invoice): def apply_to_invoice(self, invoice):
invoice_price = invoice.prix_total() invoice_price = invoice.prix_total()
discount = self.cleaned_data['discount'] discount = self.cleaned_data["discount"]
is_relative = self.cleaned_data['is_relative'] is_relative = self.cleaned_data["is_relative"]
if is_relative: if is_relative:
amount = discount/100 * invoice_price amount = discount / 100 * invoice_price
else: else:
amount = discount amount = discount
if amount: if amount:
name = _("{}% discount") if is_relative else _("{}€ discount") name = _("{}% discount") if is_relative else _("{}€ discount")
name = name.format(discount) name = name.format(discount)
Vente.objects.create( Vente.objects.create(facture=invoice, name=name, prix=-amount, number=1)
facture=invoice,
name=name,
prix=-amount,
number=1
)
class CustomInvoiceForm(FormRevMixin, ModelForm): class CustomInvoiceForm(FormRevMixin, ModelForm):
""" """
Form used to create a custom invoice. Form used to create a custom invoice.
""" """
class Meta: class Meta:
model = CustomInvoice model = CustomInvoice
fields = '__all__' fields = "__all__"
class CostEstimateForm(FormRevMixin, ModelForm): class CostEstimateForm(FormRevMixin, ModelForm):
""" """
Form used to create a cost estimate. Form used to create a cost estimate.
""" """
class Meta: class Meta:
model = CostEstimate model = CostEstimate
exclude = ['paid', 'final_invoice'] exclude = ["paid", "final_invoice"]
class ArticleForm(FormRevMixin, ModelForm): class ArticleForm(FormRevMixin, ModelForm):
""" """
Form used to create an article. Form used to create an article.
""" """
class Meta: class Meta:
model = Article model = Article
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs) super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = _("Article name") self.fields["name"].label = _("Article name")
class DelArticleForm(FormRevMixin, Form): class DelArticleForm(FormRevMixin, Form):
@ -184,19 +181,20 @@ class DelArticleForm(FormRevMixin, Form):
Form used to delete one or more of the currently available articles. Form used to delete one or more of the currently available articles.
The user must choose the one to delete by checking the boxes. The user must choose the one to delete by checking the boxes.
""" """
articles = forms.ModelMultipleChoiceField( articles = forms.ModelMultipleChoiceField(
queryset=Article.objects.none(), queryset=Article.objects.none(),
label=_("Available articles"), label=_("Available articles"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelArticleForm, self).__init__(*args, **kwargs) super(DelArticleForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['articles'].queryset = instances self.fields["articles"].queryset = instances
else: else:
self.fields['articles'].queryset = Article.objects.all() self.fields["articles"].queryset = Article.objects.all()
# TODO : change Paiement to Payment # TODO : change Paiement to Payment
@ -206,15 +204,16 @@ class PaiementForm(FormRevMixin, ModelForm):
The 'cheque' type is used to associate a specific behaviour requiring The 'cheque' type is used to associate a specific behaviour requiring
a cheque number and a bank. a cheque number and a bank.
""" """
class Meta: class Meta:
model = Paiement model = Paiement
# TODO : change moyen to method and type_paiement to payment_type # TODO : change moyen to method and type_paiement to payment_type
fields = ['moyen', 'available_for_everyone'] fields = ["moyen", "available_for_everyone"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs) super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['moyen'].label = _("Payment method name") self.fields["moyen"].label = _("Payment method name")
# TODO : change paiement to payment # TODO : change paiement to payment
@ -223,20 +222,21 @@ class DelPaiementForm(FormRevMixin, Form):
Form used to delete one or more payment methods. Form used to delete one or more payment methods.
The user must choose the one to delete by checking the boxes. The user must choose the one to delete by checking the boxes.
""" """
# TODO : change paiement to payment # TODO : change paiement to payment
paiements = forms.ModelMultipleChoiceField( paiements = forms.ModelMultipleChoiceField(
queryset=Paiement.objects.none(), queryset=Paiement.objects.none(),
label=_("Available payment methods"), label=_("Available payment methods"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelPaiementForm, self).__init__(*args, **kwargs) super(DelPaiementForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['paiements'].queryset = instances self.fields["paiements"].queryset = instances
else: else:
self.fields['paiements'].queryset = Paiement.objects.all() self.fields["paiements"].queryset = Paiement.objects.all()
# TODO : change banque to bank # TODO : change banque to bank
@ -244,15 +244,16 @@ class BanqueForm(FormRevMixin, ModelForm):
""" """
Form used to create a bank. Form used to create a bank.
""" """
class Meta: class Meta:
# TODO : change banque to bank # TODO : change banque to bank
model = Banque model = Banque
fields = ['name'] fields = ["name"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs) super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = _("Bank name") self.fields["name"].label = _("Bank name")
# TODO : change banque to bank # TODO : change banque to bank
@ -261,20 +262,21 @@ class DelBanqueForm(FormRevMixin, Form):
Form used to delete one or more banks. Form used to delete one or more banks.
The use must choose the one to delete by checking the boxes. The use must choose the one to delete by checking the boxes.
""" """
# TODO : change banque to bank # TODO : change banque to bank
banques = forms.ModelMultipleChoiceField( banques = forms.ModelMultipleChoiceField(
queryset=Banque.objects.none(), queryset=Banque.objects.none(),
label=_("Available banks"), label=_("Available banks"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelBanqueForm, self).__init__(*args, **kwargs) super(DelBanqueForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['banques'].queryset = instances self.fields["banques"].queryset = instances
else: else:
self.fields['banques'].queryset = Banque.objects.all() self.fields["banques"].queryset = Banque.objects.all()
# TODO : Better name and docstring # TODO : Better name and docstring
@ -282,36 +284,36 @@ class RechargeForm(FormRevMixin, Form):
""" """
Form used to refill a user's balance Form used to refill a user's balance
""" """
value = forms.DecimalField(
label=_("Amount"), value = forms.DecimalField(label=_("Amount"), decimal_places=2)
decimal_places=2,
)
payment = forms.ModelChoiceField( payment = forms.ModelChoiceField(
queryset=Paiement.objects.none(), queryset=Paiement.objects.none(), label=_("Payment method")
label=_("Payment method")
) )
def __init__(self, *args, user=None, user_source=None, **kwargs): def __init__(self, *args, user=None, user_source=None, **kwargs):
self.user = user self.user = user
super(RechargeForm, self).__init__(*args, **kwargs) super(RechargeForm, self).__init__(*args, **kwargs)
self.fields['payment'].empty_label = \ self.fields["payment"].empty_label = _("Select a payment method")
_("Select a payment method") self.fields["payment"].queryset = Paiement.find_allowed_payments(
self.fields['payment'].queryset = Paiement.find_allowed_payments( user_source
user_source).exclude(is_balance=True) ).exclude(is_balance=True)
def clean(self): def clean(self):
""" """
Returns a cleaned value from the received form by validating Returns a cleaned value from the received form by validating
the value is well inside the possible limits the value is well inside the possible limits
""" """
value = self.cleaned_data['value'] value = self.cleaned_data["value"]
balance_method = get_object_or_404(balance.PaymentMethod) balance_method = get_object_or_404(balance.PaymentMethod)
if balance_method.maximum_balance is not None and \ if (
value + self.user.solde > balance_method.maximum_balance: balance_method.maximum_balance is not None
and value + self.user.solde > balance_method.maximum_balance
):
raise forms.ValidationError( raise forms.ValidationError(
_("Requested amount is too high. Your balance can't exceed" _(
" %(max_online_balance)s €.") % { "Requested amount is too high. Your balance can't exceed"
'max_online_balance': balance_method.maximum_balance " %(max_online_balance)s €."
} )
% {"max_online_balance": balance_method.maximum_balance}
) )
return self.cleaned_data return self.cleaned_data

View file

@ -29,54 +29,100 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("users", "0005_auto_20160702_0006")]
('users', '0005_auto_20160702_0006'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Article', name="Article",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), (
('name', models.CharField(max_length=255)), "id",
('prix', models.DecimalField(decimal_places=2, max_digits=5)), models.AutoField(
verbose_name="ID",
auto_created=True,
primary_key=True,
serialize=False,
),
),
("name", models.CharField(max_length=255)),
("prix", models.DecimalField(decimal_places=2, max_digits=5)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Banque', name="Banque",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), (
('name', models.CharField(max_length=255)), "id",
models.AutoField(
verbose_name="ID",
auto_created=True,
primary_key=True,
serialize=False,
),
),
("name", models.CharField(max_length=255)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Facture', name="Facture",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), (
('cheque', models.CharField(max_length=255)), "id",
('number', models.IntegerField()), models.AutoField(
('date', models.DateTimeField(auto_now_add=True)), verbose_name="ID",
('name', models.CharField(max_length=255)), auto_created=True,
('prix', models.DecimalField(decimal_places=2, max_digits=5)), primary_key=True,
('article', models.ForeignKey(to='cotisations.Article', on_delete=django.db.models.deletion.PROTECT)), serialize=False,
('banque', models.ForeignKey(to='cotisations.Banque', on_delete=django.db.models.deletion.PROTECT)), ),
),
("cheque", models.CharField(max_length=255)),
("number", models.IntegerField()),
("date", models.DateTimeField(auto_now_add=True)),
("name", models.CharField(max_length=255)),
("prix", models.DecimalField(decimal_places=2, max_digits=5)),
(
"article",
models.ForeignKey(
to="cotisations.Article",
on_delete=django.db.models.deletion.PROTECT,
),
),
(
"banque",
models.ForeignKey(
to="cotisations.Banque",
on_delete=django.db.models.deletion.PROTECT,
),
),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Paiement', name="Paiement",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), (
('moyen', models.CharField(max_length=255)), "id",
models.AutoField(
verbose_name="ID",
auto_created=True,
primary_key=True,
serialize=False,
),
),
("moyen", models.CharField(max_length=255)),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='facture', model_name="facture",
name='paiement', name="paiement",
field=models.ForeignKey(to='cotisations.Paiement', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="cotisations.Paiement", on_delete=django.db.models.deletion.PROTECT
),
), ),
migrations.AddField( migrations.AddField(
model_name='facture', model_name="facture",
name='user', name="user",
field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="users.User", on_delete=django.db.models.deletion.PROTECT
),
), ),
] ]

View file

@ -28,13 +28,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0001_initial")]
('cotisations', '0001_initial'),
]
operations = [ operations = [migrations.RemoveField(model_name="facture", name="article")]
migrations.RemoveField(
model_name='facture',
name='article',
),
]

View file

@ -29,14 +29,17 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0002_remove_facture_article")]
('cotisations', '0002_remove_facture_article'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='banque', name="banque",
field=models.ForeignKey(blank=True, to='cotisations.Banque', on_delete=django.db.models.deletion.PROTECT, null=True), field=models.ForeignKey(
), blank=True,
to="cotisations.Banque",
on_delete=django.db.models.deletion.PROTECT,
null=True,
),
)
] ]

View file

@ -28,19 +28,17 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0003_auto_20160702_1448")]
('cotisations', '0003_auto_20160702_1448'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='name', name="name",
field=models.CharField(null=True, max_length=255), field=models.CharField(null=True, max_length=255),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='prix', name="prix",
field=models.DecimalField(max_digits=5, null=True, decimal_places=2), field=models.DecimalField(max_digits=5, null=True, decimal_places=2),
), ),
] ]

View file

@ -28,14 +28,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0004_auto_20160702_1528")]
('cotisations', '0004_auto_20160702_1528'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='cheque', name="cheque",
field=models.CharField(max_length=255, blank=True), field=models.CharField(max_length=255, blank=True),
), )
] ]

View file

@ -28,19 +28,19 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0005_auto_20160702_1532")]
('cotisations', '0005_auto_20160702_1532'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='name', name="name",
field=models.CharField(null=True, default='plop', max_length=255), field=models.CharField(null=True, default="plop", max_length=255),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='prix', name="prix",
field=models.DecimalField(null=True, decimal_places=2, default=1, max_digits=5), field=models.DecimalField(
null=True, decimal_places=2, default=1, max_digits=5
),
), ),
] ]

View file

@ -28,20 +28,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0006_auto_20160702_1534")]
('cotisations', '0006_auto_20160702_1534'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='name', name="name",
field=models.CharField(default='plop', max_length=255), field=models.CharField(default="plop", max_length=255),
preserve_default=False, preserve_default=False,
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='prix', name="prix",
field=models.DecimalField(default=1, max_digits=5, decimal_places=2), field=models.DecimalField(default=1, max_digits=5, decimal_places=2),
preserve_default=False, preserve_default=False,
), ),

View file

@ -30,43 +30,53 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('users', '0005_auto_20160702_0006'), ("users", "0005_auto_20160702_0006"),
('cotisations', '0007_auto_20160702_1543'), ("cotisations", "0007_auto_20160702_1543"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Cotisation', name="Cotisation",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), (
('date_start', models.DateTimeField(auto_now_add=True)), "id",
('date_end', models.DateTimeField()), models.AutoField(
verbose_name="ID",
primary_key=True,
serialize=False,
auto_created=True,
),
),
("date_start", models.DateTimeField(auto_now_add=True)),
("date_end", models.DateTimeField()),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='cotisation', name="cotisation",
field=models.BooleanField(default=True), field=models.BooleanField(default=True),
preserve_default=False, preserve_default=False,
), ),
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='duration', name="duration",
field=models.DurationField(blank=True, null=True), field=models.DurationField(blank=True, null=True),
), ),
migrations.AddField( migrations.AddField(
model_name='facture', model_name="facture", name="valid", field=models.BooleanField(default=True)
name='valid',
field=models.BooleanField(default=True),
), ),
migrations.AddField( migrations.AddField(
model_name='cotisation', model_name="cotisation",
name='facture', name="facture",
field=models.ForeignKey(to='cotisations.Facture', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="cotisations.Facture", on_delete=django.db.models.deletion.PROTECT
),
), ),
migrations.AddField( migrations.AddField(
model_name='cotisation', model_name="cotisation",
name='user', name="user",
field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="users.User", on_delete=django.db.models.deletion.PROTECT
),
), ),
] ]

View file

@ -28,13 +28,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0008_auto_20160702_1614")]
('cotisations', '0008_auto_20160702_1614'),
]
operations = [ operations = [migrations.RemoveField(model_name="cotisation", name="user")]
migrations.RemoveField(
model_name='cotisation',
name='user',
),
]

View file

@ -28,18 +28,15 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0009_remove_cotisation_user")]
('cotisations', '0009_remove_cotisation_user'),
]
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(model_name="article", name="duration"),
model_name='article',
name='duration',
),
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='duration', name="duration",
field=models.IntegerField(null=True, help_text='Durée exprimée en mois entiers', blank=True), field=models.IntegerField(
null=True, help_text="Durée exprimée en mois entiers", blank=True
),
), ),
] ]

View file

@ -28,14 +28,10 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0010_auto_20160702_1840")]
('cotisations', '0010_auto_20160702_1840'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation", name="date_start", field=models.DateTimeField()
name='date_start', )
field=models.DateTimeField(),
),
] ]

View file

@ -29,14 +29,14 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0011_auto_20160702_1911")]
('cotisations', '0011_auto_20160702_1911'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='facture', name="facture",
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='cotisations.Facture'), field=models.OneToOneField(
), on_delete=django.db.models.deletion.PROTECT, to="cotisations.Facture"
),
)
] ]

View file

@ -29,32 +29,41 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0012_auto_20160704_0118")]
('cotisations', '0012_auto_20160704_0118'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Vente', name="Vente",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=255)), "id",
('prix', models.DecimalField(decimal_places=2, max_digits=5)), models.AutoField(
('cotisation', models.BooleanField()), auto_created=True,
('duration', models.IntegerField(null=True, blank=True, help_text='Durée exprimée en mois entiers')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("prix", models.DecimalField(decimal_places=2, max_digits=5)),
("cotisation", models.BooleanField()),
(
"duration",
models.IntegerField(
null=True,
blank=True,
help_text="Durée exprimée en mois entiers",
),
),
], ],
), ),
migrations.RemoveField( migrations.RemoveField(model_name="facture", name="name"),
model_name='facture', migrations.RemoveField(model_name="facture", name="prix"),
name='name',
),
migrations.RemoveField(
model_name='facture',
name='prix',
),
migrations.AddField( migrations.AddField(
model_name='vente', model_name="vente",
name='facture', name="facture",
field=models.ForeignKey(to='cotisations.Facture', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="cotisations.Facture", on_delete=django.db.models.deletion.PROTECT
),
), ),
] ]

View file

@ -28,18 +28,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0013_auto_20160711_2240")]
('cotisations', '0013_auto_20160711_2240'),
]
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(model_name="facture", name="number"),
model_name='facture',
name='number',
),
migrations.AddField( migrations.AddField(
model_name='vente', model_name="vente",
name='number', name="number",
field=models.IntegerField(default=1), field=models.IntegerField(default=1),
preserve_default=False, preserve_default=False,
), ),

View file

@ -29,29 +29,29 @@ import django.core.validators
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0014_auto_20160712_0245")]
('cotisations', '0014_auto_20160712_0245'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='facture', model_name="facture",
name='control', name="control",
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='facture', name="facture",
field=models.OneToOneField(to='cotisations.Facture'), field=models.OneToOneField(to="cotisations.Facture"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='facture', name="facture",
field=models.ForeignKey(to='cotisations.Facture'), field=models.ForeignKey(to="cotisations.Facture"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='number', name="number",
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)]), field=models.IntegerField(
validators=[django.core.validators.MinValueValidator(1)]
),
), ),
] ]

View file

@ -28,29 +28,20 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0015_auto_20160714_2142")]
('cotisations', '0015_auto_20160714_2142'),
]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(
model_name='article', model_name="article", old_name="cotisation", new_name="iscotisation"
old_name='cotisation',
new_name='iscotisation',
), ),
migrations.RenameField( migrations.RenameField(
model_name='vente', model_name="vente", old_name="cotisation", new_name="iscotisation"
old_name='cotisation',
new_name='iscotisation',
),
migrations.RemoveField(
model_name='cotisation',
name='facture',
), ),
migrations.RemoveField(model_name="cotisation", name="facture"),
migrations.AddField( migrations.AddField(
model_name='cotisation', model_name="cotisation",
name='vente', name="vente",
field=models.OneToOneField(to='cotisations.Vente', null=True), field=models.OneToOneField(to="cotisations.Vente", null=True),
preserve_default=False, preserve_default=False,
), ),
] ]

View file

@ -8,19 +8,22 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0016_auto_20160715_0110")]
('cotisations', '0016_auto_20160715_0110'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='duration', name="duration",
field=models.IntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True, validators=[django.core.validators.MinValueValidator(0)]), field=models.IntegerField(
blank=True,
help_text="Durée exprimée en mois entiers",
null=True,
validators=[django.core.validators.MinValueValidator(0)],
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='name', name="name",
field=models.CharField(max_length=255, unique=True), field=models.CharField(max_length=255, unique=True),
), ),
] ]

View file

@ -7,15 +7,17 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0017_auto_20170718_2329")]
('cotisations', '0017_auto_20170718_2329'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.CharField(choices=[('check', 'Chèque'), (None, 'Autre')], default=None, max_length=255), field=models.CharField(
choices=[("check", "Chèque"), (None, "Autre")],
default=None,
max_length=255,
),
preserve_default=False, preserve_default=False,
), )
] ]

View file

@ -7,14 +7,14 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0018_paiement_type_paiement")]
('cotisations', '0018_paiement_type_paiement'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.CharField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), field=models.CharField(
), choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255
),
)
] ]

View file

@ -7,14 +7,14 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0019_auto_20170819_0055")]
('cotisations', '0019_auto_20170819_0055'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), field=models.IntegerField(
), choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255
),
)
] ]

View file

@ -7,14 +7,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0020_auto_20170819_0057")]
('cotisations', '0020_auto_20170819_0057'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0), field=models.IntegerField(choices=[(0, "Autre"), (1, "Chèque")], default=0),
), )
] ]

View file

@ -7,14 +7,14 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0021_auto_20170819_0104")]
('cotisations', '0021_auto_20170819_0104'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), field=models.IntegerField(
), choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255
),
)
] ]

View file

@ -7,14 +7,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0022_auto_20170824_0128")]
('cotisations', '0022_auto_20170824_0128'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0), field=models.IntegerField(choices=[(0, "Autre"), (1, "Chèque")], default=0),
), )
] ]

View file

@ -8,19 +8,24 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0023_auto_20170902_1303")]
('cotisations', '0023_auto_20170902_1303'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='duration', name="duration",
field=models.PositiveIntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True, validators=[django.core.validators.MinValueValidator(0)]), field=models.PositiveIntegerField(
blank=True,
help_text="Durée exprimée en mois entiers",
null=True,
validators=[django.core.validators.MinValueValidator(0)],
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='duration', name="duration",
field=models.PositiveIntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True), field=models.PositiveIntegerField(
blank=True, help_text="Durée exprimée en mois entiers", null=True
),
), ),
] ]

View file

@ -7,14 +7,16 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0024_auto_20171015_2033")]
('cotisations', '0024_auto_20171015_2033'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='type_user', name="type_user",
field=models.CharField(choices=[('Adherent', 'Adherent'), ('Club', 'Club'), ('All', 'All')], default='All', max_length=255), field=models.CharField(
), choices=[("Adherent", "Adherent"), ("Club", "Club"), ("All", "All")],
default="All",
max_length=255,
),
)
] ]

View file

@ -6,73 +6,94 @@ from django.db import migrations, models
def create_type(apps, schema_editor): def create_type(apps, schema_editor):
Cotisation = apps.get_model('cotisations', 'Cotisation') Cotisation = apps.get_model("cotisations", "Cotisation")
Vente = apps.get_model('cotisations', 'Vente') Vente = apps.get_model("cotisations", "Vente")
Article = apps.get_model('cotisations', 'Article') Article = apps.get_model("cotisations", "Article")
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
articles = Article.objects.using(db_alias).all() articles = Article.objects.using(db_alias).all()
ventes = Vente.objects.using(db_alias).all() ventes = Vente.objects.using(db_alias).all()
cotisations = Cotisation.objects.using(db_alias).all() cotisations = Cotisation.objects.using(db_alias).all()
for article in articles: for article in articles:
if article.iscotisation: if article.iscotisation:
article.type_cotisation='All' article.type_cotisation = "All"
article.save(using=db_alias) article.save(using=db_alias)
for vente in ventes: for vente in ventes:
if vente.iscotisation: if vente.iscotisation:
vente.type_cotisation='All' vente.type_cotisation = "All"
vente.save(using=db_alias) vente.save(using=db_alias)
for cotisation in cotisations: for cotisation in cotisations:
cotisation.type_cotisation='All' cotisation.type_cotisation = "All"
cotisation.save(using=db_alias) cotisation.save(using=db_alias)
def delete_type(apps, schema_editor): def delete_type(apps, schema_editor):
Vente = apps.get_model('cotisations', 'Vente') Vente = apps.get_model("cotisations", "Vente")
Article = apps.get_model('cotisations', 'Article') Article = apps.get_model("cotisations", "Article")
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
articles = Article.objects.using(db_alias).all() articles = Article.objects.using(db_alias).all()
ventes = Vente.objects.using(db_alias).all() ventes = Vente.objects.using(db_alias).all()
for article in articles: for article in articles:
if article.type_cotisation: if article.type_cotisation:
article.iscotisation=True article.iscotisation = True
else: else:
article.iscotisation=False article.iscotisation = False
article.save(using=db_alias) article.save(using=db_alias)
for vente in ventes: for vente in ventes:
if vente.iscotisation: if vente.iscotisation:
vente.iscotisation=True vente.iscotisation = True
else: else:
vente.iscotisation=False vente.iscotisation = False
vente.save(using=db_alias) vente.save(using=db_alias)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0025_article_type_user")]
('cotisations', '0025_article_type_user'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='type_cotisation', name="type_cotisation",
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], default=None, max_length=255, null=True), field=models.CharField(
blank=True,
choices=[
("Connexion", "Connexion"),
("Adhesion", "Adhesion"),
("All", "All"),
],
default=None,
max_length=255,
null=True,
),
), ),
migrations.AddField( migrations.AddField(
model_name='cotisation', model_name="cotisation",
name='type_cotisation', name="type_cotisation",
field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, default='All'), field=models.CharField(
choices=[
("Connexion", "Connexion"),
("Adhesion", "Adhesion"),
("All", "All"),
],
max_length=255,
default="All",
),
), ),
migrations.AddField( migrations.AddField(
model_name='vente', model_name="vente",
name='type_cotisation', name="type_cotisation",
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, null=True), field=models.CharField(
blank=True,
choices=[
("Connexion", "Connexion"),
("Adhesion", "Adhesion"),
("All", "All"),
],
max_length=255,
null=True,
),
), ),
migrations.RunPython(create_type, delete_type), migrations.RunPython(create_type, delete_type),
migrations.RemoveField( migrations.RemoveField(model_name="article", name="iscotisation"),
model_name='article', migrations.RemoveField(model_name="vente", name="iscotisation"),
name='iscotisation',
),
migrations.RemoveField(
model_name='vente',
name='iscotisation',
),
] ]

View file

@ -7,14 +7,10 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0026_auto_20171028_0126")]
('cotisations', '0026_auto_20171028_0126'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article", name="name", field=models.CharField(max_length=255)
name='name', )
field=models.CharField(max_length=255),
),
] ]

View file

@ -7,33 +7,56 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0027_auto_20171029_1156")]
('cotisations', '0027_auto_20171029_1156'),
]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='article', name="article",
options={'permissions': (('view_article', 'Peut voir un objet article'),)}, options={"permissions": (("view_article", "Peut voir un objet article"),)},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='banque', name="banque",
options={'permissions': (('view_banque', 'Peut voir un objet banque'),)}, options={"permissions": (("view_banque", "Peut voir un objet banque"),)},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='cotisation', name="cotisation",
options={'permissions': (('view_cotisation', 'Peut voir un objet cotisation'), ('change_all_cotisation', 'Superdroit, peut modifier toutes les cotisations'))}, options={
"permissions": (
("view_cotisation", "Peut voir un objet cotisation"),
(
"change_all_cotisation",
"Superdroit, peut modifier toutes les cotisations",
),
)
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='facture', name="facture",
options={'permissions': (('change_facture_control', "Peut changer l'etat de controle"), ('change_facture_pdf', 'Peut éditer une facture pdf'), ('view_facture', 'Peut voir un objet facture'), ('change_all_facture', 'Superdroit, peut modifier toutes les factures'))}, options={
"permissions": (
("change_facture_control", "Peut changer l'etat de controle"),
("change_facture_pdf", "Peut éditer une facture pdf"),
("view_facture", "Peut voir un objet facture"),
(
"change_all_facture",
"Superdroit, peut modifier toutes les factures",
),
)
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='paiement', name="paiement",
options={'permissions': (('view_paiement', 'Peut voir un objet paiement'),)}, options={
"permissions": (("view_paiement", "Peut voir un objet paiement"),)
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='vente', name="vente",
options={'permissions': (('view_vente', 'Peut voir un objet vente'), ('change_all_vente', 'Superdroit, peut modifier toutes les ventes'))}, options={
"permissions": (
("view_vente", "Peut voir un objet vente"),
("change_all_vente", "Superdroit, peut modifier toutes les ventes"),
)
},
), ),
] ]

View file

@ -9,143 +9,242 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0028_auto_20171231_0007")]
('cotisations', '0028_auto_20171231_0007'),
]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='article', name="article",
options={'permissions': (('view_article', "Can see an article's details"),), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'}, options={
"permissions": (("view_article", "Can see an article's details"),),
"verbose_name": "Article",
"verbose_name_plural": "Articles",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='banque', name="banque",
options={'permissions': (('view_banque', "Can see a bank's details"),), 'verbose_name': 'Bank', 'verbose_name_plural': 'Banks'}, options={
"permissions": (("view_banque", "Can see a bank's details"),),
"verbose_name": "Bank",
"verbose_name_plural": "Banks",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='cotisation', name="cotisation",
options={'permissions': (('view_cotisation', "Can see a cotisation's details"), ('change_all_cotisation', 'Can edit the previous cotisations'))}, options={
"permissions": (
("view_cotisation", "Can see a cotisation's details"),
("change_all_cotisation", "Can edit the previous cotisations"),
)
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='facture', name="facture",
options={'permissions': (('change_facture_control', 'Can change the "controlled" state'), ('change_facture_pdf', 'Can create a custom PDF invoice'), ('view_facture', "Can see an invoice's details"), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'Invoice', 'verbose_name_plural': 'Invoices'}, options={
"permissions": (
("change_facture_control", 'Can change the "controlled" state'),
("change_facture_pdf", "Can create a custom PDF invoice"),
("view_facture", "Can see an invoice's details"),
("change_all_facture", "Can edit all the previous invoices"),
),
"verbose_name": "Invoice",
"verbose_name_plural": "Invoices",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='paiement', name="paiement",
options={'permissions': (('view_paiement', "Can see a payement's details"),), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'}, options={
"permissions": (("view_paiement", "Can see a payement's details"),),
"verbose_name": "Payment method",
"verbose_name_plural": "Payment methods",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='vente', name="vente",
options={'permissions': (('view_vente', "Can see a purchase's details"), ('change_all_vente', 'Can edit all the previous purchases')), 'verbose_name': 'Purchase', 'verbose_name_plural': 'Purchases'}, options={
"permissions": (
("view_vente", "Can see a purchase's details"),
("change_all_vente", "Can edit all the previous purchases"),
),
"verbose_name": "Purchase",
"verbose_name_plural": "Purchases",
},
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='duration', name="duration",
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Duration (in whole month)'), field=models.PositiveIntegerField(
blank=True,
null=True,
validators=[django.core.validators.MinValueValidator(0)],
verbose_name="Duration (in whole month)",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='name', name="name",
field=models.CharField(max_length=255, verbose_name='Designation'), field=models.CharField(max_length=255, verbose_name="Designation"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='prix', name="prix",
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='Unitary price'), field=models.DecimalField(
decimal_places=2, max_digits=5, verbose_name="Unitary price"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='type_cotisation', name="type_cotisation",
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default=None, max_length=255, null=True, verbose_name='Type of cotisation'), field=models.CharField(
blank=True,
choices=[
("Connexion", "Connexion"),
("Adhesion", "Membership"),
("All", "Both of them"),
],
default=None,
max_length=255,
null=True,
verbose_name="Type of cotisation",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='type_user', name="type_user",
field=models.CharField(choices=[('Adherent', 'Member'), ('Club', 'Club'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='Type of users concerned'), field=models.CharField(
choices=[
("Adherent", "Member"),
("Club", "Club"),
("All", "Both of them"),
],
default="All",
max_length=255,
verbose_name="Type of users concerned",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='banque', model_name="banque",
name='name', name="name",
field=models.CharField(max_length=255, verbose_name='Name'), field=models.CharField(max_length=255, verbose_name="Name"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='date_end', name="date_end",
field=models.DateTimeField(verbose_name='Ending date'), field=models.DateTimeField(verbose_name="Ending date"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='date_start', name="date_start",
field=models.DateTimeField(verbose_name='Starting date'), field=models.DateTimeField(verbose_name="Starting date"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='type_cotisation', name="type_cotisation",
field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='Type of cotisation'), field=models.CharField(
choices=[
("Connexion", "Connexion"),
("Adhesion", "Membership"),
("All", "Both of them"),
],
default="All",
max_length=255,
verbose_name="Type of cotisation",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='vente', name="vente",
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='cotisations.Vente', verbose_name='Purchase'), field=models.OneToOneField(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="cotisations.Vente",
verbose_name="Purchase",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='cheque', name="cheque",
field=models.CharField(blank=True, max_length=255, verbose_name='Cheque number'), field=models.CharField(
blank=True, max_length=255, verbose_name="Cheque number"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='control', name="control",
field=models.BooleanField(default=False, verbose_name='Controlled'), field=models.BooleanField(default=False, verbose_name="Controlled"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='date', name="date",
field=models.DateTimeField(auto_now_add=True, verbose_name='Date'), field=models.DateTimeField(auto_now_add=True, verbose_name="Date"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='valid', name="valid",
field=models.BooleanField(default=True, verbose_name='Validated'), field=models.BooleanField(default=True, verbose_name="Validated"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='moyen', name="moyen",
field=models.CharField(max_length=255, verbose_name='Method'), field=models.CharField(max_length=255, verbose_name="Method"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='type_paiement', name="type_paiement",
field=models.IntegerField(choices=[(0, 'Standard'), (1, 'Cheque')], default=0, verbose_name='Payment type'), field=models.IntegerField(
choices=[(0, "Standard"), (1, "Cheque")],
default=0,
verbose_name="Payment type",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='duration', name="duration",
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Duration (in whole month)'), field=models.PositiveIntegerField(
blank=True, null=True, verbose_name="Duration (in whole month)"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='facture', name="facture",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cotisations.Facture', verbose_name='Invoice'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="cotisations.Facture",
verbose_name="Invoice",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='name', name="name",
field=models.CharField(max_length=255, verbose_name='Article'), field=models.CharField(max_length=255, verbose_name="Article"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='number', name="number",
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)], verbose_name='Amount'), field=models.IntegerField(
validators=[django.core.validators.MinValueValidator(1)],
verbose_name="Amount",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='prix', name="prix",
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='Price'), field=models.DecimalField(
decimal_places=2, max_digits=5, verbose_name="Price"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='type_cotisation', name="type_cotisation",
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], max_length=255, null=True, verbose_name='Type of cotisation'), field=models.CharField(
blank=True,
choices=[
("Connexion", "Connexion"),
("Adhesion", "Membership"),
("All", "Both of them"),
],
max_length=255,
null=True,
verbose_name="Type of cotisation",
),
), ),
] ]

View file

@ -9,8 +9,8 @@ import django.db.models.deletion
def add_cheque(apps, schema_editor): def add_cheque(apps, schema_editor):
ChequePayment = apps.get_model('cotisations', 'ChequePayment') ChequePayment = apps.get_model("cotisations", "ChequePayment")
Payment = apps.get_model('cotisations', 'Paiement') Payment = apps.get_model("cotisations", "Paiement")
for p in Payment.objects.filter(type_paiement=1): for p in Payment.objects.filter(type_paiement=1):
cheque = ChequePayment() cheque = ChequePayment()
cheque.payment = p cheque.payment = p
@ -18,14 +18,12 @@ def add_cheque(apps, schema_editor):
def add_comnpay(apps, schema_editor): def add_comnpay(apps, schema_editor):
ComnpayPayment = apps.get_model('cotisations', 'ComnpayPayment') ComnpayPayment = apps.get_model("cotisations", "ComnpayPayment")
Payment = apps.get_model('cotisations', 'Paiement') Payment = apps.get_model("cotisations", "Paiement")
AssoOption = apps.get_model('preferences', 'AssoOption') AssoOption = apps.get_model("preferences", "AssoOption")
options, _created = AssoOption.objects.get_or_create() options, _created = AssoOption.objects.get_or_create()
try: try:
payment = Payment.objects.get( payment = Payment.objects.get(moyen="Rechargement en ligne")
moyen='Rechargement en ligne'
)
except Payment.DoesNotExist: except Payment.DoesNotExist:
return return
comnpay = ComnpayPayment() comnpay = ComnpayPayment()
@ -38,11 +36,11 @@ def add_comnpay(apps, schema_editor):
def add_solde(apps, schema_editor): def add_solde(apps, schema_editor):
OptionalUser = apps.get_model('preferences', 'OptionalUser') OptionalUser = apps.get_model("preferences", "OptionalUser")
options, _created = OptionalUser.objects.get_or_create() options, _created = OptionalUser.objects.get_or_create()
Payment = apps.get_model('cotisations', 'Paiement') Payment = apps.get_model("cotisations", "Paiement")
BalancePayment = apps.get_model('cotisations', 'BalancePayment') BalancePayment = apps.get_model("cotisations", "BalancePayment")
try: try:
solde = Payment.objects.get(moyen="solde") solde = Payment.objects.get(moyen="solde")
@ -60,73 +58,191 @@ def add_solde(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('preferences', '0044_remove_payment_pass'), ("preferences", "0044_remove_payment_pass"),
('cotisations', '0029_auto_20180414_2056'), ("cotisations", "0029_auto_20180414_2056"),
] ]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='paiement', name="paiement",
options={'permissions': (('view_paiement', "Can see a payement's details"), ('use_every_payment', 'Can use every payement')), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'}, options={
"permissions": (
("view_paiement", "Can see a payement's details"),
("use_every_payment", "Can use every payement"),
),
"verbose_name": "Payment method",
"verbose_name_plural": "Payment methods",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='article', name="article",
options={'permissions': (('view_article', "Can see an article's details"), ('buy_every_article', 'Can buy every_article')), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'}, options={
"permissions": (
("view_article", "Can see an article's details"),
("buy_every_article", "Can buy every_article"),
),
"verbose_name": "Article",
"verbose_name_plural": "Articles",
},
), ),
migrations.AddField( migrations.AddField(
model_name='paiement', model_name="paiement",
name='available_for_everyone', name="available_for_everyone",
field=models.BooleanField(default=False, verbose_name='Is available for every user'), field=models.BooleanField(
default=False, verbose_name="Is available for every user"
),
), ),
migrations.AddField( migrations.AddField(
model_name='paiement', model_name="paiement",
name='is_balance', name="is_balance",
field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', verbose_name='Is user balance', validators=[cotisations.models.check_no_balance]), field=models.BooleanField(
default=False,
editable=False,
help_text="There should be only one balance payment method.",
verbose_name="Is user balance",
validators=[cotisations.models.check_no_balance],
),
), ),
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='available_for_everyone', name="available_for_everyone",
field=models.BooleanField(default=False, verbose_name='Is available for every user'), field=models.BooleanField(
default=False, verbose_name="Is available for every user"
),
), ),
migrations.CreateModel( migrations.CreateModel(
name='ChequePayment', name="ChequePayment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"payment",
models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method",
to="cotisations.Paiement",
),
),
], ],
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
options={'verbose_name': 'Cheque'}, options={"verbose_name": "Cheque"},
), ),
migrations.CreateModel( migrations.CreateModel(
name='ComnpayPayment', name="ComnpayPayment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('payment_credential', models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAD Number')), "id",
('payment_pass', re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay Secret Key')), models.AutoField(
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), auto_created=True,
('minimum_payment', models.DecimalField(decimal_places=2, default=1, help_text='The minimal amount of money you have to use when paying with ComNpay', max_digits=5, verbose_name='Minimum payment')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"payment_credential",
models.CharField(
blank=True,
default="",
max_length=255,
verbose_name="ComNpay VAD Number",
),
),
(
"payment_pass",
re2o.aes_field.AESEncryptedField(
blank=True,
max_length=255,
null=True,
verbose_name="ComNpay Secret Key",
),
),
(
"payment",
models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method",
to="cotisations.Paiement",
),
),
(
"minimum_payment",
models.DecimalField(
decimal_places=2,
default=1,
help_text="The minimal amount of money you have to use when paying with ComNpay",
max_digits=5,
verbose_name="Minimum payment",
),
),
], ],
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
options={'verbose_name': 'ComNpay'}, options={"verbose_name": "ComNpay"},
), ),
migrations.CreateModel( migrations.CreateModel(
name='BalancePayment', name="BalancePayment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('minimum_balance', models.DecimalField(decimal_places=2, default=0, help_text='The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.', max_digits=5, verbose_name='Minimum balance')), "id",
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), models.AutoField(
('maximum_balance', models.DecimalField(decimal_places=2, default=50, help_text='The maximal amount of money allowed for the balance.', max_digits=5, verbose_name='Maximum balance', null=True, blank=True)), auto_created=True,
('credit_balance_allowed', models.BooleanField(default=False, verbose_name='Allow user to credit their balance')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"minimum_balance",
models.DecimalField(
decimal_places=2,
default=0,
help_text="The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.",
max_digits=5,
verbose_name="Minimum balance",
),
),
(
"payment",
models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method",
to="cotisations.Paiement",
),
),
(
"maximum_balance",
models.DecimalField(
decimal_places=2,
default=50,
help_text="The maximal amount of money allowed for the balance.",
max_digits=5,
verbose_name="Maximum balance",
null=True,
blank=True,
),
),
(
"credit_balance_allowed",
models.BooleanField(
default=False, verbose_name="Allow user to credit their balance"
),
),
], ],
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
options={'verbose_name': 'User Balance'}, options={"verbose_name": "User Balance"},
), ),
migrations.RunPython(add_comnpay), migrations.RunPython(add_comnpay),
migrations.RunPython(add_cheque), migrations.RunPython(add_cheque),
migrations.RunPython(add_solde), migrations.RunPython(add_solde),
migrations.RemoveField( migrations.RemoveField(model_name="paiement", name="type_paiement"),
model_name='paiement',
name='type_paiement',
),
] ]

View file

@ -7,14 +7,15 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0030_custom_payment")]
('cotisations', '0030_custom_payment'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='comnpaypayment', model_name="comnpaypayment",
name='production', name="production",
field=models.BooleanField(default=True, verbose_name='Production mode enabled (production url, instead of homologation)'), field=models.BooleanField(
), default=True,
verbose_name="Production mode enabled (production url, instead of homologation)",
),
)
] ]

View file

@ -10,8 +10,8 @@ import re2o.mixins
def reattribute_ids(apps, schema_editor): def reattribute_ids(apps, schema_editor):
Facture = apps.get_model('cotisations', 'Facture') Facture = apps.get_model("cotisations", "Facture")
BaseInvoice = apps.get_model('cotisations', 'BaseInvoice') BaseInvoice = apps.get_model("cotisations", "BaseInvoice")
for f in Facture.objects.all(): for f in Facture.objects.all():
base = BaseInvoice.objects.create(id=f.pk) base = BaseInvoice.objects.create(id=f.pk)
@ -22,21 +22,23 @@ def reattribute_ids(apps, schema_editor):
def update_rights(apps, schema_editor): def update_rights(apps, schema_editor):
Permission = apps.get_model('auth', 'Permission') Permission = apps.get_model("auth", "Permission")
# creates needed permissions # creates needed permissions
app = apps.get_app_config('cotisations') app = apps.get_app_config("cotisations")
app.models_module = True app.models_module = True
create_permissions(app) create_permissions(app)
app.models_module = False app.models_module = False
ContentType = apps.get_model("contenttypes", "ContentType") ContentType = apps.get_model("contenttypes", "ContentType")
content_type = ContentType.objects.get_for_model(Permission) content_type = ContentType.objects.get_for_model(Permission)
former, created = Permission.objects.get_or_create(codename='change_facture_pdf', content_type=content_type) former, created = Permission.objects.get_or_create(
new_1 = Permission.objects.get(codename='add_custominvoice') codename="change_facture_pdf", content_type=content_type
new_2 = Permission.objects.get(codename='change_custominvoice') )
new_3 = Permission.objects.get(codename='view_custominvoice') new_1 = Permission.objects.get(codename="add_custominvoice")
new_4 = Permission.objects.get(codename='delete_custominvoice') new_2 = Permission.objects.get(codename="change_custominvoice")
new_3 = Permission.objects.get(codename="view_custominvoice")
new_4 = Permission.objects.get(codename="delete_custominvoice")
for group in former.group_set.all(): for group in former.group_set.all():
group.permissions.remove(former) group.permissions.remove(former)
group.permissions.add(new_1) group.permissions.add(new_1)
@ -48,59 +50,105 @@ def update_rights(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0031_comnpaypayment_production")]
('cotisations', '0031_comnpaypayment_production'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='BaseInvoice', name="BaseInvoice",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateTimeField(auto_now_add=True, verbose_name="Date")),
], ],
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, re2o.field_permissions.FieldPermissionModelMixin, models.Model), bases=(
re2o.mixins.RevMixin,
re2o.mixins.AclMixin,
re2o.field_permissions.FieldPermissionModelMixin,
models.Model,
),
), ),
migrations.CreateModel( migrations.CreateModel(
name='CustomInvoice', name="CustomInvoice",
fields=[ fields=[
('baseinvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice')), (
('recipient', models.CharField(max_length=255, verbose_name='Recipient')), "baseinvoice_ptr",
('payment', models.CharField(max_length=255, verbose_name='Payment type')), models.OneToOneField(
('address', models.CharField(max_length=255, verbose_name='Address')), auto_created=True,
('paid', models.BooleanField(verbose_name='Paid')), on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="cotisations.BaseInvoice",
),
),
(
"recipient",
models.CharField(max_length=255, verbose_name="Recipient"),
),
(
"payment",
models.CharField(max_length=255, verbose_name="Payment type"),
),
("address", models.CharField(max_length=255, verbose_name="Address")),
("paid", models.BooleanField(verbose_name="Paid")),
], ],
bases=('cotisations.baseinvoice',), bases=("cotisations.baseinvoice",),
options={'permissions': (('view_custominvoice', 'Can view a custom invoice'),)}, options={
"permissions": (("view_custominvoice", "Can view a custom invoice"),)
},
), ),
migrations.AddField( migrations.AddField(
model_name='facture', model_name="facture",
name='baseinvoice_ptr', name="baseinvoice_ptr",
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', null=True), field=models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to="cotisations.BaseInvoice",
null=True,
),
preserve_default=False, preserve_default=False,
), ),
migrations.RunPython(reattribute_ids), migrations.RunPython(reattribute_ids),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='facture', name="facture",
field=models.ForeignKey(on_delete=models.CASCADE, verbose_name='Invoice', to='cotisations.BaseInvoice') field=models.ForeignKey(
), on_delete=models.CASCADE,
migrations.RemoveField( verbose_name="Invoice",
model_name='facture', to="cotisations.BaseInvoice",
name='id', ),
),
migrations.RemoveField(
model_name='facture',
name='date',
), ),
migrations.RemoveField(model_name="facture", name="id"),
migrations.RemoveField(model_name="facture", name="date"),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='baseinvoice_ptr', name="baseinvoice_ptr",
field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice'), field=models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="cotisations.BaseInvoice",
),
), ),
migrations.RunPython(update_rights), migrations.RunPython(update_rights),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='facture', name="facture",
options={'permissions': (('change_facture_control', 'Can change the "controlled" state'), ('view_facture', "Can see an invoice's details"), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'Invoice', 'verbose_name_plural': 'Invoices'}, options={
"permissions": (
("change_facture_control", 'Can change the "controlled" state'),
("view_facture", "Can see an invoice's details"),
("change_all_facture", "Can edit all the previous invoices"),
),
"verbose_name": "Invoice",
"verbose_name_plural": "Invoices",
},
), ),
] ]

View file

@ -11,171 +11,294 @@ import re2o.aes_field
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0032_custom_invoice")]
('cotisations', '0032_custom_invoice'),
]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='article', name="article",
options={'permissions': (('view_article', 'Can view an article object'), ('buy_every_article', 'Can buy every article')), 'verbose_name': 'article', 'verbose_name_plural': 'articles'}, options={
"permissions": (
("view_article", "Can view an article object"),
("buy_every_article", "Can buy every article"),
),
"verbose_name": "article",
"verbose_name_plural": "articles",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='balancepayment', name="balancepayment", options={"verbose_name": "user balance"}
options={'verbose_name': 'user balance'},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='banque', name="banque",
options={'permissions': (('view_banque', 'Can view a bank object'),), 'verbose_name': 'bank', 'verbose_name_plural': 'banks'}, options={
"permissions": (("view_banque", "Can view a bank object"),),
"verbose_name": "bank",
"verbose_name_plural": "banks",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='cotisation', name="cotisation",
options={'permissions': (('view_cotisation', 'Can view a subscription object'), ('change_all_cotisation', 'Can edit the previous subscriptions')), 'verbose_name': 'subscription', 'verbose_name_plural': 'subscriptions'}, options={
"permissions": (
("view_cotisation", "Can view a subscription object"),
("change_all_cotisation", "Can edit the previous subscriptions"),
),
"verbose_name": "subscription",
"verbose_name_plural": "subscriptions",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='custominvoice', name="custominvoice",
options={'permissions': (('view_custominvoice', 'Can view a custom invoice object'),)}, options={
"permissions": (
("view_custominvoice", "Can view a custom invoice object"),
)
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='facture', name="facture",
options={'permissions': (('change_facture_control', 'Can edit the "controlled" state'), ('view_facture', 'Can view an invoice object'), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'invoice', 'verbose_name_plural': 'invoices'}, options={
"permissions": (
("change_facture_control", 'Can edit the "controlled" state'),
("view_facture", "Can view an invoice object"),
("change_all_facture", "Can edit all the previous invoices"),
),
"verbose_name": "invoice",
"verbose_name_plural": "invoices",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='paiement', name="paiement",
options={'permissions': (('view_paiement', 'Can view a payment method object'), ('use_every_payment', 'Can use every payment method')), 'verbose_name': 'payment method', 'verbose_name_plural': 'payment methods'}, options={
"permissions": (
("view_paiement", "Can view a payment method object"),
("use_every_payment", "Can use every payment method"),
),
"verbose_name": "payment method",
"verbose_name_plural": "payment methods",
},
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='vente', name="vente",
options={'permissions': (('view_vente', 'Can view a purchase object'), ('change_all_vente', 'Can edit all the previous purchases')), 'verbose_name': 'purchase', 'verbose_name_plural': 'purchases'}, options={
"permissions": (
("view_vente", "Can view a purchase object"),
("change_all_vente", "Can edit all the previous purchases"),
),
"verbose_name": "purchase",
"verbose_name_plural": "purchases",
},
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='available_for_everyone', name="available_for_everyone",
field=models.BooleanField(default=False, verbose_name='is available for every user'), field=models.BooleanField(
default=False, verbose_name="is available for every user"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='duration', name="duration",
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in months)'), field=models.PositiveIntegerField(
blank=True,
null=True,
validators=[django.core.validators.MinValueValidator(0)],
verbose_name="duration (in months)",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='name', name="name",
field=models.CharField(max_length=255, verbose_name='designation'), field=models.CharField(max_length=255, verbose_name="designation"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='prix', name="prix",
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='unit price'), field=models.DecimalField(
decimal_places=2, max_digits=5, verbose_name="unit price"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='type_cotisation', name="type_cotisation",
field=models.CharField(blank=True, choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default=None, max_length=255, null=True, verbose_name='subscription type'), field=models.CharField(
blank=True,
choices=[
("Connexion", "Connection"),
("Adhesion", "Membership"),
("All", "Both of them"),
],
default=None,
max_length=255,
null=True,
verbose_name="subscription type",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='article', model_name="article",
name='type_user', name="type_user",
field=models.CharField(choices=[('Adherent', 'Member'), ('Club', 'Club'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='type of users concerned'), field=models.CharField(
choices=[
("Adherent", "Member"),
("Club", "Club"),
("All", "Both of them"),
],
default="All",
max_length=255,
verbose_name="type of users concerned",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='banque', model_name="banque", name="name", field=models.CharField(max_length=255)
name='name',
field=models.CharField(max_length=255),
), ),
migrations.AlterField( migrations.AlterField(
model_name='comnpaypayment', model_name="comnpaypayment",
name='payment_credential', name="payment_credential",
field=models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAT Number'), field=models.CharField(
blank=True,
default="",
max_length=255,
verbose_name="ComNpay VAT Number",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='comnpaypayment', model_name="comnpaypayment",
name='payment_pass', name="payment_pass",
field=re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay secret key'), field=re2o.aes_field.AESEncryptedField(
blank=True, max_length=255, null=True, verbose_name="ComNpay secret key"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='comnpaypayment', model_name="comnpaypayment",
name='production', name="production",
field=models.BooleanField(default=True, verbose_name='Production mode enabled (production URL, instead of homologation)'), field=models.BooleanField(
default=True,
verbose_name="Production mode enabled (production URL, instead of homologation)",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='date_end', name="date_end",
field=models.DateTimeField(verbose_name='end date'), field=models.DateTimeField(verbose_name="end date"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='date_start', name="date_start",
field=models.DateTimeField(verbose_name='start date'), field=models.DateTimeField(verbose_name="start date"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='type_cotisation', name="type_cotisation",
field=models.CharField(choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='subscription type'), field=models.CharField(
choices=[
("Connexion", "Connection"),
("Adhesion", "Membership"),
("All", "Both of them"),
],
default="All",
max_length=255,
verbose_name="subscription type",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='cotisation', model_name="cotisation",
name='vente', name="vente",
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='cotisations.Vente', verbose_name='purchase'), field=models.OneToOneField(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="cotisations.Vente",
verbose_name="purchase",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='cheque', name="cheque",
field=models.CharField(blank=True, max_length=255, verbose_name='cheque number'), field=models.CharField(
blank=True, max_length=255, verbose_name="cheque number"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='control', name="control",
field=models.BooleanField(default=False, verbose_name='controlled'), field=models.BooleanField(default=False, verbose_name="controlled"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='valid', name="valid",
field=models.BooleanField(default=True, verbose_name='validated'), field=models.BooleanField(default=True, verbose_name="validated"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='available_for_everyone', name="available_for_everyone",
field=models.BooleanField(default=False, verbose_name='is available for every user'), field=models.BooleanField(
default=False, verbose_name="is available for every user"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='is_balance', name="is_balance",
field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', validators=[cotisations.validators.check_no_balance], verbose_name='is user balance'), field=models.BooleanField(
default=False,
editable=False,
help_text="There should be only one balance payment method.",
validators=[cotisations.validators.check_no_balance],
verbose_name="is user balance",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='paiement', model_name="paiement",
name='moyen', name="moyen",
field=models.CharField(max_length=255, verbose_name='method'), field=models.CharField(max_length=255, verbose_name="method"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='duration', name="duration",
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='duration (in months)'), field=models.PositiveIntegerField(
blank=True, null=True, verbose_name="duration (in months)"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='facture', name="facture",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', verbose_name='invoice'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="cotisations.BaseInvoice",
verbose_name="invoice",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='name', name="name",
field=models.CharField(max_length=255, verbose_name='article'), field=models.CharField(max_length=255, verbose_name="article"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='number', name="number",
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)], verbose_name='amount'), field=models.IntegerField(
validators=[django.core.validators.MinValueValidator(1)],
verbose_name="amount",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='prix', name="prix",
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='price'), field=models.DecimalField(
decimal_places=2, max_digits=5, verbose_name="price"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='vente', model_name="vente",
name='type_cotisation', name="type_cotisation",
field=models.CharField(blank=True, choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], max_length=255, null=True, verbose_name='subscription type'), field=models.CharField(
blank=True,
choices=[
("Connexion", "Connection"),
("Adhesion", "Membership"),
("All", "Both of them"),
],
max_length=255,
null=True,
verbose_name="subscription type",
),
), ),
] ]

View file

@ -7,14 +7,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0033_auto_20180818_1319")]
('cotisations', '0033_auto_20180818_1319'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='facture', model_name="facture",
name='valid', name="valid",
field=models.BooleanField(default=False, verbose_name='validated'), field=models.BooleanField(default=False, verbose_name="validated"),
), )
] ]

View file

@ -9,23 +9,35 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0034_auto_20180831_1532")]
('cotisations', '0034_auto_20180831_1532'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='NotePayment', name="NotePayment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('server', models.CharField(max_length=255, verbose_name='server')), "id",
('port', models.PositiveIntegerField(blank=True, null=True)), models.AutoField(
('id_note', models.PositiveIntegerField(blank=True, null=True)), auto_created=True,
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("server", models.CharField(max_length=255, verbose_name="server")),
("port", models.PositiveIntegerField(blank=True, null=True)),
("id_note", models.PositiveIntegerField(blank=True, null=True)),
(
"payment",
models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method",
to="cotisations.Paiement",
),
),
], ],
options={ options={"verbose_name": "NoteKfet"},
'verbose_name': 'NoteKfet',
},
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
), )
] ]

View file

@ -7,14 +7,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0035_notepayment")]
('cotisations', '0035_notepayment'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='custominvoice', model_name="custominvoice",
name='remark', name="remark",
field=models.TextField(blank=True, null=True, verbose_name='Remark'), field=models.TextField(blank=True, null=True, verbose_name="Remark"),
), )
] ]

View file

@ -8,21 +8,40 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0036_custominvoice_remark")]
('cotisations', '0036_custominvoice_remark'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='CostEstimate', name="CostEstimate",
fields=[ fields=[
('custominvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.CustomInvoice')), (
('validity', models.DurationField(verbose_name='Period of validity')), "custominvoice_ptr",
('final_invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='origin_cost_estimate', to='cotisations.CustomInvoice')), models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="cotisations.CustomInvoice",
),
),
("validity", models.DurationField(verbose_name="Period of validity")),
(
"final_invoice",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="origin_cost_estimate",
to="cotisations.CustomInvoice",
),
),
], ],
options={ options={
'permissions': (('view_costestimate', 'Can view a cost estimate object'),), "permissions": (
("view_costestimate", "Can view a cost estimate object"),
)
}, },
bases=('cotisations.custominvoice',), bases=("cotisations.custominvoice",),
), )
] ]

View file

@ -8,24 +8,30 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0037_costestimate")]
('cotisations', '0037_costestimate'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='costestimate', model_name="costestimate",
name='final_invoice', name="final_invoice",
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='origin_cost_estimate', to='cotisations.CustomInvoice'), field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="origin_cost_estimate",
to="cotisations.CustomInvoice",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='costestimate', model_name="costestimate",
name='validity', name="validity",
field=models.DurationField(help_text='DD HH:MM:SS', verbose_name='Period of validity'), field=models.DurationField(
help_text="DD HH:MM:SS", verbose_name="Period of validity"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='custominvoice', model_name="custominvoice",
name='paid', name="paid",
field=models.BooleanField(default=False, verbose_name='Paid'), field=models.BooleanField(default=False, verbose_name="Paid"),
), ),
] ]

View file

@ -9,20 +9,32 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0038_auto_20181231_1657")]
('cotisations', '0038_auto_20181231_1657'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='FreePayment', name="FreePayment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"payment",
models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method",
to="cotisations.Paiement",
),
),
], ],
options={ options={"verbose_name": "Free payment"},
'verbose_name': 'Free payment',
},
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
), )
] ]

View file

@ -8,19 +8,27 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0039_freepayment")]
('cotisations', '0039_freepayment'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='article', model_name="article",
name='duration_days', name="duration_days",
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in days, will be added to duration in months)'), field=models.PositiveIntegerField(
blank=True,
null=True,
validators=[django.core.validators.MinValueValidator(0)],
verbose_name="duration (in days, will be added to duration in months)",
),
), ),
migrations.AddField( migrations.AddField(
model_name='vente', model_name="vente",
name='duration_days', name="duration_days",
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in days, will be added to duration in months)'), field=models.PositiveIntegerField(
blank=True,
null=True,
validators=[django.core.validators.MinValueValidator(0)],
verbose_name="duration (in days, will be added to duration in months)",
),
), ),
] ]

View file

@ -8,34 +8,57 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("cotisations", "0040_auto_20191002_2335")]
('cotisations', '0040_auto_20191002_2335'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='balancepayment', model_name="balancepayment",
name='payment', name="payment",
field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_balance', to='cotisations.Paiement'), field=models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method_balance",
to="cotisations.Paiement",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='chequepayment', model_name="chequepayment",
name='payment', name="payment",
field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_cheque', to='cotisations.Paiement'), field=models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method_cheque",
to="cotisations.Paiement",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='comnpaypayment', model_name="comnpaypayment",
name='payment', name="payment",
field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_comnpay', to='cotisations.Paiement'), field=models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method_comnpay",
to="cotisations.Paiement",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='freepayment', model_name="freepayment",
name='payment', name="payment",
field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_free', to='cotisations.Paiement'), field=models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method_free",
to="cotisations.Paiement",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='notepayment', model_name="notepayment",
name='payment', name="payment",
field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_note', to='cotisations.Paiement'), field=models.OneToOneField(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="payment_method_note",
to="cotisations.Paiement",
),
), ),
] ]

View file

@ -19,4 +19,3 @@
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

File diff suppressed because it is too large Load diff

View file

@ -129,10 +129,4 @@ method to your model, where `form` is an instance of
from . import comnpay, cheque, balance, note_kfet, free, urls from . import comnpay, cheque, balance, note_kfet, free, urls
PAYMENT_METHODS = [ PAYMENT_METHODS = [comnpay, cheque, balance, note_kfet, free]
comnpay,
cheque,
balance,
note_kfet,
free
]

View file

@ -22,6 +22,7 @@
This module contains a method to pay online using user balance. This module contains a method to pay online using user balance.
""" """
from . import models from . import models
NAME = "BALANCE" NAME = "BALANCE"
PaymentMethod = models.BalancePayment PaymentMethod = models.BalancePayment

View file

@ -40,15 +40,16 @@ class BalancePayment(PaymentMethodMixin, models.Model):
payment = models.OneToOneField( payment = models.OneToOneField(
Paiement, Paiement,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='payment_method_balance', related_name="payment_method_balance",
editable=False editable=False,
) )
minimum_balance = models.DecimalField( minimum_balance = models.DecimalField(
verbose_name=_("Minimum balance"), verbose_name=_("Minimum balance"),
help_text=_("The minimal amount of money allowed for the balance" help_text=_(
" at the end of a payment. You can specify negative " "The minimal amount of money allowed for the balance"
"amount." " at the end of a payment. You can specify negative "
), "amount."
),
max_digits=5, max_digits=5,
decimal_places=2, decimal_places=2,
default=0, default=0,
@ -63,8 +64,7 @@ class BalancePayment(PaymentMethodMixin, models.Model):
null=True, null=True,
) )
credit_balance_allowed = models.BooleanField( credit_balance_allowed = models.BooleanField(
verbose_name=_("Allow user to credit their balance"), verbose_name=_("Allow user to credit their balance"), default=False
default=False,
) )
def end_payment(self, invoice, request): def end_payment(self, invoice, request):
@ -74,27 +74,17 @@ class BalancePayment(PaymentMethodMixin, models.Model):
user = invoice.user user = invoice.user
total_price = invoice.prix_total() total_price = invoice.prix_total()
if user.solde - total_price < self.minimum_balance: if user.solde - total_price < self.minimum_balance:
messages.error( messages.error(request, _("Your balance is too low for this operation."))
request, return redirect(reverse("users:profil", kwargs={"userid": user.id}))
_("Your balance is too low for this operation.") return invoice.paiement.end_payment(invoice, request, use_payment_method=False)
)
return redirect(reverse(
'users:profil',
kwargs={'userid': user.id}
))
return invoice.paiement.end_payment(
invoice,
request,
use_payment_method=False
)
def valid_form(self, form): def valid_form(self, form):
"""Checks that there is not already a balance payment method.""" """Checks that there is not already a balance payment method."""
p = Paiement.objects.filter(is_balance=True) p = Paiement.objects.filter(is_balance=True)
if len(p) > 0: if len(p) > 0:
form.add_error( form.add_error(
'payment_method', "payment_method",
_("There is already a payment method for user balance.") _("There is already a payment method for user balance."),
) )
def alter_payment(self, payment): def alter_payment(self, payment):
@ -107,12 +97,11 @@ class BalancePayment(PaymentMethodMixin, models.Model):
""" """
return ( return (
user.solde - price >= self.minimum_balance, user.solde - price >= self.minimum_balance,
_("Your balance is too low for this operation.") _("Your balance is too low for this operation."),
) )
def can_credit_balance(self, user_request): def can_credit_balance(self, user_request):
return ( return (
len(Paiement.find_allowed_payments(user_request) len(Paiement.find_allowed_payments(user_request).exclude(is_balance=True))
.exclude(is_balance=True)) > 0 > 0
) and self.credit_balance_allowed ) and self.credit_balance_allowed

View file

@ -22,6 +22,7 @@
This module contains a method to pay online using cheque. This module contains a method to pay online using cheque.
""" """
from . import models, urls, views from . import models, urls, views
NAME = "CHEQUE" NAME = "CHEQUE"
PaymentMethod = models.ChequePayment PaymentMethod = models.ChequePayment

View file

@ -26,6 +26,7 @@ from cotisations.models import Facture as Invoice
class InvoiceForm(FormRevMixin, forms.ModelForm): class InvoiceForm(FormRevMixin, forms.ModelForm):
"""A simple form to get the bank a the cheque number.""" """A simple form to get the bank a the cheque number."""
class Meta: class Meta:
model = Invoice model = Invoice
fields = ['banque', 'cheque'] fields = ["banque", "cheque"]

View file

@ -38,16 +38,14 @@ class ChequePayment(PaymentMethodMixin, models.Model):
payment = models.OneToOneField( payment = models.OneToOneField(
Paiement, Paiement,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='payment_method_cheque', related_name="payment_method_cheque",
editable=False editable=False,
) )
def end_payment(self, invoice, request): def end_payment(self, invoice, request):
"""Invalidates the invoice then redirect the user towards a view asking """Invalidates the invoice then redirect the user towards a view asking
for informations to add to the invoice before validating it. for informations to add to the invoice before validating it.
""" """
return redirect(reverse( return redirect(
'cotisations:cheque:validate', reverse("cotisations:cheque:validate", kwargs={"invoice_pk": invoice.pk})
kwargs={'invoice_pk': invoice.pk} )
))

View file

@ -21,10 +21,4 @@
from django.conf.urls import url from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [url(r"^validate/(?P<invoice_pk>[0-9]+)$", views.cheque, name="validate")]
url(
r'^validate/(?P<invoice_pk>[0-9]+)$',
views.cheque,
name='validate'
)
]

View file

@ -42,29 +42,17 @@ def cheque(request, invoice_pk):
invoice = get_object_or_404(Invoice, pk=invoice_pk) invoice = get_object_or_404(Invoice, pk=invoice_pk)
payment_method = find_payment_method(invoice.paiement) payment_method = find_payment_method(invoice.paiement)
if invoice.valid or not isinstance(payment_method, ChequePayment): if invoice.valid or not isinstance(payment_method, ChequePayment):
messages.error( messages.error(request, _("You can't pay this invoice with a cheque."))
request, return redirect(reverse("users:profil", kwargs={"userid": request.user.pk}))
_("You can't pay this invoice with a cheque.")
)
return redirect(reverse(
'users:profil',
kwargs={'userid': request.user.pk}
))
form = InvoiceForm(request.POST or None, instance=invoice) form = InvoiceForm(request.POST or None, instance=invoice)
if form.is_valid(): if form.is_valid():
form.instance.valid = True form.instance.valid = True
form.save() form.save()
return form.instance.paiement.end_payment( return form.instance.paiement.end_payment(
form.instance, form.instance, request, use_payment_method=False
request,
use_payment_method=False
) )
return render( return render(
request, request,
'cotisations/payment.html', "cotisations/payment.html",
{ {"form": form, "amount": invoice.prix_total()},
'form': form,
'amount': invoice.prix_total()
}
) )

View file

@ -22,5 +22,6 @@
This module contains a method to pay online using comnpay. This module contains a method to pay online using comnpay.
""" """
from . import models, urls, views from . import models, urls, views
NAME = "COMNPAY" NAME = "COMNPAY"
PaymentMethod = models.ComnpayPayment PaymentMethod = models.ComnpayPayment

View file

@ -10,13 +10,21 @@ import hashlib
from collections import OrderedDict from collections import OrderedDict
class Transaction(): class Transaction:
""" The class representing a transaction with all the functions """ The class representing a transaction with all the functions
used during the negociation used during the negociation
""" """
def __init__(self, vad_number="", secret_key="", urlRetourOK="", def __init__(
urlRetourNOK="", urlIPN="", source="", typeTr="D"): self,
vad_number="",
secret_key="",
urlRetourOK="",
urlRetourNOK="",
urlIPN="",
source="",
typeTr="D",
):
self.vad_number = vad_number self.vad_number = vad_number
self.secret_key = secret_key self.secret_key = secret_key
self.urlRetourOK = urlRetourOK self.urlRetourOK = urlRetourOK
@ -26,8 +34,7 @@ class Transaction():
self.typeTr = typeTr self.typeTr = typeTr
self.idTransaction = "" self.idTransaction = ""
def buildSecretHTML(self, produit="Produit", montant="0.00", def buildSecretHTML(self, produit="Produit", montant="0.00", idTransaction=""):
idTransaction=""):
""" Build an HTML hidden form with the different parameters for the """ Build an HTML hidden form with the different parameters for the
transaction transaction
""" """
@ -43,30 +50,26 @@ class Transaction():
idTPE=self.vad_number, idTPE=self.vad_number,
idTransaction=self.idTransaction, idTransaction=self.idTransaction,
devise="EUR", devise="EUR",
lang='fr', lang="fr",
nom_produit=produit, nom_produit=produit,
source=self.source, source=self.source,
urlRetourOK=self.urlRetourOK, urlRetourOK=self.urlRetourOK,
urlRetourNOK=self.urlRetourNOK, urlRetourNOK=self.urlRetourNOK,
typeTr=str(self.typeTr) typeTr=str(self.typeTr),
) )
if self.urlIPN != "": if self.urlIPN != "":
array_tpe['urlIPN'] = self.urlIPN array_tpe["urlIPN"] = self.urlIPN
array_tpe['key'] = self.secret_key array_tpe["key"] = self.secret_key
strWithKey = base64.b64encode(bytes( strWithKey = base64.b64encode(bytes("|".join(array_tpe.values()), "utf-8"))
'|'.join(array_tpe.values()),
'utf-8'
))
del array_tpe["key"] del array_tpe["key"]
array_tpe['sec'] = hashlib.sha512(strWithKey).hexdigest() array_tpe["sec"] = hashlib.sha512(strWithKey).hexdigest()
ret = "" ret = ""
for key in array_tpe: for key in array_tpe:
ret += '<input type="hidden" name="{k}" value="{v}"/>'.format( ret += '<input type="hidden" name="{k}" value="{v}"/>'.format(
k=key, k=key, v=array_tpe[key]
v=array_tpe[key]
) )
return ret return ret
@ -75,12 +78,13 @@ class Transaction():
def validSec(values, secret_key): def validSec(values, secret_key):
""" Check if the secret value is correct """ """ Check if the secret value is correct """
if "sec" in values: if "sec" in values:
sec = values['sec'] sec = values["sec"]
del values["sec"] del values["sec"]
strWithKey = hashlib.sha512(base64.b64encode(bytes( strWithKey = hashlib.sha512(
'|'.join(values.values()) + "|" + secret_key, base64.b64encode(
'utf-8' bytes("|".join(values.values()) + "|" + secret_key, "utf-8")
))).hexdigest() )
).hexdigest()
return strWithKey.upper() == sec.upper() return strWithKey.upper() == sec.upper()
else: else:
return False return False

View file

@ -41,39 +41,36 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
payment = models.OneToOneField( payment = models.OneToOneField(
Paiement, Paiement,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='payment_method_comnpay', related_name="payment_method_comnpay",
editable=False editable=False,
) )
payment_credential = models.CharField( payment_credential = models.CharField(
max_length=255, max_length=255, default="", blank=True, verbose_name=_("ComNpay VAT Number")
default='',
blank=True,
verbose_name=_("ComNpay VAT Number"),
) )
payment_pass = AESEncryptedField( payment_pass = AESEncryptedField(
max_length=255, max_length=255, null=True, blank=True, verbose_name=_("ComNpay secret key")
null=True,
blank=True,
verbose_name=_("ComNpay secret key"),
) )
minimum_payment = models.DecimalField( minimum_payment = models.DecimalField(
verbose_name=_("Minimum payment"), verbose_name=_("Minimum payment"),
help_text=_("The minimal amount of money you have to use when paying" help_text=_(
" with ComNpay"), "The minimal amount of money you have to use when paying" " with ComNpay"
),
max_digits=5, max_digits=5,
decimal_places=2, decimal_places=2,
default=1, default=1,
) )
production = models.BooleanField( production = models.BooleanField(
default=True, default=True,
verbose_name=_("Production mode enabled (production URL, instead of homologation)"), verbose_name=_(
"Production mode enabled (production URL, instead of homologation)"
),
) )
def return_url_comnpay(self): def return_url_comnpay(self):
if self.production: if self.production:
return 'https://secure.comnpay.com' return "https://secure.comnpay.com"
else: else:
return 'https://secure.homologation.comnpay.com' return "https://secure.homologation.comnpay.com"
def end_payment(self, invoice, request): def end_payment(self, invoice, request):
""" """
@ -85,32 +82,36 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
p = Transaction( p = Transaction(
str(self.payment_credential), str(self.payment_credential),
str(self.payment_pass), str(self.payment_pass),
'https://' + host + reverse( "https://"
'cotisations:comnpay:accept_payment', + host
kwargs={'factureid': invoice.id} + reverse(
"cotisations:comnpay:accept_payment", kwargs={"factureid": invoice.id}
), ),
'https://' + host + reverse('cotisations:comnpay:refuse_payment'), "https://" + host + reverse("cotisations:comnpay:refuse_payment"),
'https://' + host + reverse('cotisations:comnpay:ipn'), "https://" + host + reverse("cotisations:comnpay:ipn"),
"", "",
"D" "D",
) )
r = { r = {
'action': self.return_url_comnpay(), "action": self.return_url_comnpay(),
'method': 'POST', "method": "POST",
'content': p.buildSecretHTML( "content": p.buildSecretHTML(
_("Pay invoice number ")+str(invoice.id), _("Pay invoice number ") + str(invoice.id),
invoice.prix_total(), invoice.prix_total(),
idTransaction=str(invoice.id) idTransaction=str(invoice.id),
), ),
'amount': invoice.prix_total(), "amount": invoice.prix_total(),
} }
return render(request, 'cotisations/payment.html', r) return render(request, "cotisations/payment.html", r)
def check_price(self, price, *args, **kwargs): def check_price(self, price, *args, **kwargs):
"""Checks that the price meets the requirement to be paid with ComNpay. """Checks that the price meets the requirement to be paid with ComNpay.
""" """
return ((price >= self.minimum_payment), return (
_("In order to pay your invoice with ComNpay, the price must" (price >= self.minimum_payment),
" be greater than {} €.").format(self.minimum_payment)) _(
"In order to pay your invoice with ComNpay, the price must"
" be greater than {} €."
).format(self.minimum_payment),
)

View file

@ -22,19 +22,7 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url( url(r"^accept/(?P<factureid>[0-9]+)$", views.accept_payment, name="accept_payment"),
r'^accept/(?P<factureid>[0-9]+)$', url(r"^refuse/$", views.refuse_payment, name="refuse_payment"),
views.accept_payment, url(r"^ipn/$", views.ipn, name="ipn"),
name='accept_payment'
),
url(
r'^refuse/$',
views.refuse_payment,
name='refuse_payment'
),
url(
r'^ipn/$',
views.ipn,
name='ipn'
),
] ]

View file

@ -50,26 +50,24 @@ def accept_payment(request, factureid):
if invoice.valid: if invoice.valid:
messages.success( messages.success(
request, request,
_("The payment of %(amount)s € was accepted.") % { _("The payment of %(amount)s € was accepted.")
'amount': invoice.prix_total() % {"amount": invoice.prix_total()},
}
) )
# In case a cotisation was bought, inform the user, the # In case a cotisation was bought, inform the user, the
# cotisation time has been extended too # cotisation time has been extended too
if any(purchase.type_cotisation if any(purchase.type_cotisation for purchase in invoice.vente_set.all()):
for purchase in invoice.vente_set.all()):
messages.success( messages.success(
request, request,
_("The subscription of %(member_name)s was extended to" _(
" %(end_date)s.") % { "The subscription of %(member_name)s was extended to"
'member_name': invoice.user.pseudo, " %(end_date)s."
'end_date': invoice.user.end_adhesion() )
} % {
"member_name": invoice.user.pseudo,
"end_date": invoice.user.end_adhesion(),
},
) )
return redirect(reverse( return redirect(reverse("users:profil", kwargs={"userid": invoice.user.id}))
'users:profil',
kwargs={'userid': invoice.user.id}
))
@csrf_exempt @csrf_exempt
@ -79,14 +77,8 @@ def refuse_payment(request):
The view where the user is redirected when a comnpay payment has been The view where the user is redirected when a comnpay payment has been
refused. refused.
""" """
messages.error( messages.error(request, _("The payment was refused."))
request, return redirect(reverse("users:profil", kwargs={"userid": request.user.id}))
_("The payment was refused.")
)
return redirect(reverse(
'users:profil',
kwargs={'userid': request.user.id}
))
@csrf_exempt @csrf_exempt
@ -97,27 +89,26 @@ def ipn(request):
Comnpay with 400 response if not or with a 200 response if yes. Comnpay with 400 response if not or with a 200 response if yes.
""" """
p = Transaction() p = Transaction()
order = ('idTpe', 'idTransaction', 'montant', 'result', 'sec', ) order = ("idTpe", "idTransaction", "montant", "result", "sec")
try: try:
data = OrderedDict([(f, request.POST[f]) for f in order]) data = OrderedDict([(f, request.POST[f]) for f in order])
except MultiValueDictKeyError: except MultiValueDictKeyError:
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
idTransaction = request.POST['idTransaction'] idTransaction = request.POST["idTransaction"]
try: try:
factureid = int(idTransaction) factureid = int(idTransaction)
except ValueError: except ValueError:
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
facture = get_object_or_404(Facture, id=factureid) facture = get_object_or_404(Facture, id=factureid)
payment_method = get_object_or_404( payment_method = get_object_or_404(ComnpayPayment, payment=facture.paiement)
ComnpayPayment, payment=facture.paiement)
if not p.validSec(data, payment_method.payment_pass): if not p.validSec(data, payment_method.payment_pass):
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
result = True if (request.POST['result'] == 'OK') else False result = True if (request.POST["result"] == "OK") else False
idTpe = request.POST['idTpe'] idTpe = request.POST["idTpe"]
# Checking that the payment is actually for us. # Checking that the payment is actually for us.
if not idTpe == payment_method.payment_credential: if not idTpe == payment_method.payment_credential:
@ -136,4 +127,3 @@ def ipn(request):
# Everything worked we send a reponse to Comnpay indicating that # Everything worked we send a reponse to Comnpay indicating that
# it's ok for them to proceed # it's ok for them to proceed
return HttpResponse("HTTP/1.0 200 OK") return HttpResponse("HTTP/1.0 200 OK")

View file

@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from . import PAYMENT_METHODS from . import PAYMENT_METHODS
from cotisations.utils import find_payment_method from cotisations.utils import find_payment_method
def payment_method_factory(payment, *args, creation=True, **kwargs): def payment_method_factory(payment, *args, creation=True, **kwargs):
"""This function finds the right payment method form for a given payment. """This function finds the right payment method form for a given payment.
@ -40,12 +41,10 @@ def payment_method_factory(payment, *args, creation=True, **kwargs):
Returns: Returns:
A form or None A form or None
""" """
payment_method = kwargs.pop('instance', find_payment_method(payment)) payment_method = kwargs.pop("instance", find_payment_method(payment))
if payment_method is not None: if payment_method is not None:
return forms.modelform_factory(type(payment_method), fields='__all__')( return forms.modelform_factory(type(payment_method), fields="__all__")(
*args, *args, instance=payment_method, **kwargs
instance=payment_method,
**kwargs
) )
elif creation: elif creation:
return PaymentMethodForm(*args, **kwargs) return PaymentMethodForm(*args, **kwargs)
@ -58,23 +57,24 @@ class PaymentMethodForm(forms.Form):
payment_method = forms.ChoiceField( payment_method = forms.ChoiceField(
label=_("Special payment method"), label=_("Special payment method"),
help_text=_("Warning: you will not be able to change the payment " help_text=_(
"method later. But you will be allowed to edit the other " "Warning: you will not be able to change the payment "
"options." "method later. But you will be allowed to edit the other "
"options."
), ),
required=False required=False,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PaymentMethodForm, self).__init__(*args, **kwargs) super(PaymentMethodForm, self).__init__(*args, **kwargs)
prefix = kwargs.get('prefix', None) prefix = kwargs.get("prefix", None)
self.fields['payment_method'].choices = [(i,p.NAME) for (i,p) in enumerate(PAYMENT_METHODS)] self.fields["payment_method"].choices = [
self.fields['payment_method'].choices.insert(0, ('', _('no'))) (i, p.NAME) for (i, p) in enumerate(PAYMENT_METHODS)
self.fields['payment_method'].widget.attrs = { ]
'id': 'paymentMethodSelect' self.fields["payment_method"].choices.insert(0, ("", _("no")))
} self.fields["payment_method"].widget.attrs = {"id": "paymentMethodSelect"}
self.templates = [ self.templates = [
forms.modelform_factory(p.PaymentMethod, fields='__all__')(prefix=prefix) forms.modelform_factory(p.PaymentMethod, fields="__all__")(prefix=prefix)
for p in PAYMENT_METHODS for p in PAYMENT_METHODS
] ]
@ -84,29 +84,29 @@ class PaymentMethodForm(forms.Form):
found. Tries to call `payment_method.valid_form` if it exists. found. Tries to call `payment_method.valid_form` if it exists.
""" """
super(PaymentMethodForm, self).clean() super(PaymentMethodForm, self).clean()
choice = self.cleaned_data['payment_method'] choice = self.cleaned_data["payment_method"]
if choice=='': if choice == "":
return return
choice = int(choice) choice = int(choice)
model = PAYMENT_METHODS[choice].PaymentMethod model = PAYMENT_METHODS[choice].PaymentMethod
form = forms.modelform_factory(model, fields='__all__')(self.data, prefix=self.prefix) form = forms.modelform_factory(model, fields="__all__")(
self.data, prefix=self.prefix
)
self.payment_method = form.save(commit=False) self.payment_method = form.save(commit=False)
if hasattr(self.payment_method, 'valid_form'): if hasattr(self.payment_method, "valid_form"):
self.payment_method.valid_form(self) self.payment_method.valid_form(self)
return self.cleaned_data return self.cleaned_data
def save(self, payment, *args, **kwargs): def save(self, payment, *args, **kwargs):
"""Saves the payment method. """Saves the payment method.
Tries to call `payment_method.alter_payment` if it exists. Tries to call `payment_method.alter_payment` if it exists.
""" """
commit = kwargs.pop('commit', True) commit = kwargs.pop("commit", True)
if not hasattr(self, 'payment_method'): if not hasattr(self, "payment_method"):
return None return None
self.payment_method.payment = payment self.payment_method.payment = payment
if hasattr(self.payment_method, 'alter_payment'): if hasattr(self.payment_method, "alter_payment"):
self.payment_method.alter_payment(payment) self.payment_method.alter_payment(payment)
if commit: if commit:
payment.save() payment.save()

View file

@ -22,6 +22,7 @@
This module contains a method to pay online using user balance. This module contains a method to pay online using user balance.
""" """
from . import models from . import models
NAME = "FREE" NAME = "FREE"
PaymentMethod = models.FreePayment PaymentMethod = models.FreePayment

View file

@ -38,24 +38,17 @@ class FreePayment(PaymentMethodMixin, models.Model):
payment = models.OneToOneField( payment = models.OneToOneField(
Paiement, Paiement,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='payment_method_free', related_name="payment_method_free",
editable=False editable=False,
) )
def end_payment(self, invoice, request): def end_payment(self, invoice, request):
"""Ends the payment normally. """Ends the payment normally.
""" """
return invoice.paiement.end_payment( return invoice.paiement.end_payment(invoice, request, use_payment_method=False)
invoice,
request,
use_payment_method=False
)
def check_price(self, price, user, *args, **kwargs): def check_price(self, price, user, *args, **kwargs):
"""Checks that the price meets the requirement to be paid with user """Checks that the price meets the requirement to be paid with user
balance. balance.
""" """
return ( return (price == 0, _("You cannot validate this invoice for free."))
price == 0,
_("You cannot validate this invoice for free.")
)

View file

@ -29,5 +29,4 @@ class PaymentMethodMixin:
Must return a HttpResponse-like object. Must return a HttpResponse-like object.
""" """
return self.payment.end_payment( return self.payment.end_payment(invoice, request, use_payment_method=False)
invoice, request, use_payment_method=False)

View file

@ -22,5 +22,6 @@
This module contains a method to pay online using comnpay. This module contains a method to pay online using comnpay.
""" """
from . import models, urls from . import models, urls
NAME = "NOTE" NAME = "NOTE"
PaymentMethod = models.NotePayment PaymentMethod = models.NotePayment

View file

@ -24,15 +24,11 @@ from django.utils.translation import ugettext_lazy as _
from cotisations.utils import find_payment_method from cotisations.utils import find_payment_method
class NoteCredentialForm(forms.Form): class NoteCredentialForm(forms.Form):
"""A special form to get credential to connect to a NoteKfet2015 server throught his API """A special form to get credential to connect to a NoteKfet2015 server throught his API
object. object.
""" """
login = forms.CharField(
label=_("pseudo note") login = forms.CharField(label=_("pseudo note"))
) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
password = forms.CharField(
label=_("Password"),
widget=forms.PasswordInput
)

View file

@ -41,25 +41,17 @@ class NotePayment(PaymentMethodMixin, models.Model):
payment = models.OneToOneField( payment = models.OneToOneField(
Paiement, Paiement,
on_delete = models.CASCADE, on_delete=models.CASCADE,
related_name = 'payment_method_note', related_name="payment_method_note",
editable = False editable=False,
)
server = models.CharField(
max_length=255,
verbose_name=_("server")
)
port = models.PositiveIntegerField(
blank = True,
null = True
)
id_note = models.PositiveIntegerField(
blank = True,
null = True
) )
server = models.CharField(max_length=255, verbose_name=_("server"))
port = models.PositiveIntegerField(blank=True, null=True)
id_note = models.PositiveIntegerField(blank=True, null=True)
def end_payment(self, invoice, request): def end_payment(self, invoice, request):
return redirect(reverse( return redirect(
'cotisations:note_kfet:note_payment', reverse(
kwargs={'factureid': invoice.id} "cotisations:note_kfet:note_payment", kwargs={"factureid": invoice.id}
)) )
)

View file

@ -12,13 +12,14 @@ import traceback
def get_response(socket): def get_response(socket):
length_str = b'' length_str = b""
char = socket.recv(1) char = socket.recv(1)
while char != b'\n': while char != b"\n":
length_str += char length_str += char
char = socket.recv(1) char = socket.recv(1)
total = int(length_str) total = int(length_str)
return json.loads(socket.recv(total).decode('utf-8')) return json.loads(socket.recv(total).decode("utf-8"))
def connect(server, port): def connect(server, port):
sock = socket.socket() sock = socket.socket()
@ -35,7 +36,8 @@ def connect(server, port):
return (False, sock, "Serveur indisponible") return (False, sock, "Serveur indisponible")
return (True, sock, "") return (True, sock, "")
def login(server, port, username, password, masque = [[], [], True]):
def login(server, port, username, password, masque=[[], [], True]):
result, sock, err = connect(server, port) result, sock, err = connect(server, port)
if not result: if not result:
return (False, None, err) return (False, None, err)
@ -43,7 +45,7 @@ def login(server, port, username, password, masque = [[], [], True]):
commande = ["login", [username, password, "bdd", masque]] commande = ["login", [username, password, "bdd", masque]]
sock.send(json.dumps(commande).encode("utf-8")) sock.send(json.dumps(commande).encode("utf-8"))
response = get_response(sock) response = get_response(sock)
retcode = response['retcode'] retcode = response["retcode"]
if retcode == 0: if retcode == 0:
return (True, sock, "") return (True, sock, "")
elif retcode == 5: elif retcode == 5:
@ -60,11 +62,28 @@ def don(sock, montant, id_note, facture):
Faire faire un don à l'id_note Faire faire un don à l'id_note
""" """
try: try:
sock.send(json.dumps(["dons", [[id_note], round(montant*100), "Facture : id=%s, designation=%s" % (facture.id, facture.name())]]).encode("utf-8")) sock.send(
json.dumps(
[
"dons",
[
[id_note],
round(montant * 100),
"Facture : id=%s, designation=%s"
% (facture.id, facture.name()),
],
]
).encode("utf-8")
)
response = get_response(sock) response = get_response(sock)
retcode = response['retcode'] retcode = response["retcode"]
transaction_retcode = response["msg"][0][0] transaction_retcode = response["msg"][0][0]
if 0 < retcode < 100 or 200 <= retcode or 0 < transaction_retcode < 100 or 200 <= transaction_retcode: if (
0 < retcode < 100
or 200 <= retcode
or 0 < transaction_retcode < 100
or 200 <= transaction_retcode
):
return (False, "Transaction échouée. (Solde trop négatif ?)") return (False, "Transaction échouée. (Solde trop négatif ?)")
elif retcode == 0: elif retcode == 0:
return (True, "") return (True, "")

View file

@ -23,8 +23,6 @@ from . import views
urlpatterns = [ urlpatterns = [
url( url(
r'^note_payment/(?P<factureid>[0-9]+)$', r"^note_payment/(?P<factureid>[0-9]+)$", views.note_payment, name="note_payment"
views.note_payment, )
name='note_payment'
),
] ]

View file

@ -4,7 +4,7 @@
# quelques clics. # quelques clics.
# #
# Copyright © 2018 Gabriel Detraz # Copyright © 2018 Gabriel Detraz
# Copyright © 2018 Pierre-Antoine Comby # Copyright © 2018 Pierre-Antoine Comby
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -39,13 +39,11 @@ from cotisations.models import Facture
from cotisations.utils import find_payment_method from cotisations.utils import find_payment_method
from .models import NotePayment from .models import NotePayment
from re2o.views import form from re2o.views import form
from re2o.acl import ( from re2o.acl import can_create, can_edit
can_create,
can_edit
)
from .note import login, don from .note import login, don
from .forms import NoteCredentialForm from .forms import NoteCredentialForm
@login_required @login_required
@can_edit(Facture) @can_edit(Facture)
def note_payment(request, facture, factureid): def note_payment(request, facture, factureid):
@ -58,40 +56,38 @@ def note_payment(request, facture, factureid):
payment_method = find_payment_method(facture.paiement) payment_method = find_payment_method(facture.paiement)
if not payment_method or not isinstance(payment_method, NotePayment): if not payment_method or not isinstance(payment_method, NotePayment):
messages.error(request, _("Unknown error.")) messages.error(request, _("Unknown error."))
return redirect(reverse( return redirect(reverse("users:profil", kwargs={"userid": user.id}))
'users:profil',
kwargs={'userid': user.id}
))
noteform = NoteCredentialForm(request.POST or None) noteform = NoteCredentialForm(request.POST or None)
if noteform.is_valid(): if noteform.is_valid():
pseudo = noteform.cleaned_data['login'] pseudo = noteform.cleaned_data["login"]
password = noteform.cleaned_data['password'] password = noteform.cleaned_data["password"]
result, sock, err = login(payment_method.server, payment_method.port, pseudo, password) result, sock, err = login(
payment_method.server, payment_method.port, pseudo, password
)
if not result: if not result:
messages.error(request, err) messages.error(request, err)
return form( return form(
{'form': noteform, 'amount': facture.prix_total()}, {"form": noteform, "amount": facture.prix_total()},
"cotisations/payment.html", "cotisations/payment.html",
request request,
) )
else: else:
result, err = don(sock, facture.prix_total(), payment_method.id_note, facture) result, err = don(
sock, facture.prix_total(), payment_method.id_note, facture
)
if not result: if not result:
messages.error(request, err) messages.error(request, err)
return form( return form(
{'form': noteform, 'amount': facture.prix_total()}, {"form": noteform, "amount": facture.prix_total()},
"cotisations/payment.html", "cotisations/payment.html",
request request,
) )
facture.valid = True facture.valid = True
facture.save() facture.save()
messages.success(request, _("The payment with note was done.")) messages.success(request, _("The payment with note was done."))
return redirect(reverse( return redirect(reverse("users:profil", kwargs={"userid": user.id}))
'users:profil',
kwargs={'userid': user.id}
))
return form( return form(
{'form': noteform, 'amount': facture.prix_total()}, {"form": noteform, "amount": facture.prix_total()},
"cotisations/payment.html", "cotisations/payment.html",
request request,
) )

View file

@ -22,7 +22,7 @@ from django.conf.urls import include, url
from . import comnpay, cheque, note_kfet from . import comnpay, cheque, note_kfet
urlpatterns = [ urlpatterns = [
url(r'^comnpay/', include(comnpay.urls, namespace='comnpay')), url(r"^comnpay/", include(comnpay.urls, namespace="comnpay")),
url(r'^cheque/', include(cheque.urls, namespace='cheque')), url(r"^cheque/", include(cheque.urls, namespace="cheque")),
url(r'^note_kfet/', include(note_kfet.urls, namespace='note_kfet')), url(r"^note_kfet/", include(note_kfet.urls, namespace="note_kfet")),
] ]

View file

@ -7,19 +7,13 @@ from dateutil.relativedelta import relativedelta
from users.models import User from users.models import User
from .models import Vente, Facture, Cotisation, Paiement from .models import Vente, Facture, Cotisation, Paiement
class VenteModelTests(TestCase): class VenteModelTests(TestCase):
def setUp(self): def setUp(self):
self.user = User.objects.create( self.user = User.objects.create(pseudo="testUser", email="test@example.org")
pseudo="testUser", self.paiement = Paiement.objects.create(moyen="test payment")
email="test@example.org"
)
self.paiement = Paiement.objects.create(
moyen="test payment"
)
self.f = Facture.objects.create( self.f = Facture.objects.create(
user=self.user, user=self.user, paiement=self.paiement, valid=True
paiement=self.paiement,
valid=True
) )
def test_one_day_cotisation(self): def test_one_day_cotisation(self):
@ -39,7 +33,7 @@ class VenteModelTests(TestCase):
self.assertAlmostEqual( self.assertAlmostEqual(
self.user.end_connexion() - date, self.user.end_connexion() - date,
datetime.timedelta(days=1), datetime.timedelta(days=1),
delta=datetime.timedelta(seconds=1) delta=datetime.timedelta(seconds=1),
) )
def test_one_month_cotisation(self): def test_one_month_cotisation(self):
@ -57,11 +51,8 @@ class VenteModelTests(TestCase):
prix=0, prix=0,
) )
delta = relativedelta(self.user.end_connexion(), date) delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds=0 delta.microseconds = 0
self.assertEqual( self.assertEqual(delta, relativedelta(months=1))
delta,
relativedelta(months=1),
)
def test_one_month_and_one_week_cotisation(self): def test_one_month_and_one_week_cotisation(self):
""" """
@ -78,15 +69,10 @@ class VenteModelTests(TestCase):
prix=0, prix=0,
) )
delta = relativedelta(self.user.end_connexion(), date) delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds=0 delta.microseconds = 0
self.assertEqual( self.assertEqual(delta, relativedelta(months=1, days=7))
delta,
relativedelta(months=1, days=7),
)
def tearDown(self): def tearDown(self):
self.f.delete() self.f.delete()
self.user.delete() self.user.delete()
self.paiement.delete() self.paiement.delete()

View file

@ -9,6 +9,7 @@ from django.utils import timezone
from users.models import Adherent from users.models import Adherent
from .models import Vente, Facture, Cotisation, Paiement, Article from .models import Vente, Facture, Cotisation, Paiement, Article
class NewFactureTests(TestCase): class NewFactureTests(TestCase):
def tearDown(self): def tearDown(self):
self.user.facture_set.all().delete() self.user.facture_set.all().delete()
@ -19,51 +20,46 @@ class NewFactureTests(TestCase):
self.article_one_month_and_one_week.delete() self.article_one_month_and_one_week.delete()
def setUp(self): def setUp(self):
self.user = Adherent.objects.create( self.user = Adherent.objects.create(pseudo="testUser", email="test@example.org")
pseudo="testUser", self.user.set_password("plopiplop")
email="test@example.org",
)
self.user.set_password('plopiplop')
self.user.user_permissions.set( self.user.user_permissions.set(
[ [
Permission.objects.get_by_natural_key("add_facture", "cotisations", "Facture"), Permission.objects.get_by_natural_key(
Permission.objects.get_by_natural_key("use_every_payment", "cotisations", "Paiement"), "add_facture", "cotisations", "Facture"
),
Permission.objects.get_by_natural_key(
"use_every_payment", "cotisations", "Paiement"
),
] ]
) )
self.user.save() self.user.save()
self.paiement = Paiement.objects.create( self.paiement = Paiement.objects.create(moyen="test payment")
moyen="test payment",
)
self.article_one_day = Article.objects.create( self.article_one_day = Article.objects.create(
name="One day", name="One day",
prix=0, prix=0,
duration=0, duration=0,
duration_days=1, duration_days=1,
type_cotisation='All', type_cotisation="All",
available_for_everyone=True available_for_everyone=True,
) )
self.article_one_month = Article.objects.create( self.article_one_month = Article.objects.create(
name="One day", name="One day",
prix=0, prix=0,
duration=1, duration=1,
duration_days=0, duration_days=0,
type_cotisation='All', type_cotisation="All",
available_for_everyone=True available_for_everyone=True,
) )
self.article_one_month_and_one_week = Article.objects.create( self.article_one_month_and_one_week = Article.objects.create(
name="One day", name="One day",
prix=0, prix=0,
duration=1, duration=1,
duration_days=7, duration_days=7,
type_cotisation='All', type_cotisation="All",
available_for_everyone=True available_for_everyone=True,
)
self.client.login(
username="testUser",
password="plopiplop"
) )
self.client.login(username="testUser", password="plopiplop")
def test_invoice_with_one_day(self): def test_invoice_with_one_day(self):
data = { data = {
@ -76,19 +72,15 @@ class NewFactureTests(TestCase):
"form-0-quantity": 1, "form-0-quantity": 1,
} }
date = timezone.now() date = timezone.now()
response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) response = self.client.post(
self.assertEqual( reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data
response.status_code,
302
)
self.assertEqual(
response.url,
"/users/profil/%d"%self.user.pk
) )
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/users/profil/%d" % self.user.pk)
self.assertAlmostEqual( self.assertAlmostEqual(
self.user.end_connexion() - date, self.user.end_connexion() - date,
datetime.timedelta(days=1), datetime.timedelta(days=1),
delta=datetime.timedelta(seconds=1) delta=datetime.timedelta(seconds=1),
) )
def test_invoice_with_one_month(self): def test_invoice_with_one_month(self):
@ -102,21 +94,14 @@ class NewFactureTests(TestCase):
"form-0-quantity": 1, "form-0-quantity": 1,
} }
date = timezone.now() date = timezone.now()
response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) response = self.client.post(
self.assertEqual( reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data
response.status_code,
302
)
self.assertEqual(
response.url,
"/users/profil/%d"%self.user.pk
) )
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/users/profil/%d" % self.user.pk)
delta = relativedelta(self.user.end_connexion(), date) delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds=0 delta.microseconds = 0
self.assertEqual( self.assertEqual(delta, relativedelta(months=1))
delta,
relativedelta(months=1),
)
def test_invoice_with_one_month_and_one_week(self): def test_invoice_with_one_month_and_one_week(self):
data = { data = {
@ -131,23 +116,15 @@ class NewFactureTests(TestCase):
"form-1-quantity": 1, "form-1-quantity": 1,
} }
date = timezone.now() date = timezone.now()
response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) response = self.client.post(
self.assertEqual( reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data
response.status_code,
302
)
self.assertEqual(
response.url,
"/users/profil/%d"%self.user.pk
) )
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/users/profil/%d" % self.user.pk)
invoice = self.user.facture_set.first() invoice = self.user.facture_set.first()
delta = relativedelta(self.user.end_connexion(), date) delta = relativedelta(self.user.end_connexion(), date)
delta.microseconds=0 delta.microseconds = 0
self.assertEqual( self.assertEqual(delta, relativedelta(months=1, days=7))
delta,
relativedelta(months=1, days=7),
)
def test_several_articles_creates_several_purchases(self): def test_several_articles_creates_several_purchases(self):
data = { data = {
@ -161,6 +138,8 @@ class NewFactureTests(TestCase):
"form-1-article": 2, "form-1-article": 2,
"form-1-quantity": 1, "form-1-quantity": 1,
} }
response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) response = self.client.post(
reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data
)
f = self.user.facture_set.first() f = self.user.facture_set.first()
self.assertEqual(f.vente_set.count(), 2) self.assertEqual(f.vente_set.count(), 2)

View file

@ -42,9 +42,9 @@ from re2o.mixins import AclMixin, RevMixin
from preferences.models import CotisationsOption from preferences.models import CotisationsOption
TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-') TEMP_PREFIX = getattr(settings, "TEX_TEMP_PREFIX", "render_tex-")
CACHE_PREFIX = getattr(settings, 'TEX_CACHE_PREFIX', 'render-tex') CACHE_PREFIX = getattr(settings, "TEX_CACHE_PREFIX", "render-tex")
CACHE_TIMEOUT = getattr(settings, 'TEX_CACHE_TIMEOUT', 86400) # 1 day CACHE_TIMEOUT = getattr(settings, "TEX_CACHE_TIMEOUT", 86400) # 1 day
def render_invoice(_request, ctx={}): def render_invoice(_request, ctx={}):
@ -53,20 +53,20 @@ def render_invoice(_request, ctx={}):
date, the user, the articles, the prices, ... date, the user, the articles, the prices, ...
""" """
options, _ = CotisationsOption.objects.get_or_create() options, _ = CotisationsOption.objects.get_or_create()
is_estimate = ctx.get('is_estimate', False) is_estimate = ctx.get("is_estimate", False)
filename = '_'.join([ filename = "_".join(
'cost_estimate' if is_estimate else 'invoice', [
slugify(ctx.get('asso_name', "")), "cost_estimate" if is_estimate else "invoice",
slugify(ctx.get('recipient_name', "")), slugify(ctx.get("asso_name", "")),
str(ctx.get('DATE', datetime.now()).year), slugify(ctx.get("recipient_name", "")),
str(ctx.get('DATE', datetime.now()).month), str(ctx.get("DATE", datetime.now()).year),
str(ctx.get('DATE', datetime.now()).day), str(ctx.get("DATE", datetime.now()).month),
]) str(ctx.get("DATE", datetime.now()).day),
templatename = options.invoice_template.template.name.split('/')[-1] ]
r = render_tex(_request, templatename, ctx)
r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
name=filename
) )
templatename = options.invoice_template.template.name.split("/")[-1]
r = render_tex(_request, templatename, ctx)
r["Content-Disposition"] = 'attachment; filename="{name}.pdf"'.format(name=filename)
return r return r
@ -75,20 +75,20 @@ def render_voucher(_request, ctx={}):
Render a subscribtion voucher. Render a subscribtion voucher.
""" """
options, _ = CotisationsOption.objects.get_or_create() options, _ = CotisationsOption.objects.get_or_create()
filename = '_'.join([ filename = "_".join(
'voucher', [
slugify(ctx.get('asso_name', "")), "voucher",
slugify(ctx.get('firstname', "")), slugify(ctx.get("asso_name", "")),
slugify(ctx.get('lastname', "")), slugify(ctx.get("firstname", "")),
str(ctx.get('date_begin', datetime.now()).year), slugify(ctx.get("lastname", "")),
str(ctx.get('date_begin', datetime.now()).month), str(ctx.get("date_begin", datetime.now()).year),
str(ctx.get('date_begin', datetime.now()).day), str(ctx.get("date_begin", datetime.now()).month),
]) str(ctx.get("date_begin", datetime.now()).day),
templatename = options.voucher_template.template.name.split('/')[-1] ]
r = render_tex(_request, templatename, ctx)
r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
name=filename
) )
templatename = options.voucher_template.template.name.split("/")[-1]
r = render_tex(_request, templatename, ctx)
r["Content-Disposition"] = 'attachment; filename="{name}.pdf"'.format(name=filename)
return r return r
@ -106,18 +106,18 @@ def create_pdf(template, ctx={}):
""" """
context = ctx context = ctx
template = get_template(template) template = get_template(template)
rendered_tpl = template.render(context).encode('utf-8') rendered_tpl = template.render(context).encode("utf-8")
with tempfile.TemporaryDirectory() as tempdir: with tempfile.TemporaryDirectory() as tempdir:
for _ in range(2): for _ in range(2):
with open("/var/www/re2o/out.log", "w") as f: with open("/var/www/re2o/out.log", "w") as f:
process = Popen( process = Popen(
['pdflatex', '-output-directory', tempdir], ["pdflatex", "-output-directory", tempdir],
stdin=PIPE, stdin=PIPE,
stdout=f,#PIPE, stdout=f, # PIPE,
) )
process.communicate(rendered_tpl) process.communicate(rendered_tpl)
with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f: with open(os.path.join(tempdir, "texput.pdf"), "rb") as f:
pdf = f.read() pdf = f.read()
return pdf return pdf
@ -127,10 +127,7 @@ def escape_chars(string):
"""Escape the '%' and the '' signs to avoid messing with LaTeX""" """Escape the '%' and the '' signs to avoid messing with LaTeX"""
if not isinstance(string, str): if not isinstance(string, str):
return string return string
mapping = ( mapping = (("", r"\euro"), ("%", r"\%"))
('', r'\euro'),
('%', r'\%'),
)
r = str(string) r = str(string)
for k, v in mapping: for k, v in mapping:
r = r.replace(k, v) r = r.replace(k, v)
@ -152,6 +149,6 @@ def render_tex(_request, template, ctx={}):
An HttpResponse with type `application/pdf` containing the PDF file. An HttpResponse with type `application/pdf` containing the PDF file.
""" """
pdf = create_pdf(template, ctx) pdf = create_pdf(template, ctx)
r = HttpResponse(content_type='application/pdf') r = HttpResponse(content_type="application/pdf")
r.write(pdf) r.write(pdf)
return r return r

View file

@ -31,155 +31,77 @@ from . import views
from . import payment_methods from . import payment_methods
urlpatterns = [ urlpatterns = [
url(r"^new_facture/(?P<userid>[0-9]+)$", views.new_facture, name="new-facture"),
url( url(
r'^new_facture/(?P<userid>[0-9]+)$', r"^edit_facture/(?P<factureid>[0-9]+)$", views.edit_facture, name="edit-facture"
views.new_facture, ),
name='new-facture' url(r"^del_facture/(?P<factureid>[0-9]+)$", views.del_facture, name="del-facture"),
url(r"^facture_pdf/(?P<factureid>[0-9]+)$", views.facture_pdf, name="facture-pdf"),
url(r"^voucher_pdf/(?P<factureid>[0-9]+)$", views.voucher_pdf, name="voucher-pdf"),
url(r"^new_cost_estimate/$", views.new_cost_estimate, name="new-cost-estimate"),
url(
r"^index_cost_estimate/$", views.index_cost_estimate, name="index-cost-estimate"
), ),
url( url(
r'^edit_facture/(?P<factureid>[0-9]+)$', r"^cost_estimate_pdf/(?P<costestimateid>[0-9]+)$",
views.edit_facture,
name='edit-facture'
),
url(
r'^del_facture/(?P<factureid>[0-9]+)$',
views.del_facture,
name='del-facture'
),
url(
r'^facture_pdf/(?P<factureid>[0-9]+)$',
views.facture_pdf,
name='facture-pdf'
),
url(
r'^voucher_pdf/(?P<factureid>[0-9]+)$',
views.voucher_pdf,
name='voucher-pdf'
),
url(
r'^new_cost_estimate/$',
views.new_cost_estimate,
name='new-cost-estimate'
),
url(
r'^index_cost_estimate/$',
views.index_cost_estimate,
name='index-cost-estimate'
),
url(
r'^cost_estimate_pdf/(?P<costestimateid>[0-9]+)$',
views.cost_estimate_pdf, views.cost_estimate_pdf,
name='cost-estimate-pdf', name="cost-estimate-pdf",
), ),
url( url(
r'^index_custom_invoice/$', r"^index_custom_invoice/$",
views.index_custom_invoice, views.index_custom_invoice,
name='index-custom-invoice' name="index-custom-invoice",
), ),
url( url(
r'^edit_cost_estimate/(?P<costestimateid>[0-9]+)$', r"^edit_cost_estimate/(?P<costestimateid>[0-9]+)$",
views.edit_cost_estimate, views.edit_cost_estimate,
name='edit-cost-estimate' name="edit-cost-estimate",
), ),
url( url(
r'^cost_estimate_to_invoice/(?P<costestimateid>[0-9]+)$', r"^cost_estimate_to_invoice/(?P<costestimateid>[0-9]+)$",
views.cost_estimate_to_invoice, views.cost_estimate_to_invoice,
name='cost-estimate-to-invoice' name="cost-estimate-to-invoice",
), ),
url( url(
r'^del_cost_estimate/(?P<costestimateid>[0-9]+)$', r"^del_cost_estimate/(?P<costestimateid>[0-9]+)$",
views.del_cost_estimate, views.del_cost_estimate,
name='del-cost-estimate' name="del-cost-estimate",
), ),
url(r"^new_custom_invoice/$", views.new_custom_invoice, name="new-custom-invoice"),
url( url(
r'^new_custom_invoice/$', r"^edit_custom_invoice/(?P<custominvoiceid>[0-9]+)$",
views.new_custom_invoice,
name='new-custom-invoice'
),
url(
r'^edit_custom_invoice/(?P<custominvoiceid>[0-9]+)$',
views.edit_custom_invoice, views.edit_custom_invoice,
name='edit-custom-invoice' name="edit-custom-invoice",
), ),
url( url(
r'^custom_invoice_pdf/(?P<custominvoiceid>[0-9]+)$', r"^custom_invoice_pdf/(?P<custominvoiceid>[0-9]+)$",
views.custom_invoice_pdf, views.custom_invoice_pdf,
name='custom-invoice-pdf', name="custom-invoice-pdf",
), ),
url( url(
r'^del_custom_invoice/(?P<custominvoiceid>[0-9]+)$', r"^del_custom_invoice/(?P<custominvoiceid>[0-9]+)$",
views.del_custom_invoice, views.del_custom_invoice,
name='del-custom-invoice' name="del-custom-invoice",
), ),
url(r"^credit_solde/(?P<userid>[0-9]+)$", views.credit_solde, name="credit-solde"),
url(r"^add_article/$", views.add_article, name="add-article"),
url( url(
r'^credit_solde/(?P<userid>[0-9]+)$', r"^edit_article/(?P<articleid>[0-9]+)$", views.edit_article, name="edit-article"
views.credit_solde,
name='credit-solde'
), ),
url(r"^del_article/$", views.del_article, name="del-article"),
url(r"^add_paiement/$", views.add_paiement, name="add-paiement"),
url( url(
r'^add_article/$', r"^edit_paiement/(?P<paiementid>[0-9]+)$",
views.add_article,
name='add-article'
),
url(
r'^edit_article/(?P<articleid>[0-9]+)$',
views.edit_article,
name='edit-article'
),
url(
r'^del_article/$',
views.del_article,
name='del-article'
),
url(
r'^add_paiement/$',
views.add_paiement,
name='add-paiement'
),
url(
r'^edit_paiement/(?P<paiementid>[0-9]+)$',
views.edit_paiement, views.edit_paiement,
name='edit-paiement' name="edit-paiement",
), ),
url( url(r"^del_paiement/$", views.del_paiement, name="del-paiement"),
r'^del_paiement/$', url(r"^add_banque/$", views.add_banque, name="add-banque"),
views.del_paiement, url(r"^edit_banque/(?P<banqueid>[0-9]+)$", views.edit_banque, name="edit-banque"),
name='del-paiement' url(r"^del_banque/$", views.del_banque, name="del-banque"),
), url(r"^index_article/$", views.index_article, name="index-article"),
url( url(r"^index_banque/$", views.index_banque, name="index-banque"),
r'^add_banque/$', url(r"^index_paiement/$", views.index_paiement, name="index-paiement"),
views.add_banque, url(r"^control/$", views.control, name="control"),
name='add-banque' url(r"^$", views.index, name="index"),
),
url(
r'^edit_banque/(?P<banqueid>[0-9]+)$',
views.edit_banque,
name='edit-banque'
),
url(
r'^del_banque/$',
views.del_banque,
name='del-banque'
),
url(
r'^index_article/$',
views.index_article,
name='index-article'
),
url(
r'^index_banque/$',
views.index_banque,
name='index-banque'
),
url(
r'^index_paiement/$',
views.index_paiement,
name='index-paiement'
),
url(
r'^control/$',
views.control,
name='control'
),
url(r'^$', views.index, name='index'),
] + payment_methods.urls.urlpatterns ] + payment_methods.urls.urlpatterns

View file

@ -25,9 +25,7 @@ from django.template.loader import get_template
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from .tex import create_pdf from .tex import create_pdf
from preferences.models import ( from preferences.models import AssoOption, GeneralOption, CotisationsOption, Mandate
AssoOption, GeneralOption, CotisationsOption, Mandate
)
from re2o.settings import LOGO_PATH from re2o.settings import LOGO_PATH
from re2o import settings from re2o import settings
@ -35,6 +33,7 @@ from re2o import settings
def find_payment_method(payment): def find_payment_method(payment):
"""Finds the payment method associated to the payment if it exists.""" """Finds the payment method associated to the payment if it exists."""
from cotisations.payment_methods import PAYMENT_METHODS from cotisations.payment_methods import PAYMENT_METHODS
for method in PAYMENT_METHODS: for method in PAYMENT_METHODS:
try: try:
o = method.PaymentMethod.objects.get(payment=payment) o = method.PaymentMethod.objects.get(payment=payment)
@ -48,51 +47,47 @@ def send_mail_invoice(invoice):
"""Creates the pdf of the invoice and sends it by email to the client""" """Creates the pdf of the invoice and sends it by email to the client"""
purchases_info = [] purchases_info = []
for purchase in invoice.vente_set.all(): for purchase in invoice.vente_set.all():
purchases_info.append({ purchases_info.append(
'name': purchase.name, {
'price': purchase.prix, "name": purchase.name,
'quantity': purchase.number, "price": purchase.prix,
'total_price': purchase.prix_total "quantity": purchase.number,
}) "total_price": purchase.prix_total,
}
)
ctx = { ctx = {
'paid': True, "paid": True,
'fid': invoice.id, "fid": invoice.id,
'DATE': invoice.date, "DATE": invoice.date,
'recipient_name': "{} {}".format( "recipient_name": "{} {}".format(invoice.user.name, invoice.user.surname),
invoice.user.name, "address": invoice.user.room,
invoice.user.surname "article": purchases_info,
), "total": invoice.prix_total(),
'address': invoice.user.room, "asso_name": AssoOption.get_cached_value("name"),
'article': purchases_info, "line1": AssoOption.get_cached_value("adresse1"),
'total': invoice.prix_total(), "line2": AssoOption.get_cached_value("adresse2"),
'asso_name': AssoOption.get_cached_value('name'), "siret": AssoOption.get_cached_value("siret"),
'line1': AssoOption.get_cached_value('adresse1'), "email": AssoOption.get_cached_value("contact"),
'line2': AssoOption.get_cached_value('adresse2'), "phone": AssoOption.get_cached_value("telephone"),
'siret': AssoOption.get_cached_value('siret'), "tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH),
'email': AssoOption.get_cached_value('contact'),
'phone': AssoOption.get_cached_value('telephone'),
'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)
} }
pdf = create_pdf('cotisations/factures.tex', ctx) pdf = create_pdf("cotisations/factures.tex", ctx)
template = get_template('cotisations/email_invoice') template = get_template("cotisations/email_invoice")
ctx = { ctx = {
'name': "{} {}".format( "name": "{} {}".format(invoice.user.name, invoice.user.surname),
invoice.user.name, "contact_mail": AssoOption.get_cached_value("contact"),
invoice.user.surname "asso_name": AssoOption.get_cached_value("name"),
),
'contact_mail': AssoOption.get_cached_value('contact'),
'asso_name': AssoOption.get_cached_value('name')
} }
mail = EmailMessage( mail = EmailMessage(
'Votre facture / Your invoice', "Votre facture / Your invoice",
template.render(ctx), template.render(ctx),
GeneralOption.get_cached_value('email_from'), GeneralOption.get_cached_value("email_from"),
[invoice.user.get_mail], [invoice.user.get_mail],
attachments=[('invoice.pdf', pdf, 'application/pdf')] attachments=[("invoice.pdf", pdf, "application/pdf")],
) )
mail.send() mail.send()
@ -101,34 +96,33 @@ def send_mail_voucher(invoice):
"""Creates a voucher from an invoice and sends it by email to the client""" """Creates a voucher from an invoice and sends it by email to the client"""
president = Mandate.get_mandate(invoice.date).president president = Mandate.get_mandate(invoice.date).president
ctx = { ctx = {
'asso_name': AssoOption.get_cached_value('name'), "asso_name": AssoOption.get_cached_value("name"),
'pres_name': ' '.join([president.name, president.surname]), "pres_name": " ".join([president.name, president.surname]),
'firstname': invoice.user.name, "firstname": invoice.user.name,
'lastname': invoice.user.surname, "lastname": invoice.user.surname,
'email': invoice.user.email, "email": invoice.user.email,
'phone': invoice.user.telephone, "phone": invoice.user.telephone,
'date_end': invoice.get_subscription().latest('date_end').date_end, "date_end": invoice.get_subscription().latest("date_end").date_end,
'date_begin': invoice.get_subscription().earliest('date_start').date_start "date_begin": invoice.get_subscription().earliest("date_start").date_start,
} }
templatename = CotisationsOption.get_cached_value('voucher_template').template.name.split('/')[-1] templatename = CotisationsOption.get_cached_value(
"voucher_template"
).template.name.split("/")[-1]
pdf = create_pdf(templatename, ctx) pdf = create_pdf(templatename, ctx)
template = get_template('cotisations/email_subscription_accepted') template = get_template("cotisations/email_subscription_accepted")
ctx = { ctx = {
'name': "{} {}".format( "name": "{} {}".format(invoice.user.name, invoice.user.surname),
invoice.user.name, "asso_email": AssoOption.get_cached_value("contact"),
invoice.user.surname "asso_name": AssoOption.get_cached_value("name"),
), "date_end": invoice.get_subscription().latest("date_end").date_end,
'asso_email': AssoOption.get_cached_value('contact'),
'asso_name': AssoOption.get_cached_value('name'),
'date_end': invoice.get_subscription().latest('date_end').date_end,
} }
mail = EmailMessage( mail = EmailMessage(
'Votre reçu / Your voucher', "Votre reçu / Your voucher",
template.render(ctx), template.render(ctx),
GeneralOption.get_cached_value('email_from'), GeneralOption.get_cached_value("email_from"),
[invoice.user.get_mail], [invoice.user.get_mail],
attachments=[('voucher.pdf', pdf, 'application/pdf')] attachments=[("voucher.pdf", pdf, "application/pdf")],
) )
mail.send() mail.send()

View file

@ -12,11 +12,9 @@ def check_no_balance(is_balance):
ValidationError: if such a Paiement exists. ValidationError: if such a Paiement exists.
""" """
from .models import Paiement from .models import Paiement
if not is_balance: if not is_balance:
return return
p = Paiement.objects.filter(is_balance=True) p = Paiement.objects.filter(is_balance=True)
if len(p) > 0: if len(p) > 0:
raise ValidationError( raise ValidationError(_("There is already a payment method for user balance."))
_("There is already a payment method for user balance.")
)

File diff suppressed because it is too large Load diff

View file

@ -62,7 +62,7 @@ from preferences.models import RadiusOption
#: Serveur radius de test (pas la prod) #: Serveur radius de test (pas la prod)
TEST_SERVER = bool(os.getenv('DBG_FREERADIUS', False)) TEST_SERVER = bool(os.getenv("DBG_FREERADIUS", False))
# Logging # Logging
@ -77,13 +77,13 @@ class RadiusdHandler(logging.Handler):
rad_sig = radiusd.L_INFO rad_sig = radiusd.L_INFO
else: else:
rad_sig = radiusd.L_DBG rad_sig = radiusd.L_DBG
radiusd.radlog(rad_sig, record.msg.encode('utf-8')) radiusd.radlog(rad_sig, record.msg.encode("utf-8"))
# Initialisation d'un logger (pour logguer unifié) # Initialisation d'un logger (pour logguer unifié)
logger = logging.getLogger('auth.py') logger = logging.getLogger("auth.py")
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s') formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s")
handler = RadiusdHandler() handler = RadiusdHandler()
handler.setFormatter(formatter) handler.setFormatter(formatter)
logger.addHandler(handler) logger.addHandler(handler)
@ -111,17 +111,16 @@ def radius_event(fun):
for (key, value) in auth_data or []: for (key, value) in auth_data or []:
# Beware: les valeurs scalaires sont entre guillemets # Beware: les valeurs scalaires sont entre guillemets
# Ex: Calling-Station-Id: "une_adresse_mac" # Ex: Calling-Station-Id: "une_adresse_mac"
data[key] = value.replace('"', '') data[key] = value.replace('"', "")
try: try:
# TODO s'assurer ici que les tuples renvoyés sont bien des # TODO s'assurer ici que les tuples renvoyés sont bien des
# (str,str) : rlm_python ne digère PAS les unicodes # (str,str) : rlm_python ne digère PAS les unicodes
return fun(data) return fun(data)
except Exception as err: except Exception as err:
exc_type, exc_instance, exc_traceback = sys.exc_info() exc_type, exc_instance, exc_traceback = sys.exc_info()
formatted_traceback = ''.join(traceback.format_tb( formatted_traceback = "".join(traceback.format_tb(exc_traceback))
exc_traceback)) logger.error("Failed %r on data %r" % (err, auth_data))
logger.error('Failed %r on data %r' % (err, auth_data)) logger.error("Function %r, Traceback : %r" % (fun, formatted_traceback))
logger.error('Function %r, Traceback : %r' % (fun, formatted_traceback))
return radiusd.RLM_MODULE_FAIL return radiusd.RLM_MODULE_FAIL
return new_f return new_f
@ -131,9 +130,9 @@ def radius_event(fun):
def instantiate(*_): def instantiate(*_):
"""Utile pour initialiser les connexions ldap une première fois (otherwise, """Utile pour initialiser les connexions ldap une première fois (otherwise,
do nothing)""" do nothing)"""
logger.info('Instantiation') logger.info("Instantiation")
if TEST_SERVER: if TEST_SERVER:
logger.info(u'DBG_FREERADIUS is enabled') logger.info(u"DBG_FREERADIUS is enabled")
@radius_event @radius_event
@ -146,23 +145,19 @@ def authorize(data):
accept en authorize accept en authorize
""" """
# Pour les requetes proxifiees, on split # Pour les requetes proxifiees, on split
nas = data.get('NAS-IP-Address', data.get('NAS-Identifier', None)) nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None))
nas_instance = find_nas_from_request(nas) nas_instance = find_nas_from_request(nas)
# Toutes les reuquètes non proxifiées # Toutes les reuquètes non proxifiées
nas_type = None nas_type = None
if nas_instance: if nas_instance:
nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first()
if not nas_type or nas_type.port_access_mode == '802.1X': if not nas_type or nas_type.port_access_mode == "802.1X":
user = data.get('User-Name', '').decode('utf-8', errors='replace') user = data.get("User-Name", "").decode("utf-8", errors="replace")
user = user.split('@', 1)[0] user = user.split("@", 1)[0]
mac = data.get('Calling-Station-Id', '') mac = data.get("Calling-Station-Id", "")
result, log, password = check_user_machine_and_register( result, log, password = check_user_machine_and_register(nas_type, user, mac)
nas_type, logger.info(log.encode("utf-8"))
user, logger.info(user.encode("utf-8"))
mac
)
logger.info(log.encode('utf-8'))
logger.info(user.encode('utf-8'))
if not result: if not result:
return radiusd.RLM_MODULE_REJECT return radiusd.RLM_MODULE_REJECT
@ -170,19 +165,11 @@ def authorize(data):
return ( return (
radiusd.RLM_MODULE_UPDATED, radiusd.RLM_MODULE_UPDATED,
(), (),
( ((str("NT-Password"), str(password)),),
(str("NT-Password"), str(password)),
),
) )
else: else:
return ( return (radiusd.RLM_MODULE_UPDATED, (), (("Auth-Type", "Accept"),))
radiusd.RLM_MODULE_UPDATED,
(),
(
("Auth-Type", "Accept"),
),
)
@radius_event @radius_event
@ -190,52 +177,49 @@ def post_auth(data):
""" Function called after the user is authenticated """ Function called after the user is authenticated
""" """
nas = data.get('NAS-IP-Address', data.get('NAS-Identifier', None)) nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None))
nas_instance = find_nas_from_request(nas) nas_instance = find_nas_from_request(nas)
# Toutes les reuquètes non proxifiées # Toutes les reuquètes non proxifiées
if not nas_instance: if not nas_instance:
logger.info(u"Requete proxifiee, nas inconnu".encode('utf-8')) logger.info(u"Requete proxifiee, nas inconnu".encode("utf-8"))
return radiusd.RLM_MODULE_OK return radiusd.RLM_MODULE_OK
nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first()
if not nas_type: if not nas_type:
logger.info( logger.info(u"Type de nas non enregistre dans la bdd!".encode("utf-8"))
u"Type de nas non enregistre dans la bdd!".encode('utf-8')
)
return radiusd.RLM_MODULE_OK return radiusd.RLM_MODULE_OK
mac = data.get('Calling-Station-Id', None) mac = data.get("Calling-Station-Id", None)
# Switch et bornes héritent de machine et peuvent avoir plusieurs # Switch et bornes héritent de machine et peuvent avoir plusieurs
# interfaces filles # interfaces filles
nas_machine = nas_instance.machine nas_machine = nas_instance.machine
# Si il s'agit d'un switch # Si il s'agit d'un switch
if hasattr(nas_machine, 'switch'): if hasattr(nas_machine, "switch"):
port = data.get('NAS-Port-Id', data.get('NAS-Port', None)) port = data.get("NAS-Port-Id", data.get("NAS-Port", None))
# Pour les infrastructures possédant des switchs Juniper : # Pour les infrastructures possédant des switchs Juniper :
# On vérifie si le switch fait partie d'un stack Juniper # On vérifie si le switch fait partie d'un stack Juniper
instance_stack = nas_machine.switch.stack instance_stack = nas_machine.switch.stack
if instance_stack: if instance_stack:
# Si c'est le cas, on resélectionne le bon switch dans la stack # Si c'est le cas, on resélectionne le bon switch dans la stack
id_stack_member = port.split("-")[1].split('/')[0] id_stack_member = port.split("-")[1].split("/")[0]
nas_machine = (Switch.objects nas_machine = (
.filter(stack=instance_stack) Switch.objects.filter(stack=instance_stack)
.filter(stack_member_id=id_stack_member) .filter(stack_member_id=id_stack_member)
.prefetch_related( .prefetch_related("interface_set__domain__extension")
'interface_set__domain__extension' .first()
) )
.first())
# On récupère le numéro du port sur l'output de freeradius. # On récupère le numéro du port sur l'output de freeradius.
# La ligne suivante fonctionne pour cisco, HP et Juniper # La ligne suivante fonctionne pour cisco, HP et Juniper
port = port.split(".")[0].split('/')[-1][-2:] port = port.split(".")[0].split("/")[-1][-2:]
out = decide_vlan_switch(nas_machine, nas_type, port, mac) out = decide_vlan_switch(nas_machine, nas_type, port, mac)
sw_name, room, reason, vlan_id, decision, attributes = out sw_name, room, reason, vlan_id, decision, attributes = out
if decision: if decision:
log_message = '(fil) %s -> %s [%s%s]' % ( log_message = "(fil) %s -> %s [%s%s]" % (
sw_name + u":" + port + u"/" + str(room), sw_name + u":" + port + u"/" + str(room),
mac, mac,
vlan_id, vlan_id,
(reason and u': ' + reason).encode('utf-8') (reason and u": " + reason).encode("utf-8"),
) )
logger.info(log_message) logger.info(log_message)
@ -245,23 +229,20 @@ def post_auth(data):
( (
("Tunnel-Type", "VLAN"), ("Tunnel-Type", "VLAN"),
("Tunnel-Medium-Type", "IEEE-802"), ("Tunnel-Medium-Type", "IEEE-802"),
("Tunnel-Private-Group-Id", '%d' % int(vlan_id)), ("Tunnel-Private-Group-Id", "%d" % int(vlan_id)),
) + tuple(attributes), )
() + tuple(attributes),
(),
) )
else: else:
log_message = '(fil) %s -> %s [Reject:%s]' % ( log_message = "(fil) %s -> %s [Reject:%s]" % (
sw_name + u":" + port + u"/" + str(room), sw_name + u":" + port + u"/" + str(room),
mac, mac,
(reason and u': ' + reason).encode('utf-8') (reason and u": " + reason).encode("utf-8"),
) )
logger.info(log_message) logger.info(log_message)
return ( return (radiusd.RLM_MODULE_REJECT, tuple(attributes), ())
radiusd.RLM_MODULE_REJECT,
tuple(attributes),
()
)
else: else:
return radiusd.RLM_MODULE_OK return radiusd.RLM_MODULE_OK
@ -282,13 +263,14 @@ def detach(_=None):
def find_nas_from_request(nas_id): def find_nas_from_request(nas_id):
""" Get the nas object from its ID """ """ Get the nas object from its ID """
nas = (Interface.objects nas = (
.filter( Interface.objects.filter(
Q(domain=Domain.objects.filter(name=nas_id)) | Q(domain=Domain.objects.filter(name=nas_id))
Q(ipv4=IpList.objects.filter(ipv4=nas_id)) | Q(ipv4=IpList.objects.filter(ipv4=nas_id))
) )
.select_related('machine_type') .select_related("machine_type")
.select_related('machine__switch__stack')) .select_related("machine__switch__stack")
)
return nas.first() return nas.first()
@ -300,17 +282,18 @@ def check_user_machine_and_register(nas_type, username, mac_address):
interface = Interface.objects.filter(mac_address=mac_address).first() interface = Interface.objects.filter(mac_address=mac_address).first()
user = User.objects.filter(pseudo__iexact=username).first() user = User.objects.filter(pseudo__iexact=username).first()
if not user: if not user:
return (False, u"User inconnu", '') return (False, u"User inconnu", "")
if not user.has_access(): if not user.has_access():
return (False, u"Adherent non cotisant", '') return (False, u"Adherent non cotisant", "")
if interface: if interface:
if interface.machine.user != user: if interface.machine.user != user:
return (False, return (
u"Machine enregistree sur le compte d'un autre " False,
"user...", u"Machine enregistree sur le compte d'un autre " "user...",
'') "",
)
elif not interface.is_active: elif not interface.is_active:
return (False, u"Machine desactivee", '') return (False, u"Machine desactivee", "")
elif not interface.ipv4: elif not interface.ipv4:
interface.assign_ipv4() interface.assign_ipv4()
return (True, u"Ok, Reassignation de l'ipv4", user.pwd_ntlm) return (True, u"Ok, Reassignation de l'ipv4", user.pwd_ntlm)
@ -320,19 +303,16 @@ def check_user_machine_and_register(nas_type, username, mac_address):
if nas_type.autocapture_mac: if nas_type.autocapture_mac:
result, reason = user.autoregister_machine(mac_address, nas_type) result, reason = user.autoregister_machine(mac_address, nas_type)
if result: if result:
return (True, return (True, u"Access Ok, Capture de la mac...", user.pwd_ntlm)
u'Access Ok, Capture de la mac...',
user.pwd_ntlm)
else: else:
return (False, u'Erreur dans le register mac %s' % reason, '') return (False, u"Erreur dans le register mac %s" % reason, "")
else: else:
return (False, u'Machine inconnue', '') return (False, u"Machine inconnue", "")
else: else:
return (False, u"Machine inconnue", '') return (False, u"Machine inconnue", "")
def decide_vlan_switch(nas_machine, nas_type, port_number, def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address):
mac_address):
"""Fonction de placement vlan pour un switch en radius filaire auth par """Fonction de placement vlan pour un switch en radius filaire auth par
mac. mac.
Plusieurs modes : Plusieurs modes :
@ -373,32 +353,27 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
- Attributs supplémentaires (attribut:str, operateur:str, valeur:str) - Attributs supplémentaires (attribut:str, operateur:str, valeur:str)
""" """
attributes_kwargs = { attributes_kwargs = {
'client_mac' : str(mac_address), "client_mac": str(mac_address),
'switch_port' : str(port_number), "switch_port": str(port_number),
} }
# Get port from switch and port number # Get port from switch and port number
extra_log = "" extra_log = ""
# Si le NAS est inconnu, on place sur le vlan defaut # Si le NAS est inconnu, on place sur le vlan defaut
if not nas_machine: if not nas_machine:
return ( return (
'?', "?",
u'Chambre inconnue', u"Chambre inconnue",
u'Nas inconnu', u"Nas inconnu",
RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, RadiusOption.get_cached_value("vlan_decision_ok").vlan_id,
True, True,
RadiusOption.get_attributes('ok_attributes', attributes_kwargs) RadiusOption.get_attributes("ok_attributes", attributes_kwargs),
) )
sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) sw_name = str(getattr(nas_machine, "short_name", str(nas_machine)))
switch = Switch.objects.filter(machine_ptr=nas_machine).first() switch = Switch.objects.filter(machine_ptr=nas_machine).first()
attributes_kwargs['switch_ip'] = str(switch.ipv4) attributes_kwargs["switch_ip"] = str(switch.ipv4)
port = (Port.objects port = Port.objects.filter(switch=switch, port=port_number).first()
.filter(
switch=switch,
port=port_number
)
.first())
# Si le port est inconnu, on place sur le vlan defaut # Si le port est inconnu, on place sur le vlan defaut
# Aucune information particulière ne permet de déterminer quelle # Aucune information particulière ne permet de déterminer quelle
@ -407,10 +382,12 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
return ( return (
sw_name, sw_name,
"Port inconnu", "Port inconnu",
u'Port inconnu', u"Port inconnu",
getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT, RadiusOption.get_cached_value("unknown_port_vlan"), "vlan_id", None
RadiusOption.get_attributes('unknown_port_attributes', attributes_kwargs) ),
RadiusOption.get_cached_value("unknown_port") != RadiusOption.REJECT,
RadiusOption.get_attributes("unknown_port_attributes", attributes_kwargs),
) )
# On récupère le profil du port # On récupère le profil du port
@ -423,35 +400,36 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
extra_log = u"Force sur vlan " + str(DECISION_VLAN) extra_log = u"Force sur vlan " + str(DECISION_VLAN)
attributes = () attributes = ()
else: else:
DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok').vlan_id DECISION_VLAN = RadiusOption.get_cached_value("vlan_decision_ok").vlan_id
attributes = RadiusOption.get_attributes('ok_attributes', attributes_kwargs) attributes = RadiusOption.get_attributes("ok_attributes", attributes_kwargs)
# Si le port est désactivé, on rejette la connexion # Si le port est désactivé, on rejette la connexion
if not port.state: if not port.state:
return (sw_name, port.room, u'Port desactive', None, False, ()) return (sw_name, port.room, u"Port desactive", None, False, ())
# Si radius est désactivé, on laisse passer # Si radius est désactivé, on laisse passer
if port_profile.radius_type == 'NO': if port_profile.radius_type == "NO":
return (sw_name, return (
"", sw_name,
u"Pas d'authentification sur ce port" + extra_log, "",
DECISION_VLAN, u"Pas d'authentification sur ce port" + extra_log,
True, DECISION_VLAN,
attributes True,
) attributes,
)
# Si le 802.1X est activé sur ce port, cela veut dire que la personne a # Si le 802.1X est activé sur ce port, cela veut dire que la personne a
# été accept précédemment # été accept précédemment
# Par conséquent, on laisse passer sur le bon vlan # Par conséquent, on laisse passer sur le bon vlan
if (nas_type.port_access_mode, port_profile.radius_type) == ('802.1X', '802.1X'): if (nas_type.port_access_mode, port_profile.radius_type) == ("802.1X", "802.1X"):
room = port.room or "Chambre/local inconnu" room = port.room or "Chambre/local inconnu"
return ( return (
sw_name, sw_name,
room, room,
u'Acceptation authentification 802.1X', u"Acceptation authentification 802.1X",
DECISION_VLAN, DECISION_VLAN,
True, True,
attributes attributes,
) )
# Sinon, cela veut dire qu'on fait de l'auth radius par mac # Sinon, cela veut dire qu'on fait de l'auth radius par mac
@ -460,16 +438,20 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
# (anti squattage) # (anti squattage)
# Il n'est pas possible de se connecter sur une prise strict sans adhérent # Il n'est pas possible de se connecter sur une prise strict sans adhérent
# à jour de cotis dedans # à jour de cotis dedans
if port_profile.radius_mode == 'STRICT': if port_profile.radius_mode == "STRICT":
room = port.room room = port.room
if not room: if not room:
return ( return (
sw_name, sw_name,
"Inconnue", "Inconnue",
u'Chambre inconnue', u"Chambre inconnue",
getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT, RadiusOption.get_cached_value("unknown_room_vlan"), "vlan_id", None
RadiusOption.get_attributes('unknown_room_attributes', attributes_kwargs), ),
RadiusOption.get_cached_value("unknown_room") != RadiusOption.REJECT,
RadiusOption.get_attributes(
"unknown_room_attributes", attributes_kwargs
),
) )
room_user = User.objects.filter( room_user = User.objects.filter(
@ -479,41 +461,52 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
return ( return (
sw_name, sw_name,
room, room,
u'Chambre non cotisante', u"Chambre non cotisante",
getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, RadiusOption.get_cached_value("non_member_vlan"), "vlan_id", None
RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ),
RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT,
RadiusOption.get_attributes("non_member_attributes", attributes_kwargs),
) )
for user in room_user: for user in room_user:
if user.is_ban() or user.state != User.STATE_ACTIVE: if user.is_ban() or user.state != User.STATE_ACTIVE:
return ( return (
sw_name, sw_name,
room, room,
u'Utilisateur banni ou desactive', u"Utilisateur banni ou desactive",
getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, RadiusOption.get_cached_value("banned_vlan"), "vlan_id", None
RadiusOption.get_attributes('banned_attributes', attributes_kwargs), ),
RadiusOption.get_cached_value("banned") != RadiusOption.REJECT,
RadiusOption.get_attributes("banned_attributes", attributes_kwargs),
) )
elif not (user.is_connected() or user.is_whitelisted()): elif not (user.is_connected() or user.is_whitelisted()):
return ( return (
sw_name, sw_name,
room, room,
u'Utilisateur non cotisant', u"Utilisateur non cotisant",
getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, RadiusOption.get_cached_value("non_member_vlan"),
RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), "vlan_id",
None,
),
RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT,
RadiusOption.get_attributes(
"non_member_attributes", attributes_kwargs
),
) )
# else: user OK, on passe à la verif MAC # else: user OK, on passe à la verif MAC
# Si on fait de l'auth par mac, on cherche l'interface # Si on fait de l'auth par mac, on cherche l'interface
# via sa mac dans la bdd # via sa mac dans la bdd
if port_profile.radius_mode == 'COMMON' or port_profile.radius_mode == 'STRICT': if port_profile.radius_mode == "COMMON" or port_profile.radius_mode == "STRICT":
# Authentification par mac # Authentification par mac
interface = (Interface.objects interface = (
.filter(mac_address=mac_address) Interface.objects.filter(mac_address=mac_address)
.select_related('machine__user') .select_related("machine__user")
.select_related('ipv4') .select_related("ipv4")
.first()) .first()
)
if not interface: if not interface:
room = port.room room = port.room
# On essaye de register la mac, si l'autocapture a été activée, # On essaye de register la mac, si l'autocapture a été activée,
@ -522,10 +515,17 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
return ( return (
sw_name, sw_name,
room, room,
u'Machine Inconnue', u"Machine Inconnue",
getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, RadiusOption.get_cached_value("unknown_machine_vlan"),
RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), "vlan_id",
None,
),
RadiusOption.get_cached_value("unknown_machine")
!= RadiusOption.REJECT,
RadiusOption.get_attributes(
"unknown_machine_attributes", attributes_kwargs
),
) )
# Sinon on bascule sur la politique définie dans les options # Sinon on bascule sur la politique définie dans les options
# radius. # radius.
@ -533,10 +533,17 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
return ( return (
sw_name, sw_name,
"", "",
u'Machine inconnue', u"Machine inconnue",
getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, RadiusOption.get_cached_value("unknown_machine_vlan"),
RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), "vlan_id",
None,
),
RadiusOption.get_cached_value("unknown_machine")
!= RadiusOption.REJECT,
RadiusOption.get_attributes(
"unknown_machine_attributes", attributes_kwargs
),
) )
# L'interface a été trouvée, on vérifie qu'elle est active, # L'interface a été trouvée, on vérifie qu'elle est active,
@ -549,23 +556,31 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
return ( return (
sw_name, sw_name,
room, room,
u'Adherent banni', u"Adherent banni",
getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, RadiusOption.get_cached_value("banned_vlan"), "vlan_id", None
RadiusOption.get_attributes('banned_attributes', attributes_kwargs), ),
RadiusOption.get_cached_value("banned") != RadiusOption.REJECT,
RadiusOption.get_attributes("banned_attributes", attributes_kwargs),
) )
if not interface.is_active: if not interface.is_active:
return ( return (
sw_name, sw_name,
room, room,
u'Machine non active / adherent non cotisant', u"Machine non active / adherent non cotisant",
getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), getattr(
RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, RadiusOption.get_cached_value("non_member_vlan"),
RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), "vlan_id",
None,
),
RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT,
RadiusOption.get_attributes(
"non_member_attributes", attributes_kwargs
),
) )
# Si on choisi de placer les machines sur le vlan # Si on choisi de placer les machines sur le vlan
# correspondant à leur type : # correspondant à leur type :
if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE': if RadiusOption.get_cached_value("radius_general_policy") == "MACHINE":
DECISION_VLAN = interface.machine_type.ip_type.vlan.vlan_id DECISION_VLAN = interface.machine_type.ip_type.vlan.vlan_id
if not interface.ipv4: if not interface.ipv4:
interface.assign_ipv4() interface.assign_ipv4()
@ -575,14 +590,14 @@ def decide_vlan_switch(nas_machine, nas_type, port_number,
u"Ok, Reassignation de l'ipv4" + extra_log, u"Ok, Reassignation de l'ipv4" + extra_log,
DECISION_VLAN, DECISION_VLAN,
True, True,
attributes attributes,
) )
else: else:
return ( return (
sw_name, sw_name,
room, room,
u'Machine OK' + extra_log, u"Machine OK" + extra_log,
DECISION_VLAN, DECISION_VLAN,
True, True,
attributes attributes,
) )

View file

@ -38,11 +38,9 @@ def can_view(user):
A couple (allowed, msg) where allowed is a boolean which is True if A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None). viewing is granted and msg is a message (can be None).
""" """
can = user.has_module_perms('admin') can = user.has_module_perms("admin")
return ( return (
can, can,
None if can else _("You don't have the right to view this" None if can else _("You don't have the right to view this" " application."),
" application."), "admin",
'admin'
) )

View file

@ -34,12 +34,14 @@ def classname(obj):
""" Returns the object class name """ """ Returns the object class name """
return obj.__class__.__name__ return obj.__class__.__name__
@register.filter @register.filter
def is_facture(baseinvoice): def is_facture(baseinvoice):
"""Returns True if a baseinvoice has a `Facture` child.""" """Returns True if a baseinvoice has a `Facture` child."""
return hasattr(baseinvoice, 'facture') return hasattr(baseinvoice, "facture")
@register.inclusion_tag('buttons/history.html')
@register.inclusion_tag("buttons/history.html")
def history_button(instance, text=False, html_class=True): def history_button(instance, text=False, html_class=True):
"""Creates the correct history button for an instance. """Creates the correct history button for an instance.
@ -51,9 +53,9 @@ def history_button(instance, text=False, html_class=True):
""" """
return { return {
'application': instance._meta.app_label, "application": instance._meta.app_label,
'name': instance._meta.model_name, "name": instance._meta.model_name,
'id': instance.id, "id": instance.id,
'text': text, "text": text,
'class': html_class, "class": html_class,
} }

View file

@ -30,18 +30,20 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.index, name='index'), url(r"^$", views.index, name="index"),
url(r'^stats_logs$', views.stats_logs, name='stats-logs'), url(r"^stats_logs$", views.stats_logs, name="stats-logs"),
url(r'^revert_action/(?P<revision_id>[0-9]+)$',
views.revert_action,
name='revert-action'),
url(r'^stats_general/$', views.stats_general, name='stats-general'),
url(r'^stats_models/$', views.stats_models, name='stats-models'),
url(r'^stats_users/$', views.stats_users, name='stats-users'),
url(r'^stats_actions/$', views.stats_actions, name='stats-actions'),
url( url(
r'(?P<application>\w+)/(?P<object_name>\w+)/(?P<object_id>[0-9]+)$', r"^revert_action/(?P<revision_id>[0-9]+)$",
views.revert_action,
name="revert-action",
),
url(r"^stats_general/$", views.stats_general, name="stats-general"),
url(r"^stats_models/$", views.stats_models, name="stats-models"),
url(r"^stats_users/$", views.stats_users, name="stats-users"),
url(r"^stats_actions/$", views.stats_actions, name="stats-actions"),
url(
r"(?P<application>\w+)/(?P<object_name>\w+)/(?P<object_id>[0-9]+)$",
views.history, views.history,
name='history', name="history",
), ),
] ]

View file

@ -60,16 +60,9 @@ from users.models import (
Ban, Ban,
Whitelist, Whitelist,
Adherent, Adherent,
Club Club,
)
from cotisations.models import (
Facture,
Vente,
Article,
Banque,
Paiement,
Cotisation
) )
from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation
from machines.models import ( from machines.models import (
Machine, Machine,
MachineType, MachineType,
@ -84,7 +77,7 @@ from machines.models import (
Nas, Nas,
SOA, SOA,
Mx, Mx,
Ns Ns,
) )
from topologie.models import ( from topologie.models import (
Switch, Switch,
@ -93,7 +86,7 @@ from topologie.models import (
Stack, Stack,
ModelSwitch, ModelSwitch,
ConstructorSwitch, ConstructorSwitch,
AccessPoint AccessPoint,
) )
from preferences.models import GeneralOption from preferences.models import GeneralOption
from re2o.views import form from re2o.views import form
@ -105,36 +98,24 @@ from re2o.utils import (
all_active_assigned_interfaces_count, all_active_assigned_interfaces_count,
all_active_interfaces_count, all_active_interfaces_count,
) )
from re2o.base import ( from re2o.base import re2o_paginator, SortTable
re2o_paginator, from re2o.acl import can_view_all, can_view_app, can_edit_history
SortTable
)
from re2o.acl import (
can_view_all,
can_view_app,
can_edit_history,
)
@login_required @login_required
@can_view_app('logs') @can_view_app("logs")
def index(request): def index(request):
"""Affiche les logs affinés, date reformatées, selectionne """Affiche les logs affinés, date reformatées, selectionne
les event importants (ajout de droits, ajout de ban/whitelist)""" les event importants (ajout de droits, ajout de ban/whitelist)"""
pagination_number = GeneralOption.get_cached_value('pagination_number') pagination_number = GeneralOption.get_cached_value("pagination_number")
# The types of content kept for display # The types of content kept for display
content_type_filter = ['ban', 'whitelist', 'vente', 'interface', 'user'] content_type_filter = ["ban", "whitelist", "vente", "interface", "user"]
# Select only wanted versions # Select only wanted versions
versions = Version.objects.filter( versions = Version.objects.filter(
content_type__in=ContentType.objects.filter( content_type__in=ContentType.objects.filter(model__in=content_type_filter)
model__in=content_type_filter ).select_related("revision")
)
).select_related('revision')
versions = SortTable.sort( versions = SortTable.sort(
versions, versions, request.GET.get("col"), request.GET.get("order"), SortTable.LOGS_INDEX
request.GET.get('col'),
request.GET.get('order'),
SortTable.LOGS_INDEX
) )
versions = re2o_paginator(request, versions, pagination_number) versions = re2o_paginator(request, versions, pagination_number)
# Force to have a list instead of QuerySet # Force to have a list instead of QuerySet
@ -146,20 +127,21 @@ def index(request):
if versions.object_list[i].object: if versions.object_list[i].object:
version = versions.object_list[i] version = versions.object_list[i]
versions.object_list[i] = { versions.object_list[i] = {
'rev_id': version.revision.id, "rev_id": version.revision.id,
'comment': version.revision.comment, "comment": version.revision.comment,
'datetime': version.revision.date_created, "datetime": version.revision.date_created,
'username': "username": version.revision.user.get_username()
version.revision.user.get_username() if version.revision.user
if version.revision.user else '?', else "?",
'user_id': version.revision.user_id, "user_id": version.revision.user_id,
'version': version} "version": version,
}
else: else:
to_remove.insert(0, i) to_remove.insert(0, i)
# Remove all tagged invalid items # Remove all tagged invalid items
for i in to_remove: for i in to_remove:
versions.object_list.pop(i) versions.object_list.pop(i)
return render(request, 'logs/index.html', {'versions_list': versions}) return render(request, "logs/index.html", {"versions_list": versions})
@login_required @login_required
@ -167,19 +149,20 @@ def index(request):
def stats_logs(request): def stats_logs(request):
"""Affiche l'ensemble des logs et des modifications sur les objets, """Affiche l'ensemble des logs et des modifications sur les objets,
classés par date croissante, en vrac""" classés par date croissante, en vrac"""
pagination_number = GeneralOption.get_cached_value('pagination_number') pagination_number = GeneralOption.get_cached_value("pagination_number")
revisions = Revision.objects.all().select_related('user')\ revisions = (
.prefetch_related('version_set__object') Revision.objects.all()
.select_related("user")
.prefetch_related("version_set__object")
)
revisions = SortTable.sort( revisions = SortTable.sort(
revisions, revisions,
request.GET.get('col'), request.GET.get("col"),
request.GET.get('order'), request.GET.get("order"),
SortTable.LOGS_STATS_LOGS SortTable.LOGS_STATS_LOGS,
) )
revisions = re2o_paginator(request, revisions, pagination_number) revisions = re2o_paginator(request, revisions, pagination_number)
return render(request, 'logs/stats_logs.html', { return render(request, "logs/stats_logs.html", {"revisions_list": revisions})
'revisions_list': revisions
})
@login_required @login_required
@ -193,11 +176,12 @@ def revert_action(request, revision_id):
if request.method == "POST": if request.method == "POST":
revision.revert() revision.revert()
messages.success(request, _("The action was deleted.")) messages.success(request, _("The action was deleted."))
return redirect(reverse('logs:index')) return redirect(reverse("logs:index"))
return form({ return form(
'objet': revision, {"objet": revision, "objet_name": revision.__class__.__name__},
'objet_name': revision.__class__.__name__ "logs/delete.html",
}, 'logs/delete.html', request) request,
)
@login_required @login_required
@ -207,226 +191,221 @@ def stats_general(request):
range, et les statistiques générales sur les users : users actifs, range, et les statistiques générales sur les users : users actifs,
cotisants, activés, archivés, etc""" cotisants, activés, archivés, etc"""
ip_dict = dict() ip_dict = dict()
for ip_range in IpType.objects.select_related('vlan').all(): for ip_range in IpType.objects.select_related("vlan").all():
all_ip = IpList.objects.filter(ip_type=ip_range) all_ip = IpList.objects.filter(ip_type=ip_range)
used_ip = Interface.objects.filter(ipv4__in=all_ip).count() used_ip = Interface.objects.filter(ipv4__in=all_ip).count()
active_ip = all_active_assigned_interfaces_count().filter( active_ip = (
ipv4__in=IpList.objects.filter(ip_type=ip_range) all_active_assigned_interfaces_count()
).count() .filter(ipv4__in=IpList.objects.filter(ip_type=ip_range))
ip_dict[ip_range] = [ip_range, ip_range.vlan, all_ip.count(), .count()
used_ip, active_ip, all_ip.count()-used_ip] )
ip_dict[ip_range] = [
ip_range,
ip_range.vlan,
all_ip.count(),
used_ip,
active_ip,
all_ip.count() - used_ip,
]
_all_adherent = all_adherent(including_asso=False) _all_adherent = all_adherent(including_asso=False)
_all_has_access = all_has_access(including_asso=False) _all_has_access = all_has_access(including_asso=False)
_all_baned = all_baned() _all_baned = all_baned()
_all_whitelisted = all_whitelisted() _all_whitelisted = all_whitelisted()
_all_active_interfaces_count = all_active_interfaces_count() _all_active_interfaces_count = all_active_interfaces_count()
_all_active_assigned_interfaces_count = \ _all_active_assigned_interfaces_count = all_active_assigned_interfaces_count()
all_active_assigned_interfaces_count()
stats = [ stats = [
[ # First set of data (about users) [ # First set of data (about users)
[ # Headers [ # Headers
_("Category"), _("Category"),
_("Number of users (members and clubs)"), _("Number of users (members and clubs)"),
_("Number of members"), _("Number of members"),
_("Number of clubs") _("Number of clubs"),
], ],
{ # Data { # Data
'active_users': [ "active_users": [
_("Activated users"), _("Activated users"),
User.objects.filter(state=User.STATE_ACTIVE).count(), User.objects.filter(state=User.STATE_ACTIVE).count(),
(Adherent.objects (Adherent.objects.filter(state=Adherent.STATE_ACTIVE).count()),
.filter(state=Adherent.STATE_ACTIVE) Club.objects.filter(state=Club.STATE_ACTIVE).count(),
.count()),
Club.objects.filter(state=Club.STATE_ACTIVE).count()
], ],
'inactive_users': [ "inactive_users": [
_("Disabled users"), _("Disabled users"),
User.objects.filter(state=User.STATE_DISABLED).count(), User.objects.filter(state=User.STATE_DISABLED).count(),
(Adherent.objects (Adherent.objects.filter(state=Adherent.STATE_DISABLED).count()),
.filter(state=Adherent.STATE_DISABLED) Club.objects.filter(state=Club.STATE_DISABLED).count(),
.count()),
Club.objects.filter(state=Club.STATE_DISABLED).count()
], ],
'archive_users': [ "archive_users": [
_("Archived users"), _("Archived users"),
User.objects.filter(state=User.STATE_ARCHIVE).count(), User.objects.filter(state=User.STATE_ARCHIVE).count(),
(Adherent.objects (Adherent.objects.filter(state=Adherent.STATE_ARCHIVE).count()),
.filter(state=Adherent.STATE_ARCHIVE) Club.objects.filter(state=Club.STATE_ARCHIVE).count(),
.count()),
Club.objects.filter(state=Club.STATE_ARCHIVE).count()
], ],
'full_archive_users': [ "full_archive_users": [
_("Full Archived users"), _("Full Archived users"),
User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(), User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(),
(Adherent.objects (
.filter(state=Adherent.STATE_FULL_ARCHIVE) Adherent.objects.filter(
.count()), state=Adherent.STATE_FULL_ARCHIVE
Club.objects.filter(state=Club.STATE_FULL_ARCHIVE).count() ).count()
),
Club.objects.filter(state=Club.STATE_FULL_ARCHIVE).count(),
], ],
'not_active_users': [ "not_active_users": [
_("Not yet active users"), _("Not yet active users"),
User.objects.filter(state=User.STATE_NOT_YET_ACTIVE).count(), User.objects.filter(state=User.STATE_NOT_YET_ACTIVE).count(),
(Adherent.objects (
.filter(state=Adherent.STATE_NOT_YET_ACTIVE) Adherent.objects.filter(
.count()), state=Adherent.STATE_NOT_YET_ACTIVE
Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count() ).count()
),
Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count(),
], ],
'adherent_users': [ "adherent_users": [
_("Contributing members"), _("Contributing members"),
_all_adherent.count(), _all_adherent.count(),
_all_adherent.exclude(adherent__isnull=True).count(), _all_adherent.exclude(adherent__isnull=True).count(),
_all_adherent.exclude(club__isnull=True).count() _all_adherent.exclude(club__isnull=True).count(),
], ],
'connexion_users': [ "connexion_users": [
_("Users benefiting from a connection"), _("Users benefiting from a connection"),
_all_has_access.count(), _all_has_access.count(),
_all_has_access.exclude(adherent__isnull=True).count(), _all_has_access.exclude(adherent__isnull=True).count(),
_all_has_access.exclude(club__isnull=True).count() _all_has_access.exclude(club__isnull=True).count(),
], ],
'ban_users': [ "ban_users": [
_("Banned users"), _("Banned users"),
_all_baned.count(), _all_baned.count(),
_all_baned.exclude(adherent__isnull=True).count(), _all_baned.exclude(adherent__isnull=True).count(),
_all_baned.exclude(club__isnull=True).count() _all_baned.exclude(club__isnull=True).count(),
], ],
'whitelisted_user': [ "whitelisted_user": [
_("Users benefiting from a free connection"), _("Users benefiting from a free connection"),
_all_whitelisted.count(), _all_whitelisted.count(),
_all_whitelisted.exclude(adherent__isnull=True).count(), _all_whitelisted.exclude(adherent__isnull=True).count(),
_all_whitelisted.exclude(club__isnull=True).count() _all_whitelisted.exclude(club__isnull=True).count(),
], ],
'actives_interfaces': [ "actives_interfaces": [
_("Active interfaces (with access to the network)"), _("Active interfaces (with access to the network)"),
_all_active_interfaces_count.count(), _all_active_interfaces_count.count(),
(_all_active_interfaces_count (
.exclude(machine__user__adherent__isnull=True) _all_active_interfaces_count.exclude(
.count()), machine__user__adherent__isnull=True
(_all_active_interfaces_count ).count()
.exclude(machine__user__club__isnull=True) ),
.count()) (
_all_active_interfaces_count.exclude(
machine__user__club__isnull=True
).count()
),
], ],
'actives_assigned_interfaces': [ "actives_assigned_interfaces": [
_("Active interfaces assigned IPv4"), _("Active interfaces assigned IPv4"),
_all_active_assigned_interfaces_count.count(), _all_active_assigned_interfaces_count.count(),
(_all_active_assigned_interfaces_count (
.exclude(machine__user__adherent__isnull=True) _all_active_assigned_interfaces_count.exclude(
.count()), machine__user__adherent__isnull=True
(_all_active_assigned_interfaces_count ).count()
.exclude(machine__user__club__isnull=True) ),
.count()) (
] _all_active_assigned_interfaces_count.exclude(
} machine__user__club__isnull=True
).count()
),
],
},
], ],
[ # Second set of data (about ip adresses) [ # Second set of data (about ip adresses)
[ # Headers [ # Headers
_("IP range"), _("IP range"),
_("VLAN"), _("VLAN"),
_("Total number of IP addresses"), _("Total number of IP addresses"),
_("Number of assigned IP addresses"), _("Number of assigned IP addresses"),
_("Number of IP address assigned to an activated machine"), _("Number of IP address assigned to an activated machine"),
_("Number of nonassigned IP addresses") _("Number of nonassigned IP addresses"),
], ],
ip_dict # Data already prepared ip_dict, # Data already prepared
] ],
] ]
return render(request, 'logs/stats_general.html', {'stats_list': stats}) return render(request, "logs/stats_general.html", {"stats_list": stats})
@login_required @login_required
@can_view_app('users', 'cotisations', 'machines', 'topologie') @can_view_app("users", "cotisations", "machines", "topologie")
def stats_models(request): def stats_models(request):
"""Statistiques générales, affiche les comptages par models: """Statistiques générales, affiche les comptages par models:
nombre d'users, d'écoles, de droits, de bannissements, nombre d'users, d'écoles, de droits, de bannissements,
de factures, de ventes, de banque, de machines, etc""" de factures, de ventes, de banque, de machines, etc"""
stats = { stats = {
_("Users"): { _("Users"): {
'users': [User._meta.verbose_name, User.objects.count()], "users": [User._meta.verbose_name, User.objects.count()],
'adherents': [Adherent._meta.verbose_name, Adherent.objects.count()], "adherents": [Adherent._meta.verbose_name, Adherent.objects.count()],
'clubs': [Club._meta.verbose_name, Club.objects.count()], "clubs": [Club._meta.verbose_name, Club.objects.count()],
'serviceuser': [ServiceUser._meta.verbose_name, "serviceuser": [
ServiceUser.objects.count()], ServiceUser._meta.verbose_name,
'school': [School._meta.verbose_name, School.objects.count()], ServiceUser.objects.count(),
'listright': [ListRight._meta.verbose_name, ListRight.objects.count()], ],
'listshell': [ListShell._meta.verbose_name, ListShell.objects.count()], "school": [School._meta.verbose_name, School.objects.count()],
'ban': [Ban._meta.verbose_name, Ban.objects.count()], "listright": [ListRight._meta.verbose_name, ListRight.objects.count()],
'whitelist': [Whitelist._meta.verbose_name, Whitelist.objects.count()] "listshell": [ListShell._meta.verbose_name, ListShell.objects.count()],
"ban": [Ban._meta.verbose_name, Ban.objects.count()],
"whitelist": [Whitelist._meta.verbose_name, Whitelist.objects.count()],
}, },
_("Subscriptions"): { _("Subscriptions"): {
'factures': [ "factures": [Facture._meta.verbose_name, Facture.objects.count()],
Facture._meta.verbose_name, "vente": [Vente._meta.verbose_name, Vente.objects.count()],
Facture.objects.count() "cotisation": [Cotisation._meta.verbose_name, Cotisation.objects.count()],
], "article": [Article._meta.verbose_name, Article.objects.count()],
'vente': [ "banque": [Banque._meta.verbose_name, Banque.objects.count()],
Vente._meta.verbose_name,
Vente.objects.count()
],
'cotisation': [
Cotisation._meta.verbose_name,
Cotisation.objects.count()
],
'article': [
Article._meta.verbose_name,
Article.objects.count()
],
'banque': [
Banque._meta.verbose_name,
Banque.objects.count()
],
}, },
_("Machines"): { _("Machines"): {
'machine': [Machine._meta.verbose_name, "machine": [Machine._meta.verbose_name, Machine.objects.count()],
Machine.objects.count()], "typemachine": [
'typemachine': [MachineType._meta.verbose_name, MachineType._meta.verbose_name,
MachineType.objects.count()], MachineType.objects.count(),
'typeip': [IpType._meta.verbose_name,
IpType.objects.count()],
'extension': [Extension._meta.verbose_name,
Extension.objects.count()],
'interface': [Interface._meta.verbose_name,
Interface.objects.count()],
'alias': [Domain._meta.verbose_name,
Domain.objects.exclude(cname=None).count()],
'iplist': [IpList._meta.verbose_name,
IpList.objects.count()],
'service': [Service._meta.verbose_name,
Service.objects.count()],
'ouvertureportlist': [
OuverturePortList._meta.verbose_name,
OuverturePortList.objects.count()
], ],
'vlan': [Vlan._meta.verbose_name, Vlan.objects.count()], "typeip": [IpType._meta.verbose_name, IpType.objects.count()],
'SOA': [SOA._meta.verbose_name, SOA.objects.count()], "extension": [Extension._meta.verbose_name, Extension.objects.count()],
'Mx': [Mx._meta.verbose_name, Mx.objects.count()], "interface": [Interface._meta.verbose_name, Interface.objects.count()],
'Ns': [Ns._meta.verbose_name, Ns.objects.count()], "alias": [
'nas': [Nas._meta.verbose_name, Nas.objects.count()], Domain._meta.verbose_name,
Domain.objects.exclude(cname=None).count(),
],
"iplist": [IpList._meta.verbose_name, IpList.objects.count()],
"service": [Service._meta.verbose_name, Service.objects.count()],
"ouvertureportlist": [
OuverturePortList._meta.verbose_name,
OuverturePortList.objects.count(),
],
"vlan": [Vlan._meta.verbose_name, Vlan.objects.count()],
"SOA": [SOA._meta.verbose_name, SOA.objects.count()],
"Mx": [Mx._meta.verbose_name, Mx.objects.count()],
"Ns": [Ns._meta.verbose_name, Ns.objects.count()],
"nas": [Nas._meta.verbose_name, Nas.objects.count()],
}, },
_("Topology"): { _("Topology"): {
'switch': [Switch._meta.verbose_name, "switch": [Switch._meta.verbose_name, Switch.objects.count()],
Switch.objects.count()], "bornes": [AccessPoint._meta.verbose_name, AccessPoint.objects.count()],
'bornes': [AccessPoint._meta.verbose_name, "port": [Port._meta.verbose_name, Port.objects.count()],
AccessPoint.objects.count()], "chambre": [Room._meta.verbose_name, Room.objects.count()],
'port': [Port._meta.verbose_name, Port.objects.count()], "stack": [Stack._meta.verbose_name, Stack.objects.count()],
'chambre': [Room._meta.verbose_name, Room.objects.count()], "modelswitch": [
'stack': [Stack._meta.verbose_name, Stack.objects.count()],
'modelswitch': [
ModelSwitch._meta.verbose_name, ModelSwitch._meta.verbose_name,
ModelSwitch.objects.count() ModelSwitch.objects.count(),
], ],
'constructorswitch': [ "constructorswitch": [
ConstructorSwitch._meta.verbose_name, ConstructorSwitch._meta.verbose_name,
ConstructorSwitch.objects.count() ConstructorSwitch.objects.count(),
], ],
}, },
_("Actions performed"): _("Actions performed"): {
{ "revision": [_("Number of actions"), Revision.objects.count()]
'revision': [_("Number of actions"), Revision.objects.count()],
}, },
} }
return render(request, 'logs/stats_models.html', {'stats_list': stats}) return render(request, "logs/stats_models.html", {"stats_list": stats})
@login_required @login_required
@can_view_app('users') @can_view_app("users")
def stats_users(request): def stats_users(request):
"""Affiche les statistiques base de données aggrégées par user : """Affiche les statistiques base de données aggrégées par user :
nombre de machines par user, d'etablissements par user, nombre de machines par user, d'etablissements par user,
@ -434,55 +413,51 @@ def stats_users(request):
de bannissement par user, etc""" de bannissement par user, etc"""
stats = { stats = {
_("User"): { _("User"): {
_("Machines"): User.objects.annotate( _("Machines"): User.objects.annotate(num=Count("machine")).order_by("-num")[
num=Count('machine') :10
).order_by('-num')[:10], ],
_("Invoice"): User.objects.annotate( _("Invoice"): User.objects.annotate(num=Count("facture")).order_by("-num")[
num=Count('facture') :10
).order_by('-num')[:10], ],
_("Ban"): User.objects.annotate( _("Ban"): User.objects.annotate(num=Count("ban")).order_by("-num")[:10],
num=Count('ban') _("Whitelist"): User.objects.annotate(num=Count("whitelist")).order_by(
).order_by('-num')[:10], "-num"
_("Whitelist"): User.objects.annotate( )[:10],
num=Count('whitelist') _("Rights"): User.objects.annotate(num=Count("groups")).order_by("-num")[
).order_by('-num')[:10], :10
_("Rights"): User.objects.annotate( ],
num=Count('groups')
).order_by('-num')[:10],
}, },
_("School"): { _("School"): {
_("User"): School.objects.annotate( _("User"): School.objects.annotate(num=Count("user")).order_by("-num")[:10]
num=Count('user')
).order_by('-num')[:10],
}, },
_("Payment method"): { _("Payment method"): {
_("User"): Paiement.objects.annotate( _("User"): Paiement.objects.annotate(num=Count("facture")).order_by("-num")[
num=Count('facture') :10
).order_by('-num')[:10], ]
}, },
_("Bank"): { _("Bank"): {
_("User"): Banque.objects.annotate( _("User"): Banque.objects.annotate(num=Count("facture")).order_by("-num")[
num=Count('facture') :10
).order_by('-num')[:10], ]
}, },
} }
return render(request, 'logs/stats_users.html', {'stats_list': stats}) return render(request, "logs/stats_users.html", {"stats_list": stats})
@login_required @login_required
@can_view_app('users') @can_view_app("users")
def stats_actions(request): def stats_actions(request):
"""Vue qui affiche les statistiques de modifications d'objets par """Vue qui affiche les statistiques de modifications d'objets par
utilisateurs. utilisateurs.
Affiche le nombre de modifications aggrégées par utilisateurs""" Affiche le nombre de modifications aggrégées par utilisateurs"""
stats = { stats = {
_("User"): { _("User"): {
_("Action"): User.objects.annotate( _("Action"): User.objects.annotate(num=Count("revision")).order_by("-num")[
num=Count('revision') :40
).order_by('-num')[:40], ]
}, }
} }
return render(request, 'logs/stats_users.html', {'stats_list': stats}) return render(request, "logs/stats_users.html", {"stats_list": stats})
def history(request, application, object_name, object_id): def history(request, application, object_name, object_id):
@ -509,33 +484,29 @@ def history(request, application, object_name, object_id):
model = apps.get_model(application, object_name) model = apps.get_model(application, object_name)
except LookupError: except LookupError:
raise Http404(_("No model found.")) raise Http404(_("No model found."))
object_name_id = object_name + 'id' object_name_id = object_name + "id"
kwargs = {object_name_id: object_id} kwargs = {object_name_id: object_id}
try: try:
instance = model.get_instance(**kwargs) instance = model.get_instance(**kwargs)
except model.DoesNotExist: except model.DoesNotExist:
messages.error(request, _("Nonexistent entry.")) messages.error(request, _("Nonexistent entry."))
return redirect(reverse( return redirect(
'users:profil', reverse("users:profil", kwargs={"userid": str(request.user.id)})
kwargs={'userid': str(request.user.id)} )
))
can, msg, _permissions = instance.can_view(request.user) can, msg, _permissions = instance.can_view(request.user)
if not can: if not can:
messages.error(request, msg or _("You don't have the right to access this menu.")) messages.error(
return redirect(reverse( request, msg or _("You don't have the right to access this menu.")
'users:profil', )
kwargs={'userid': str(request.user.id)} return redirect(
)) reverse("users:profil", kwargs={"userid": str(request.user.id)})
pagination_number = GeneralOption.get_cached_value('pagination_number') )
pagination_number = GeneralOption.get_cached_value("pagination_number")
reversions = Version.objects.get_for_object(instance) reversions = Version.objects.get_for_object(instance)
if hasattr(instance, 'linked_objects'): if hasattr(instance, "linked_objects"):
for related_object in chain(instance.linked_objects()): for related_object in chain(instance.linked_objects()):
reversions = (reversions | reversions = reversions | Version.objects.get_for_object(related_object)
Version.objects.get_for_object(related_object))
reversions = re2o_paginator(request, reversions, pagination_number) reversions = re2o_paginator(request, reversions, pagination_number)
return render( return render(
request, request, "re2o/history.html", {"reversions": reversions, "object": instance}
're2o/history.html',
{'reversions': reversions, 'object': instance}
) )

View file

@ -38,11 +38,9 @@ def can_view(user):
A couple (allowed, msg) where allowed is a boolean which is True if A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None). viewing is granted and msg is a message (can be None).
""" """
can = user.has_module_perms('machines') can = user.has_module_perms("machines")
return ( return (
can, can,
None if can else _("You don't have the right to view this" None if can else _("You don't have the right to view this" " application."),
" application."), ("machines",),
('machines',)
) )

View file

@ -51,106 +51,127 @@ from .models import IpType, Machine, MachineType, Domain, IpList, Interface
class MachineAdmin(VersionAdmin): class MachineAdmin(VersionAdmin):
""" Admin view of a Machine object """ """ Admin view of a Machine object """
pass pass
class Ipv6ListAdmin(VersionAdmin): class Ipv6ListAdmin(VersionAdmin):
""" Admin view of a Ipv6List object """ """ Admin view of a Ipv6List object """
pass pass
class IpTypeAdmin(VersionAdmin): class IpTypeAdmin(VersionAdmin):
""" Admin view of a IpType object """ """ Admin view of a IpType object """
pass pass
class MachineTypeAdmin(VersionAdmin): class MachineTypeAdmin(VersionAdmin):
""" Admin view of a MachineType object """ """ Admin view of a MachineType object """
pass pass
class VlanAdmin(VersionAdmin): class VlanAdmin(VersionAdmin):
""" Admin view of a Vlan object """ """ Admin view of a Vlan object """
pass pass
class ExtensionAdmin(VersionAdmin): class ExtensionAdmin(VersionAdmin):
""" Admin view of a Extension object """ """ Admin view of a Extension object """
pass pass
class SOAAdmin(VersionAdmin): class SOAAdmin(VersionAdmin):
""" Admin view of a SOA object """ """ Admin view of a SOA object """
pass pass
class MxAdmin(VersionAdmin): class MxAdmin(VersionAdmin):
""" Admin view of a MX object """ """ Admin view of a MX object """
pass pass
class NsAdmin(VersionAdmin): class NsAdmin(VersionAdmin):
""" Admin view of a NS object """ """ Admin view of a NS object """
pass pass
class TxtAdmin(VersionAdmin): class TxtAdmin(VersionAdmin):
""" Admin view of a TXT object """ """ Admin view of a TXT object """
pass pass
class DNameAdmin(VersionAdmin): class DNameAdmin(VersionAdmin):
""" Admin view of a DName object """ """ Admin view of a DName object """
pass pass
class SrvAdmin(VersionAdmin): class SrvAdmin(VersionAdmin):
""" Admin view of a SRV object """ """ Admin view of a SRV object """
pass pass
class SshFpAdmin(VersionAdmin): class SshFpAdmin(VersionAdmin):
""" Admin view of a SSHFP object """ """ Admin view of a SSHFP object """
pass pass
class NasAdmin(VersionAdmin): class NasAdmin(VersionAdmin):
""" Admin view of a Nas object """ """ Admin view of a Nas object """
pass pass
class IpListAdmin(VersionAdmin): class IpListAdmin(VersionAdmin):
""" Admin view of a Ipv4List object """ """ Admin view of a Ipv4List object """
pass pass
class OuverturePortAdmin(VersionAdmin): class OuverturePortAdmin(VersionAdmin):
""" Admin view of a OuverturePort object """ """ Admin view of a OuverturePort object """
pass pass
class OuverturePortListAdmin(VersionAdmin): class OuverturePortListAdmin(VersionAdmin):
""" Admin view of a OuverturePortList object """ """ Admin view of a OuverturePortList object """
pass pass
class InterfaceAdmin(VersionAdmin): class InterfaceAdmin(VersionAdmin):
""" Admin view of a Interface object """ """ Admin view of a Interface object """
list_display = ('machine', 'machine_type', 'mac_address', 'ipv4', 'details')
list_display = ("machine", "machine_type", "mac_address", "ipv4", "details")
class DomainAdmin(VersionAdmin): class DomainAdmin(VersionAdmin):
""" Admin view of a Domain object """ """ Admin view of a Domain object """
list_display = ('interface_parent', 'name', 'extension', 'cname')
list_display = ("interface_parent", "name", "extension", "cname")
class ServiceAdmin(VersionAdmin): class ServiceAdmin(VersionAdmin):
""" Admin view of a ServiceAdmin object """ """ Admin view of a ServiceAdmin object """
list_display = ('service_type', 'min_time_regen', 'regular_time_regen')
list_display = ("service_type", "min_time_regen", "regular_time_regen")
class RoleAdmin(VersionAdmin): class RoleAdmin(VersionAdmin):
""" Admin view of a RoleAdmin object """ """ Admin view of a RoleAdmin object """
pass pass

View file

@ -70,19 +70,19 @@ class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class Meta: class Meta:
model = Machine model = Machine
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs) super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = _("Machine name") self.fields["name"].label = _("Machine name")
class NewMachineForm(EditMachineForm): class NewMachineForm(EditMachineForm):
"""Creation d'une machine, ne renseigne que le nom""" """Creation d'une machine, ne renseigne que le nom"""
class Meta(EditMachineForm.Meta): class Meta(EditMachineForm.Meta):
fields = ['name'] fields = ["name"]
class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
@ -90,39 +90,38 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class Meta: class Meta:
model = Interface model = Interface
fields = ['machine', 'machine_type', 'ipv4', 'mac_address', 'details'] fields = ["machine", "machine_type", "ipv4", "mac_address", "details"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
user = kwargs.get('user') user = kwargs.get("user")
super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs) super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['mac_address'].label = _("MAC address") self.fields["mac_address"].label = _("MAC address")
self.fields['machine_type'].label = _("Machine type") self.fields["machine_type"].label = _("Machine type")
self.fields['machine_type'].empty_label = _("Select a machine type") self.fields["machine_type"].empty_label = _("Select a machine type")
if "ipv4" in self.fields: if "ipv4" in self.fields:
self.fields['ipv4'].empty_label = _("Automatic IPv4 assignment") self.fields["ipv4"].empty_label = _("Automatic IPv4 assignment")
self.fields['ipv4'].queryset = IpList.objects.filter( self.fields["ipv4"].queryset = IpList.objects.filter(interface__isnull=True)
interface__isnull=True
)
can_use_all_iptype, _reason, _permissions = IpType.can_use_all(user) can_use_all_iptype, _reason, _permissions = IpType.can_use_all(user)
if not can_use_all_iptype: if not can_use_all_iptype:
self.fields['ipv4'].queryset = IpList.objects.filter( self.fields["ipv4"].queryset = IpList.objects.filter(
interface__isnull=True interface__isnull=True
).filter(ip_type__in=IpType.objects.filter(need_infra=False)) ).filter(ip_type__in=IpType.objects.filter(need_infra=False))
else: else:
self.fields['ipv4'].queryset = IpList.objects.filter( self.fields["ipv4"].queryset = IpList.objects.filter(
interface__isnull=True interface__isnull=True
) )
# Add it's own address # Add it's own address
self.fields['ipv4'].queryset |= IpList.objects.filter( self.fields["ipv4"].queryset |= IpList.objects.filter(
interface=self.instance interface=self.instance
) )
if "machine" in self.fields: if "machine" in self.fields:
self.fields['machine'].queryset = Machine.objects.all() \ self.fields["machine"].queryset = Machine.objects.all().select_related(
.select_related('user') "user"
)
can_use_all_machinetype, _reason, _permissions = MachineType.can_use_all(user) can_use_all_machinetype, _reason, _permissions = MachineType.can_use_all(user)
if not can_use_all_machinetype: if not can_use_all_machinetype:
self.fields['machine_type'].queryset = MachineType.objects.filter( self.fields["machine_type"].queryset = MachineType.objects.filter(
ip_type__in=IpType.objects.filter(need_infra=False) ip_type__in=IpType.objects.filter(need_infra=False)
) )
@ -132,7 +131,7 @@ class AddInterfaceForm(EditInterfaceForm):
affiche ou non l'ensemble des ip disponibles""" affiche ou non l'ensemble des ip disponibles"""
class Meta(EditInterfaceForm.Meta): class Meta(EditInterfaceForm.Meta):
fields = ['machine_type', 'ipv4', 'mac_address', 'details'] fields = ["machine_type", "ipv4", "mac_address", "details"]
class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
@ -140,15 +139,15 @@ class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class Meta: class Meta:
model = Domain model = Domain
fields = ['name', 'extension', 'ttl'] fields = ["name", "extension", "ttl"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
user = kwargs['user'] user = kwargs["user"]
super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs)
can_use_all, _reason, _permissions = Extension.can_use_all(user) can_use_all, _reason, _permissions = Extension.can_use_all(user)
if not can_use_all: if not can_use_all:
self.fields['extension'].queryset = Extension.objects.filter( self.fields["extension"].queryset = Extension.objects.filter(
need_infra=False need_infra=False
) )
@ -158,30 +157,31 @@ class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class Meta: class Meta:
model = Domain model = Domain
fields = ['name', 'ttl'] fields = ["name", "ttl"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if 'user' in kwargs: if "user" in kwargs:
user = kwargs['user'] user = kwargs["user"]
initial = kwargs.get('initial', {}) initial = kwargs.get("initial", {})
initial['name'] = user.get_next_domain_name() initial["name"] = user.get_next_domain_name()
kwargs['initial'] = initial kwargs["initial"] = initial
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs) super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelAliasForm(FormRevMixin, Form): class DelAliasForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs objets alias""" """Suppression d'un ou plusieurs objets alias"""
alias = forms.ModelMultipleChoiceField( alias = forms.ModelMultipleChoiceField(
queryset=Domain.objects.all(), queryset=Domain.objects.all(),
label=_("Current aliases"), label=_("Current aliases"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
interface = kwargs.pop('interface') interface = kwargs.pop("interface")
super(DelAliasForm, self).__init__(*args, **kwargs) super(DelAliasForm, self).__init__(*args, **kwargs)
self.fields['alias'].queryset = Domain.objects.filter( self.fields["alias"].queryset = Domain.objects.filter(
cname__in=Domain.objects.filter(interface_parent=interface) cname__in=Domain.objects.filter(interface_parent=interface)
) )
@ -191,30 +191,31 @@ class MachineTypeForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = MachineType model = MachineType
fields = ['name', 'ip_type'] fields = ["name", "ip_type"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs) super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = _("Machine type to add") self.fields["name"].label = _("Machine type to add")
self.fields['ip_type'].label = _("Related IP type") self.fields["ip_type"].label = _("Related IP type")
class DelMachineTypeForm(FormRevMixin, Form): class DelMachineTypeForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs machinetype""" """Suppression d'un ou plusieurs machinetype"""
machinetypes = forms.ModelMultipleChoiceField( machinetypes = forms.ModelMultipleChoiceField(
queryset=MachineType.objects.none(), queryset=MachineType.objects.none(),
label=_("Current machine types"), label=_("Current machine types"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelMachineTypeForm, self).__init__(*args, **kwargs) super(DelMachineTypeForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['machinetypes'].queryset = instances self.fields["machinetypes"].queryset = instances
else: else:
self.fields['machinetypes'].queryset = MachineType.objects.all() self.fields["machinetypes"].queryset = MachineType.objects.all()
class IpTypeForm(FormRevMixin, ModelForm): class IpTypeForm(FormRevMixin, ModelForm):
@ -223,12 +224,12 @@ class IpTypeForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = IpType model = IpType
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs) super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = _("IP type to add") self.fields["name"].label = _("IP type to add")
class EditIpTypeForm(IpTypeForm): class EditIpTypeForm(IpTypeForm):
@ -236,27 +237,37 @@ class EditIpTypeForm(IpTypeForm):
synchroniser les objets iplist""" synchroniser les objets iplist"""
class Meta(IpTypeForm.Meta): class Meta(IpTypeForm.Meta):
fields = ['extension', 'name', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask', fields = [
'prefix_v6', 'prefix_v6_length', "extension",
'vlan', 'reverse_v4', 'reverse_v6', "name",
'ouverture_ports'] "need_infra",
"domaine_ip_network",
"domaine_ip_netmask",
"prefix_v6",
"prefix_v6_length",
"vlan",
"reverse_v4",
"reverse_v6",
"ouverture_ports",
]
class DelIpTypeForm(FormRevMixin, Form): class DelIpTypeForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs iptype""" """Suppression d'un ou plusieurs iptype"""
iptypes = forms.ModelMultipleChoiceField( iptypes = forms.ModelMultipleChoiceField(
queryset=IpType.objects.none(), queryset=IpType.objects.none(),
label=_("Current IP types"), label=_("Current IP types"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelIpTypeForm, self).__init__(*args, **kwargs) super(DelIpTypeForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['iptypes'].queryset = instances self.fields["iptypes"].queryset = instances
else: else:
self.fields['iptypes'].queryset = IpType.objects.all() self.fields["iptypes"].queryset = IpType.objects.all()
class ExtensionForm(FormRevMixin, ModelForm): class ExtensionForm(FormRevMixin, ModelForm):
@ -264,33 +275,34 @@ class ExtensionForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Extension model = Extension
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(ExtensionForm, self).__init__(*args, prefix=prefix, **kwargs) super(ExtensionForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = _("Extension to add") self.fields["name"].label = _("Extension to add")
self.fields['origin'].label = _("A record origin") self.fields["origin"].label = _("A record origin")
self.fields['origin_v6'].label = _("AAAA record origin") self.fields["origin_v6"].label = _("AAAA record origin")
self.fields['soa'].label = _("SOA record to use") self.fields["soa"].label = _("SOA record to use")
self.fields['dnssec'].label = _("Sign with DNSSEC") self.fields["dnssec"].label = _("Sign with DNSSEC")
class DelExtensionForm(FormRevMixin, Form): class DelExtensionForm(FormRevMixin, Form):
"""Suppression d'une ou plusieurs extensions""" """Suppression d'une ou plusieurs extensions"""
extensions = forms.ModelMultipleChoiceField( extensions = forms.ModelMultipleChoiceField(
queryset=Extension.objects.none(), queryset=Extension.objects.none(),
label=_("Current extensions"), label=_("Current extensions"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelExtensionForm, self).__init__(*args, **kwargs) super(DelExtensionForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['extensions'].queryset = instances self.fields["extensions"].queryset = instances
else: else:
self.fields['extensions'].queryset = Extension.objects.all() self.fields["extensions"].queryset = Extension.objects.all()
class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
@ -298,10 +310,10 @@ class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
class Meta: class Meta:
model = Ipv6List model = Ipv6List
fields = ['ipv6', 'slaac_ip'] fields = ["ipv6", "slaac_ip"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs) super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs)
@ -310,28 +322,29 @@ class SOAForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = SOA model = SOA
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs) super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelSOAForm(FormRevMixin, Form): class DelSOAForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs SOA""" """Suppression d'un ou plusieurs SOA"""
soa = forms.ModelMultipleChoiceField( soa = forms.ModelMultipleChoiceField(
queryset=SOA.objects.none(), queryset=SOA.objects.none(),
label=_("Current SOA records"), label=_("Current SOA records"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelSOAForm, self).__init__(*args, **kwargs) super(DelSOAForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['soa'].queryset = instances self.fields["soa"].queryset = instances
else: else:
self.fields['soa'].queryset = SOA.objects.all() self.fields["soa"].queryset = SOA.objects.all()
class MxForm(FormRevMixin, ModelForm): class MxForm(FormRevMixin, ModelForm):
@ -339,31 +352,32 @@ class MxForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Mx model = Mx
fields = ['zone', 'priority', 'name', 'ttl'] fields = ["zone", "priority", "name", "ttl"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(MxForm, self).__init__(*args, prefix=prefix, **kwargs) super(MxForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].queryset = Domain.objects.exclude( self.fields["name"].queryset = Domain.objects.exclude(
interface_parent=None interface_parent=None
).select_related('extension') ).select_related("extension")
class DelMxForm(FormRevMixin, Form): class DelMxForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs MX""" """Suppression d'un ou plusieurs MX"""
mx = forms.ModelMultipleChoiceField( mx = forms.ModelMultipleChoiceField(
queryset=Mx.objects.none(), queryset=Mx.objects.none(),
label=_("Current MX records"), label=_("Current MX records"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelMxForm, self).__init__(*args, **kwargs) super(DelMxForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['mx'].queryset = instances self.fields["mx"].queryset = instances
else: else:
self.fields['mx'].queryset = Mx.objects.all() self.fields["mx"].queryset = Mx.objects.all()
class NsForm(FormRevMixin, ModelForm): class NsForm(FormRevMixin, ModelForm):
@ -373,31 +387,32 @@ class NsForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Ns model = Ns
fields = ['zone', 'ns', 'ttl'] fields = ["zone", "ns", "ttl"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(NsForm, self).__init__(*args, prefix=prefix, **kwargs) super(NsForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['ns'].queryset = Domain.objects.exclude( self.fields["ns"].queryset = Domain.objects.exclude(
interface_parent=None interface_parent=None
).select_related('extension') ).select_related("extension")
class DelNsForm(FormRevMixin, Form): class DelNsForm(FormRevMixin, Form):
"""Suppresion d'un ou plusieurs NS""" """Suppresion d'un ou plusieurs NS"""
ns = forms.ModelMultipleChoiceField( ns = forms.ModelMultipleChoiceField(
queryset=Ns.objects.none(), queryset=Ns.objects.none(),
label=_("Current NS records"), label=_("Current NS records"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelNsForm, self).__init__(*args, **kwargs) super(DelNsForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['ns'].queryset = instances self.fields["ns"].queryset = instances
else: else:
self.fields['ns'].queryset = Ns.objects.all() self.fields["ns"].queryset = Ns.objects.all()
class TxtForm(FormRevMixin, ModelForm): class TxtForm(FormRevMixin, ModelForm):
@ -405,28 +420,29 @@ class TxtForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Txt model = Txt
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs) super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelTxtForm(FormRevMixin, Form): class DelTxtForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs TXT""" """Suppression d'un ou plusieurs TXT"""
txt = forms.ModelMultipleChoiceField( txt = forms.ModelMultipleChoiceField(
queryset=Txt.objects.none(), queryset=Txt.objects.none(),
label=_("Current TXT records"), label=_("Current TXT records"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelTxtForm, self).__init__(*args, **kwargs) super(DelTxtForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['txt'].queryset = instances self.fields["txt"].queryset = instances
else: else:
self.fields['txt'].queryset = Txt.objects.all() self.fields["txt"].queryset = Txt.objects.all()
class DNameForm(FormRevMixin, ModelForm): class DNameForm(FormRevMixin, ModelForm):
@ -434,28 +450,29 @@ class DNameForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = DName model = DName
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(DNameForm, self).__init__(*args, prefix=prefix, **kwargs) super(DNameForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelDNameForm(FormRevMixin, Form): class DelDNameForm(FormRevMixin, Form):
"""Delete a set of DNAME entries""" """Delete a set of DNAME entries"""
dnames = forms.ModelMultipleChoiceField( dnames = forms.ModelMultipleChoiceField(
queryset=Txt.objects.none(), queryset=Txt.objects.none(),
label=_("Current DNAME records"), label=_("Current DNAME records"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelDNameForm, self).__init__(*args, **kwargs) super(DelDNameForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['dnames'].queryset = instances self.fields["dnames"].queryset = instances
else: else:
self.fields['dnames'].queryset = DName.objects.all() self.fields["dnames"].queryset = DName.objects.all()
class SrvForm(FormRevMixin, ModelForm): class SrvForm(FormRevMixin, ModelForm):
@ -463,28 +480,29 @@ class SrvForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Srv model = Srv
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs) super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelSrvForm(FormRevMixin, Form): class DelSrvForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs Srv""" """Suppression d'un ou plusieurs Srv"""
srv = forms.ModelMultipleChoiceField( srv = forms.ModelMultipleChoiceField(
queryset=Srv.objects.none(), queryset=Srv.objects.none(),
label=_("Current SRV records"), label=_("Current SRV records"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelSrvForm, self).__init__(*args, **kwargs) super(DelSrvForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['srv'].queryset = instances self.fields["srv"].queryset = instances
else: else:
self.fields['srv'].queryset = Srv.objects.all() self.fields["srv"].queryset = Srv.objects.all()
class NasForm(FormRevMixin, ModelForm): class NasForm(FormRevMixin, ModelForm):
@ -493,28 +511,29 @@ class NasForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Nas model = Nas
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(NasForm, self).__init__(*args, prefix=prefix, **kwargs) super(NasForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelNasForm(FormRevMixin, Form): class DelNasForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs nas""" """Suppression d'un ou plusieurs nas"""
nas = forms.ModelMultipleChoiceField( nas = forms.ModelMultipleChoiceField(
queryset=Nas.objects.none(), queryset=Nas.objects.none(),
label=_("Current NAS devices"), label=_("Current NAS devices"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelNasForm, self).__init__(*args, **kwargs) super(DelNasForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['nas'].queryset = instances self.fields["nas"].queryset = instances
else: else:
self.fields['nas'].queryset = Nas.objects.all() self.fields["nas"].queryset = Nas.objects.all()
class RoleForm(FormRevMixin, ModelForm): class RoleForm(FormRevMixin, ModelForm):
@ -522,32 +541,32 @@ class RoleForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Role model = Role
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs) super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['servers'].queryset = (Interface.objects.all() self.fields["servers"].queryset = Interface.objects.all().select_related(
.select_related( "domain__extension"
'domain__extension' )
))
class DelRoleForm(FormRevMixin, Form): class DelRoleForm(FormRevMixin, Form):
"""Deletion of one or several roles.""" """Deletion of one or several roles."""
role = forms.ModelMultipleChoiceField( role = forms.ModelMultipleChoiceField(
queryset=Role.objects.none(), queryset=Role.objects.none(),
label=_("Current roles"), label=_("Current roles"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelRoleForm, self).__init__(*args, **kwargs) super(DelRoleForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['role'].queryset = instances self.fields["role"].queryset = instances
else: else:
self.fields['role'].queryset = Role.objects.all() self.fields["role"].queryset = Role.objects.all()
class ServiceForm(FormRevMixin, ModelForm): class ServiceForm(FormRevMixin, ModelForm):
@ -555,15 +574,14 @@ class ServiceForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Service model = Service
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs) super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['servers'].queryset = (Interface.objects.all() self.fields["servers"].queryset = Interface.objects.all().select_related(
.select_related( "domain__extension"
'domain__extension' )
))
def save(self, commit=True): def save(self, commit=True):
# TODO : None of the parents of ServiceForm use the commit # TODO : None of the parents of ServiceForm use the commit
@ -571,25 +589,26 @@ class ServiceForm(FormRevMixin, ModelForm):
instance = super(ServiceForm, self).save(commit=False) instance = super(ServiceForm, self).save(commit=False)
if commit: if commit:
instance.save() instance.save()
instance.process_link(self.cleaned_data.get('servers')) instance.process_link(self.cleaned_data.get("servers"))
return instance return instance
class DelServiceForm(FormRevMixin, Form): class DelServiceForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs service""" """Suppression d'un ou plusieurs service"""
service = forms.ModelMultipleChoiceField( service = forms.ModelMultipleChoiceField(
queryset=Service.objects.none(), queryset=Service.objects.none(),
label=_("Current services"), label=_("Current services"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelServiceForm, self).__init__(*args, **kwargs) super(DelServiceForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['service'].queryset = instances self.fields["service"].queryset = instances
else: else:
self.fields['service'].queryset = Service.objects.all() self.fields["service"].queryset = Service.objects.all()
class VlanForm(FormRevMixin, ModelForm): class VlanForm(FormRevMixin, ModelForm):
@ -597,39 +616,41 @@ class VlanForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Vlan model = Vlan
fields = ['vlan_id', 'name', 'comment'] fields = ["vlan_id", "name", "comment"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs) super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs)
class EditOptionVlanForm(FormRevMixin, ModelForm): class EditOptionVlanForm(FormRevMixin, ModelForm):
"""Ajout d'un vlan : id, nom""" """Ajout d'un vlan : id, nom"""
class Meta: class Meta:
model = Vlan model = Vlan
fields = ['dhcp_snooping', 'dhcpv6_snooping', 'arp_protect', 'igmp', 'mld'] fields = ["dhcp_snooping", "dhcpv6_snooping", "arp_protect", "igmp", "mld"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs) super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs)
class DelVlanForm(FormRevMixin, Form): class DelVlanForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs vlans""" """Suppression d'un ou plusieurs vlans"""
vlan = forms.ModelMultipleChoiceField( vlan = forms.ModelMultipleChoiceField(
queryset=Vlan.objects.none(), queryset=Vlan.objects.none(),
label=_("Current VLANs"), label=_("Current VLANs"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None) instances = kwargs.pop("instances", None)
super(DelVlanForm, self).__init__(*args, **kwargs) super(DelVlanForm, self).__init__(*args, **kwargs)
if instances: if instances:
self.fields['vlan'].queryset = instances self.fields["vlan"].queryset = instances
else: else:
self.fields['vlan'].queryset = Vlan.objects.all() self.fields["vlan"].queryset = Vlan.objects.all()
class EditOuverturePortConfigForm(FormRevMixin, ModelForm): class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
@ -638,14 +659,12 @@ class EditOuverturePortConfigForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = Interface model = Interface
fields = ['port_lists'] fields = ["port_lists"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOuverturePortConfigForm, self).__init__( super(EditOuverturePortConfigForm, self).__init__(
*args, *args, prefix=prefix, **kwargs
prefix=prefix,
**kwargs
) )
@ -655,15 +674,11 @@ class EditOuverturePortListForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = OuverturePortList model = OuverturePortList
fields = '__all__' fields = "__all__"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOuverturePortListForm, self).__init__( super(EditOuverturePortListForm, self).__init__(*args, prefix=prefix, **kwargs)
*args,
prefix=prefix,
**kwargs
)
class SshFpForm(FormRevMixin, ModelForm): class SshFpForm(FormRevMixin, ModelForm):
@ -671,12 +686,8 @@ class SshFpForm(FormRevMixin, ModelForm):
class Meta: class Meta:
model = SshFp model = SshFp
exclude = ('machine',) exclude = ("machine",)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(SshFpForm, self).__init__( super(SshFpForm, self).__init__(*args, prefix=prefix, **kwargs)
*args,
prefix=prefix,
**kwargs
)

View file

@ -29,32 +29,50 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("users", "0005_auto_20160702_0006")]
('users', '0005_auto_20160702_0006'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Machine', name="Machine",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), (
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
)
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='MachineType', name="MachineType",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), (
('type', models.CharField(max_length=255)), "id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("type", models.CharField(max_length=255)),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='machine', model_name="machine",
name='type', name="type",
field=models.ForeignKey(to='machines.MachineType', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="machines.MachineType", on_delete=django.db.models.deletion.PROTECT
),
), ),
migrations.AddField( migrations.AddField(
model_name='machine', model_name="machine",
name='user', name="user",
field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="users.User", on_delete=django.db.models.deletion.PROTECT
),
), ),
] ]

View file

@ -30,36 +30,57 @@ import macaddress.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("machines", "0001_initial")]
('machines', '0001_initial'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Interface', name="Interface",
fields=[ fields=[
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), (
('ipv6', models.GenericIPAddressField(protocol='IPv6')), "id",
('mac_address', macaddress.fields.MACAddressField(integer=True)), models.AutoField(
('details', models.CharField(max_length=255)), serialize=False,
('name', models.CharField(max_length=255, blank=True, unique=True)), verbose_name="ID",
auto_created=True,
primary_key=True,
),
),
("ipv6", models.GenericIPAddressField(protocol="IPv6")),
("mac_address", macaddress.fields.MACAddressField(integer=True)),
("details", models.CharField(max_length=255)),
("name", models.CharField(max_length=255, blank=True, unique=True)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='IpList', name="IpList",
fields=[ fields=[
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), (
('ipv4', models.GenericIPAddressField(protocol='IPv4')), "id",
models.AutoField(
serialize=False,
verbose_name="ID",
auto_created=True,
primary_key=True,
),
),
("ipv4", models.GenericIPAddressField(protocol="IPv4")),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='interface', model_name="interface",
name='ipv4', name="ipv4",
field=models.OneToOneField(null=True, to='machines.IpList', blank=True, on_delete=django.db.models.deletion.PROTECT), field=models.OneToOneField(
null=True,
to="machines.IpList",
blank=True,
on_delete=django.db.models.deletion.PROTECT,
),
), ),
migrations.AddField( migrations.AddField(
model_name='interface', model_name="interface",
name='machine', name="machine",
field=models.ForeignKey(to='machines.Machine', on_delete=django.db.models.deletion.PROTECT), field=models.ForeignKey(
to="machines.Machine", on_delete=django.db.models.deletion.PROTECT
),
), ),
] ]

View file

@ -29,14 +29,12 @@ import macaddress.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("machines", "0002_auto_20160703_1444")]
('machines', '0002_auto_20160703_1444'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='interface', model_name="interface",
name='mac_address', name="mac_address",
field=macaddress.fields.MACAddressField(integer=True, unique=True), field=macaddress.fields.MACAddressField(integer=True, unique=True),
), )
] ]

View file

@ -28,14 +28,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("machines", "0003_auto_20160703_1450")]
('machines', '0003_auto_20160703_1450'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='iplist', model_name="iplist",
name='ipv4', name="ipv4",
field=models.GenericIPAddressField(protocol='IPv4', unique=True), field=models.GenericIPAddressField(protocol="IPv4", unique=True),
), )
] ]

View file

@ -28,19 +28,15 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("machines", "0004_auto_20160703_1451")]
('machines', '0004_auto_20160703_1451'),
]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(model_name="interface", old_name="name", new_name="dns"),
model_name='interface',
old_name='name',
new_name='dns',
),
migrations.AddField( migrations.AddField(
model_name='machine', model_name="machine",
name='name', name="name",
field=models.CharField(blank=True, unique=True, max_length=255, help_text='Optionnel'), field=models.CharField(
blank=True, unique=True, max_length=255, help_text="Optionnel"
),
), ),
] ]

Some files were not shown because too many files have changed in this diff Show more