diff --git a/cotisations/views.py b/cotisations/views.py index 4cd76f93..68118711 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -47,7 +47,10 @@ from users.models import User from re2o.settings import LOGO_PATH from re2o import settings from re2o.views import form -from re2o.utils import SortTable, re2o_paginator +from re2o.base import ( + SortTable, + re2o_paginator, +) from re2o.acl import ( can_create, can_edit, diff --git a/logs/views.py b/logs/views.py index 21e3c470..a54edd56 100644 --- a/logs/views.py +++ b/logs/views.py @@ -102,15 +102,18 @@ from re2o.utils import ( all_baned, all_has_access, all_adherent, + all_active_assigned_interfaces_count, + all_active_interfaces_count, +) +from re2o.base import ( re2o_paginator, + SortTable ) from re2o.acl import ( can_view_all, can_view_app, can_edit_history, ) -from re2o.utils import all_active_assigned_interfaces_count -from re2o.utils import all_active_interfaces_count, SortTable @login_required diff --git a/machines/views.py b/machines/views.py index 8d395749..59d4bd5a 100644 --- a/machines/views.py +++ b/machines/views.py @@ -55,6 +55,8 @@ from re2o.acl import ( from re2o.utils import ( all_active_assigned_interfaces, filter_active_interfaces, +) +from re2o.base import ( SortTable, re2o_paginator, ) diff --git a/re2o/base.py b/re2o/base.py index 539cc30f..023a16ff 100644 --- a/re2o/base.py +++ b/re2o/base.py @@ -29,10 +29,41 @@ Et non corrélées/dépendantes des autres applications import smtplib from django.utils.translation import ugettext_lazy as _ +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from re2o.settings import EMAIL_HOST +# Mapping of srtftime format for better understanding +# https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior +datetime_mapping={ + '%a': '%a', + '%A': '%A', + '%w': '%w', + '%d': 'dd', + '%b': '%b', + '%B': '%B', + '%m': 'mm', + '%y': 'yy', + '%Y': 'yyyy', + '%H': 'HH', + '%I': 'HH(12h)', + '%p': 'AMPM', + '%M': 'MM', + '%S': 'SS', + '%f': 'µµ', + '%z': 'UTC(+/-HHMM)', + '%Z': 'UTC(TZ)', + '%j': '%j', + '%U': 'ww', + '%W': 'ww', + '%c': '%c', + '%x': '%x', + '%X': '%X', + '%%': '%%', +} + + def smtp_check(local_part): """Return True if the local_part is already taken False if available""" @@ -46,3 +77,191 @@ def smtp_check(local_part): except: return True, _("Smtp unreachable") return False, None + + +def convert_datetime_format(format): + i=0 + new_format = "" + while i < len(format): + if format[i] == '%': + char = format[i:i+2] + new_format += datetime_mapping.get(char, char) + i += 2 + else: + new_format += format[i] + i += 1 + return new_format + + +def get_input_formats_help_text(input_formats): + """Returns a help text about the possible input formats""" + if len(input_formats) > 1: + help_text_template="Format: {main} {more}" + else: + help_text_template="Format: {main}" + more_text_template="" + help_text = help_text_template.format( + main=convert_datetime_format(input_formats[0]), + more=more_text_template.format( + '\n'.join(map(convert_datetime_format, input_formats)) + ) + ) + return help_text + + +class SortTable: + """ Class gathering uselful stuff to sort the colums of a table, according + to the column and order requested. It's used with a dict of possible + values and associated model_fields """ + + # All the possible possible values + # The naming convention is based on the URL or the views function + # The syntax to describe the sort to apply is a dict where the keys are + # the url value and the values are a list of model field name to use to + # order the request. They are applied in the order they are given. + # A 'default' might be provided to specify what to do if the requested col + # doesn't match any keys. + + USERS_INDEX = { + 'user_name': ['name'], + 'user_surname': ['surname'], + 'user_pseudo': ['pseudo'], + 'user_room': ['room'], + 'default': ['state', 'pseudo'] + } + USERS_INDEX_BAN = { + 'ban_user': ['user__pseudo'], + 'ban_start': ['date_start'], + 'ban_end': ['date_end'], + 'default': ['-date_end'] + } + USERS_INDEX_WHITE = { + 'white_user': ['user__pseudo'], + 'white_start': ['date_start'], + 'white_end': ['date_end'], + 'default': ['-date_end'] + } + USERS_INDEX_SCHOOL = { + 'school_name': ['name'], + 'default': ['name'] + } + MACHINES_INDEX = { + 'machine_name': ['name'], + 'default': ['pk'] + } + COTISATIONS_INDEX = { + 'cotis_user': ['user__pseudo'], + 'cotis_paiement': ['paiement__moyen'], + 'cotis_date': ['date'], + 'cotis_id': ['id'], + 'default': ['-date'] + } + COTISATIONS_CUSTOM = { + 'invoice_date': ['date'], + 'invoice_id': ['id'], + 'invoice_recipient': ['recipient'], + 'invoice_address': ['address'], + 'invoice_payment': ['payment'], + 'default': ['-date'] + } + COTISATIONS_CONTROL = { + 'control_name': ['user__adherent__name'], + 'control_surname': ['user__surname'], + 'control_paiement': ['paiement'], + 'control_date': ['date'], + 'control_valid': ['valid'], + 'control_control': ['control'], + 'control_id': ['id'], + 'control_user-id': ['user__id'], + 'default': ['-date'] + } + TOPOLOGIE_INDEX = { + 'switch_dns': ['interface__domain__name'], + 'switch_ip': ['interface__ipv4__ipv4'], + 'switch_loc': ['switchbay__name'], + 'switch_ports': ['number'], + 'switch_stack': ['stack__name'], + 'default': ['switchbay', 'stack', 'stack_member_id'] + } + TOPOLOGIE_INDEX_PORT = { + 'port_port': ['port'], + 'port_room': ['room__name'], + 'port_interface': ['machine_interface__domain__name'], + 'port_related': ['related__switch__name'], + 'port_radius': ['radius'], + 'port_vlan': ['vlan_force__name'], + 'default': ['port'] + } + TOPOLOGIE_INDEX_ROOM = { + 'room_name': ['name'], + 'default': ['name'] + } + TOPOLOGIE_INDEX_BUILDING = { + 'building_name': ['name'], + 'default': ['name'] + } + TOPOLOGIE_INDEX_BORNE = { + 'ap_name': ['interface__domain__name'], + 'ap_ip': ['interface__ipv4__ipv4'], + 'ap_mac': ['interface__mac_address'], + 'default': ['interface__domain__name'] + } + TOPOLOGIE_INDEX_STACK = { + 'stack_name': ['name'], + 'stack_id': ['stack_id'], + 'default': ['stack_id'], + } + TOPOLOGIE_INDEX_MODEL_SWITCH = { + 'model-switch_name': ['reference'], + 'model-switch_contructor': ['constructor__name'], + 'default': ['reference'], + } + TOPOLOGIE_INDEX_SWITCH_BAY = { + 'switch-bay_name': ['name'], + 'switch-bay_building': ['building__name'], + 'default': ['name'], + } + TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH = { + 'constructor-switch_name': ['name'], + 'default': ['name'], + } + LOGS_INDEX = { + 'sum_date': ['revision__date_created'], + 'default': ['-revision__date_created'], + } + LOGS_STATS_LOGS = { + 'logs_author': ['user__name'], + 'logs_date': ['date_created'], + 'default': ['-date_created'] + } + + @staticmethod + def sort(request, col, order, values): + """ Check if the given values are possible and add .order_by() and + a .reverse() as specified according to those values """ + fields = values.get(col, None) + if not fields: + fields = values.get('default', []) + request = request.order_by(*fields) + if values.get(col, None) and order == 'desc': + return request.reverse() + else: + return request + + +def re2o_paginator(request, query_set, pagination_number): + """Paginator script for list display in re2o. + :request: + :query_set: Query_set to paginate + :pagination_number: Number of entries to display""" + paginator = Paginator(query_set, pagination_number) + page = request.GET.get('page') + try: + results = paginator.page(page) + except PageNotAnInteger: + # If page is not an integer, deliver first page. + results = paginator.page(1) + except EmptyPage: + # If page is out of range (e.g. 9999), deliver last page of results. + results = paginator.page(paginator.num_pages) + return results diff --git a/re2o/utils.py b/re2o/utils.py index 6f7870f0..9836a98c 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -38,55 +38,11 @@ from __future__ import unicode_literals from django.utils import timezone from django.db.models import Q -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from cotisations.models import Cotisation, Facture, Vente from machines.models import Interface, Machine from users.models import Adherent, User, Ban, Whitelist -# Mapping of srtftime format for better understanding -# https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior -datetime_mapping={ - '%a': '%a', - '%A': '%A', - '%w': '%w', - '%d': 'dd', - '%b': '%b', - '%B': '%B', - '%m': 'mm', - '%y': 'yy', - '%Y': 'yyyy', - '%H': 'HH', - '%I': 'HH(12h)', - '%p': 'AMPM', - '%M': 'MM', - '%S': 'SS', - '%f': 'µµ', - '%z': 'UTC(+/-HHMM)', - '%Z': 'UTC(TZ)', - '%j': '%j', - '%U': 'ww', - '%W': 'ww', - '%c': '%c', - '%x': '%x', - '%X': '%X', - '%%': '%%', -} - - -def convert_datetime_format(format): - i=0 - new_format = "" - while i < len(format): - if format[i] == '%': - char = format[i:i+2] - new_format += datetime_mapping.get(char, char) - i += 2 - else: - new_format += format[i] - i += 1 - return new_format - def all_adherent(search_time=None): """ Fonction renvoyant tous les users adherents. Optimisee pour n'est @@ -203,164 +159,6 @@ def all_active_assigned_interfaces_count(): return all_active_interfaces_count().filter(ipv4__isnull=False) -class SortTable: - """ Class gathering uselful stuff to sort the colums of a table, according - to the column and order requested. It's used with a dict of possible - values and associated model_fields """ - - # All the possible possible values - # The naming convention is based on the URL or the views function - # The syntax to describe the sort to apply is a dict where the keys are - # the url value and the values are a list of model field name to use to - # order the request. They are applied in the order they are given. - # A 'default' might be provided to specify what to do if the requested col - # doesn't match any keys. - - USERS_INDEX = { - 'user_name': ['name'], - 'user_surname': ['surname'], - 'user_pseudo': ['pseudo'], - 'user_room': ['room'], - 'default': ['state', 'pseudo'] - } - USERS_INDEX_BAN = { - 'ban_user': ['user__pseudo'], - 'ban_start': ['date_start'], - 'ban_end': ['date_end'], - 'default': ['-date_end'] - } - USERS_INDEX_WHITE = { - 'white_user': ['user__pseudo'], - 'white_start': ['date_start'], - 'white_end': ['date_end'], - 'default': ['-date_end'] - } - USERS_INDEX_SCHOOL = { - 'school_name': ['name'], - 'default': ['name'] - } - MACHINES_INDEX = { - 'machine_name': ['name'], - 'default': ['pk'] - } - COTISATIONS_INDEX = { - 'cotis_user': ['user__pseudo'], - 'cotis_paiement': ['paiement__moyen'], - 'cotis_date': ['date'], - 'cotis_id': ['id'], - 'default': ['-date'] - } - COTISATIONS_CUSTOM = { - 'invoice_date': ['date'], - 'invoice_id': ['id'], - 'invoice_recipient': ['recipient'], - 'invoice_address': ['address'], - 'invoice_payment': ['payment'], - 'default': ['-date'] - } - COTISATIONS_CONTROL = { - 'control_name': ['user__adherent__name'], - 'control_surname': ['user__surname'], - 'control_paiement': ['paiement'], - 'control_date': ['date'], - 'control_valid': ['valid'], - 'control_control': ['control'], - 'control_id': ['id'], - 'control_user-id': ['user__id'], - 'default': ['-date'] - } - TOPOLOGIE_INDEX = { - 'switch_dns': ['interface__domain__name'], - 'switch_ip': ['interface__ipv4__ipv4'], - 'switch_loc': ['switchbay__name'], - 'switch_ports': ['number'], - 'switch_stack': ['stack__name'], - 'default': ['switchbay', 'stack', 'stack_member_id'] - } - TOPOLOGIE_INDEX_PORT = { - 'port_port': ['port'], - 'port_room': ['room__name'], - 'port_interface': ['machine_interface__domain__name'], - 'port_related': ['related__switch__name'], - 'port_radius': ['radius'], - 'port_vlan': ['vlan_force__name'], - 'default': ['port'] - } - TOPOLOGIE_INDEX_ROOM = { - 'room_name': ['name'], - 'default': ['name'] - } - TOPOLOGIE_INDEX_BUILDING = { - 'building_name': ['name'], - 'default': ['name'] - } - TOPOLOGIE_INDEX_BORNE = { - 'ap_name': ['interface__domain__name'], - 'ap_ip': ['interface__ipv4__ipv4'], - 'ap_mac': ['interface__mac_address'], - 'default': ['interface__domain__name'] - } - TOPOLOGIE_INDEX_STACK = { - 'stack_name': ['name'], - 'stack_id': ['stack_id'], - 'default': ['stack_id'], - } - TOPOLOGIE_INDEX_MODEL_SWITCH = { - 'model-switch_name': ['reference'], - 'model-switch_contructor': ['constructor__name'], - 'default': ['reference'], - } - TOPOLOGIE_INDEX_SWITCH_BAY = { - 'switch-bay_name': ['name'], - 'switch-bay_building': ['building__name'], - 'default': ['name'], - } - TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH = { - 'constructor-switch_name': ['name'], - 'default': ['name'], - } - LOGS_INDEX = { - 'sum_date': ['revision__date_created'], - 'default': ['-revision__date_created'], - } - LOGS_STATS_LOGS = { - 'logs_author': ['user__name'], - 'logs_date': ['date_created'], - 'default': ['-date_created'] - } - - @staticmethod - def sort(request, col, order, values): - """ Check if the given values are possible and add .order_by() and - a .reverse() as specified according to those values """ - fields = values.get(col, None) - if not fields: - fields = values.get('default', []) - request = request.order_by(*fields) - if values.get(col, None) and order == 'desc': - return request.reverse() - else: - return request - - -def re2o_paginator(request, query_set, pagination_number): - """Paginator script for list display in re2o. - :request: - :query_set: Query_set to paginate - :pagination_number: Number of entries to display""" - paginator = Paginator(query_set, pagination_number) - page = request.GET.get('page') - try: - results = paginator.page(page) - except PageNotAnInteger: - # If page is not an integer, deliver first page. - results = paginator.page(1) - except EmptyPage: - # If page is out of range (e.g. 9999), deliver last page of results. - results = paginator.page(paginator.num_pages) - return results - - def remove_user_room(room): """ Déménage de force l'ancien locataire de la chambre """ try: @@ -370,18 +168,3 @@ def remove_user_room(room): user.room = None user.save() - -def get_input_formats_help_text(input_formats): - """Returns a help text about the possible input formats""" - if len(input_formats) > 1: - help_text_template="Format: {main} {more}" - else: - help_text_template="Format: {main}" - more_text_template="" - help_text = help_text_template.format( - main=convert_datetime_format(input_formats[0]), - more=more_text_template.format( - '\n'.join(map(convert_datetime_format, input_formats)) - ) - ) - return help_text diff --git a/search/forms.py b/search/forms.py index 5c98415f..5fa5fca8 100644 --- a/search/forms.py +++ b/search/forms.py @@ -27,7 +27,7 @@ from __future__ import unicode_literals from django import forms from django.forms import Form from django.utils.translation import ugettext_lazy as _ -from re2o.utils import get_input_formats_help_text +from re2o.base import get_input_formats_help_text CHOICES_USER = ( ('0', _("Active")), diff --git a/search/views.py b/search/views.py index a92b0105..eb0027ec 100644 --- a/search/views.py +++ b/search/views.py @@ -46,7 +46,7 @@ from search.forms import ( CHOICES_AFF, initial_choices ) -from re2o.utils import SortTable +from re2o.base import SortTable from re2o.acl import can_view_all diff --git a/topologie/views.py b/topologie/views.py index 0bd0f6c2..a4db2dc6 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -48,7 +48,10 @@ from django.utils.translation import ugettext as _ import tempfile from users.views import form -from re2o.utils import re2o_paginator, SortTable +from re2o.base import ( + re2o_paginator, + SortTable, +) from re2o.acl import ( can_create, can_edit, diff --git a/users/forms.py b/users/forms.py index 7695e6fc..b96e3ad3 100644 --- a/users/forms.py +++ b/users/forms.py @@ -45,7 +45,8 @@ from django.utils.safestring import mark_safe from machines.models import Interface, Machine, Nas from topologie.models import Port from preferences.models import OptionalUser -from re2o.utils import remove_user_room, get_input_formats_help_text +from re2o.utils import remove_user_room +from re2o.base import get_input_formats_help_text from re2o.mixins import FormRevMixin from re2o.field_permissions import FieldPermissionFormMixin diff --git a/users/views.py b/users/views.py index a94a7927..060610f8 100644 --- a/users/views.py +++ b/users/views.py @@ -57,8 +57,10 @@ from preferences.models import OptionalUser, GeneralOption, AssoOption from re2o.views import form from re2o.utils import ( all_has_access, - SortTable, - re2o_paginator +) +from re2o.base import ( + re2o_paginator, + SortTable ) from re2o.acl import ( can_create,