base.py 8.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2018  Gabriel Détraz
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

# -*- coding: utf-8 -*-
"""
Regroupe les fonctions transversales utiles

Et non corrélées/dépendantes des autres applications
"""

import smtplib

from django.utils.translation import ugettext_lazy as _
32
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
33 34 35 36

from re2o.settings import EMAIL_HOST


37 38
# Mapping of srtftime format for better understanding
# https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
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",
    "%%": "%%",
64 65 66
}


67 68 69 70 71 72 73 74 75
def smtp_check(local_part):
    """Return True if the local_part is already taken
       False if available"""
    try:
        srv = smtplib.SMTP(EMAIL_HOST)
        srv.putcmd("vrfy", local_part)
        reply_code = srv.getreply()[0]
        srv.close()
        if reply_code in [250, 252]:
Laouen Fernet's avatar
Laouen Fernet committed
76
            return True, _("This domain is already taken.")
77
    except:
Laouen Fernet's avatar
Laouen Fernet committed
78
        return True, _("SMTP unreachable.")
79
    return False, None
80 81 82


def convert_datetime_format(format):
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
83
    i = 0
84 85
    new_format = ""
    while i < len(format):
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
86 87
        if format[i] == "%":
            char = format[i : i + 2]
88 89 90 91 92 93 94 95 96 97 98
            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:
99
        help_text_template = _("Format: {main} {more}")
100
    else:
101
        help_text_template = _("Format: {main}")
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
102
    more_text_template = '<i class="fa fa-question-circle" title="{}"></i>'
103 104 105
    help_text = help_text_template.format(
        main=convert_datetime_format(input_formats[0]),
        more=more_text_template.format(
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
106 107
            "\n".join(map(convert_datetime_format, input_formats))
        ),
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    )
    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 = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
126 127 128 129 130
        "user_name": ["name"],
        "user_surname": ["surname"],
        "user_pseudo": ["pseudo"],
        "user_room": ["room"],
        "default": ["state", "pseudo"],
131 132
    }
    USERS_INDEX_BAN = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
133 134 135 136
        "ban_user": ["user__pseudo"],
        "ban_start": ["date_start"],
        "ban_end": ["date_end"],
        "default": ["-date_end"],
137 138
    }
    USERS_INDEX_WHITE = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
139 140 141 142
        "white_user": ["user__pseudo"],
        "white_start": ["date_start"],
        "white_end": ["date_end"],
        "default": ["-date_end"],
143
    }
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
144 145
    USERS_INDEX_SCHOOL = {"school_name": ["name"], "default": ["name"]}
    MACHINES_INDEX = {"machine_name": ["name"], "default": ["pk"]}
146
    COTISATIONS_INDEX = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
147 148 149 150 151
        "cotis_user": ["user__pseudo"],
        "cotis_paiement": ["paiement__moyen"],
        "cotis_date": ["date"],
        "cotis_id": ["id"],
        "default": ["-date"],
152 153
    }
    COTISATIONS_CUSTOM = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
154 155 156 157 158 159
        "invoice_date": ["date"],
        "invoice_id": ["id"],
        "invoice_recipient": ["recipient"],
        "invoice_address": ["address"],
        "invoice_payment": ["payment"],
        "default": ["-date"],
160 161
    }
    COTISATIONS_CONTROL = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
162 163 164 165 166 167 168 169 170
        "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"],
171 172
    }
    TOPOLOGIE_INDEX = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
173 174 175 176 177 178
        "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"],
179 180
    }
    TOPOLOGIE_INDEX_PORT = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
181 182 183 184 185 186 187
        "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"],
188 189
    }
    TOPOLOGIE_INDEX_ROOM = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
190 191 192
        "room_name": ["name"],
        "building_name": ["building__name"],
        "default": ["building__name", "name"],
detraz's avatar
detraz committed
193
    }
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
194 195
    TOPOLOGIE_INDEX_BUILDING = {"building_name": ["name"], "default": ["name"]}
    TOPOLOGIE_INDEX_DORMITORY = {"dormitory_name": ["name"], "default": ["name"]}
196
    TOPOLOGIE_INDEX_BORNE = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
197 198 199 200
        "ap_name": ["interface__domain__name"],
        "ap_ip": ["interface__ipv4__ipv4"],
        "ap_mac": ["interface__mac_address"],
        "default": ["interface__domain__name"],
201 202
    }
    TOPOLOGIE_INDEX_STACK = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
203 204 205
        "stack_name": ["name"],
        "stack_id": ["stack_id"],
        "default": ["stack_id"],
206 207
    }
    TOPOLOGIE_INDEX_MODEL_SWITCH = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
208 209 210
        "model-switch_name": ["reference"],
        "model-switch_contructor": ["constructor__name"],
        "default": ["reference"],
211 212
    }
    TOPOLOGIE_INDEX_SWITCH_BAY = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
213 214 215
        "switch-bay_name": ["name"],
        "switch-bay_building": ["building__name"],
        "default": ["name"],
216 217
    }
    TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
218 219
        "constructor-switch_name": ["name"],
        "default": ["name"],
220 221
    }
    LOGS_INDEX = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
222 223
        "sum_date": ["revision__date_created"],
        "default": ["-revision__date_created"],
224 225
    }
    LOGS_STATS_LOGS = {
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
226 227 228
        "logs_author": ["user__name"],
        "logs_date": ["date_created"],
        "default": ["-date_created"],
229 230 231 232 233 234 235 236
    }

    @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:
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
237
            fields = values.get("default", [])
238
        request = request.order_by(*fields)
Hugo Levy-Falk's avatar
Hugo Levy-Falk committed
239
        if values.get(col, None) and order == "desc":
240 241 242 243 244
            return request.reverse()
        else:
            return request


245
def re2o_paginator(request, query_set, pagination_number, page_arg="page"):
246 247 248 249 250
    """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)
251
    page = request.GET.get(page_arg)
252 253 254 255 256 257 258 259 260
    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