utils.py 10.7 KB
Newer Older
chirac's avatar
chirac committed
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 32 33 34 35 36 37 38 39 40 41
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017  Gabriel Détraz
# Copyright © 2017  Goulven Kermarec
# Copyright © 2017  Augustin Lemesle
#
# 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 -*-
# David Sinquin, Gabriel Détraz, Goulven Kermarec
"""
Regroupe les fonctions transversales utiles

Fonction :
    - récupérer tous les utilisateurs actifs
    - récupérer toutes les machines
    - récupérer tous les bans
    etc
"""


from __future__ import unicode_literals


from django.utils import timezone
from django.db.models import Q
42 43
from django.contrib import messages
from django.shortcuts import redirect
44
from django.urls import reverse
45
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
chirac's avatar
chirac committed
46 47 48

from cotisations.models import Cotisation, Facture, Paiement, Vente
from machines.models import Domain, Interface, Machine
49
from users.models import Adherent, User, Ban, Whitelist
chirac's avatar
chirac committed
50 51 52
from preferences.models import Service


53
def all_adherent(search_time=None):
chirac's avatar
chirac committed
54 55 56 57
    """ Fonction renvoyant tous les users adherents. Optimisee pour n'est
    qu'une seule requete sql
    Inspecte les factures de l'user et ses cotisation, regarde si elles
    sont posterieur à now (end_time)"""
58 59
    if search_time is None:
        search_time = timezone.now()
chirac's avatar
chirac committed
60 61 62
    return User.objects.filter(
        facture__in=Facture.objects.filter(
            vente__in=Vente.objects.filter(
63
                Q(type_cotisation='All') | Q(type_cotisation='Adhesion'),
chirac's avatar
chirac committed
64 65 66 67 68 69 70 71 72 73
                cotisation__in=Cotisation.objects.filter(
                    vente__in=Vente.objects.filter(
                        facture__in=Facture.objects.all().exclude(valid=False)
                    )
                ).filter(date_end__gt=search_time)
            )
        )
    ).distinct()


74
def all_baned(search_time=None):
chirac's avatar
chirac committed
75
    """ Fonction renvoyant tous les users bannis """
76 77
    if search_time is None:
        search_time = timezone.now()
chirac's avatar
chirac committed
78 79 80 81 82 83 84
    return User.objects.filter(
        ban__in=Ban.objects.filter(
            date_end__gt=search_time
        )
    ).distinct()


85
def all_whitelisted(search_time=None):
chirac's avatar
chirac committed
86
    """ Fonction renvoyant tous les users whitelistes """
87 88
    if search_time is None:
        search_time = timezone.now()
chirac's avatar
chirac committed
89 90 91 92 93 94 95
    return User.objects.filter(
        whitelist__in=Whitelist.objects.filter(
            date_end__gt=search_time
        )
    ).distinct()


96
def all_has_access(search_time=None):
chirac's avatar
chirac committed
97 98
    """  Renvoie tous les users beneficiant d'une connexion
    : user adherent ou whiteliste et non banni """
99 100
    if search_time is None:
        search_time = timezone.now()
chirac's avatar
chirac committed
101 102 103 104 105 106 107
    return User.objects.filter(
        Q(state=User.STATE_ACTIVE) &
        ~Q(ban__in=Ban.objects.filter(date_end__gt=search_time)) &
        (Q(whitelist__in=Whitelist.objects.filter(date_end__gt=search_time)) |
         Q(facture__in=Facture.objects.filter(
             vente__in=Vente.objects.filter(
                 cotisation__in=Cotisation.objects.filter(
108
                     Q(type_cotisation='All') | Q(type_cotisation='Connexion'),
chirac's avatar
chirac committed
109 110 111 112 113 114 115 116 117 118
                     vente__in=Vente.objects.filter(
                         facture__in=Facture.objects.all()
                         .exclude(valid=False)
                     )
                 ).filter(date_end__gt=search_time)
             )
         )))
    ).distinct()


119 120 121
def filter_active_interfaces(interface_set):
    """Filtre les machines autorisées à sortir sur internet dans une requête"""
    return interface_set.filter(
chirac's avatar
chirac committed
122 123 124 125 126 127 128 129 130
        machine__in=Machine.objects.filter(
            user__in=all_has_access()
        ).filter(active=True)
    ).select_related('domain').select_related('machine')\
    .select_related('type').select_related('ipv4')\
    .select_related('domain__extension').select_related('ipv4__ip_type')\
    .distinct()


131 132 133 134 135 136
def filter_complete_interfaces(interface_set):
    """Appel la fonction précédente avec un prefetch_related ipv6 en plus"""
    return filter_active_interfaces(interface_set).prefetch_related('ipv6list')


def all_active_interfaces(full=False):
137
    """Renvoie l'ensemble des machines autorisées à sortir sur internet """
138 139 140 141
    if full:
        return filter_complete_interfaces(Interface.objects)
    else:
        return filter_active_interfaces(Interface.objects)
142 143


144
def all_active_assigned_interfaces(full=False):
chirac's avatar
chirac committed
145 146
    """ Renvoie l'ensemble des machines qui ont une ipv4 assignées et
    disposant de l'accès internet"""
147
    return all_active_interfaces(full=full).filter(ipv4__isnull=False)
chirac's avatar
chirac committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161


def all_active_interfaces_count():
    """ Version light seulement pour compter"""
    return Interface.objects.filter(
        machine__in=Machine.objects.filter(
            user__in=all_has_access()
        ).filter(active=True)
    )


def all_active_assigned_interfaces_count():
    """ Version light seulement pour compter"""
    return all_active_interfaces_count().filter(ipv4__isnull=False)
162 163 164 165 166 167

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 """

168
    # All the possible possible values
169
    # The naming convention is based on the URL or the views function
170 171 172 173 174
    # 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.
175
    USERS_INDEX = {
176 177 178 179
        'user_name': ['name'],
        'user_surname': ['surname'],
        'user_pseudo': ['pseudo'],
        'user_room': ['room'],
180
        'default': ['state', 'pseudo']
181 182
    }
    USERS_INDEX_BAN = {
183 184 185
        'ban_user': ['user__pseudo'],
        'ban_start': ['date_start'],
        'ban_end': ['date_end'],
186
        'default': ['-date_end']
187 188
    }
    USERS_INDEX_WHITE = {
189 190 191
        'white_user': ['user__pseudo'],
        'white_start': ['date_start'],
        'white_end': ['date_end'],
192
        'default': ['-date_end']
193
    }
194 195 196 197
    USERS_INDEX_SCHOOL = {
        'school_name': ['name'],
        'default': ['name']
    }
198
    MACHINES_INDEX = {
199
        'machine_name': ['name'],
200
        'default': ['pk']
201 202
    }
    COTISATIONS_INDEX = {
203 204 205
        'cotis_user': ['user__pseudo'],
        'cotis_paiement': ['paiement__moyen'],
        'cotis_date': ['date'],
206
        'cotis_id': ['id'],
207
        'default': ['-date']
208 209
    }
    COTISATIONS_CONTROL = {
210
        'control_name': ['user__adherent__name'],
211 212 213 214 215
        'control_surname': ['user__surname'],
        'control_paiement': ['paiement'],
        'control_date': ['date'],
        'control_valid': ['valid'],
        'control_control': ['control'],
216 217
        'control_id': ['id'],
        'control_user-id': ['user__id'],
218
        'default': ['-date']
219 220
    }
    TOPOLOGIE_INDEX = {
221 222
        'switch_dns': ['interface__domain__name'],
        'switch_ip': ['interface__ipv4__ipv4'],
223
        'switch_loc': ['switchbay__name'],
224 225
        'switch_ports': ['number'],
        'switch_stack': ['stack__name'],
226
        'default': ['switchbay', 'stack', 'stack_member_id']
227 228
    }
    TOPOLOGIE_INDEX_PORT = {
229 230 231 232 233 234
        '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'],
235
        'default': ['port']
236 237
    }
    TOPOLOGIE_INDEX_ROOM = {
238
        'room_name': ['name'],
239
        'default': ['name']
240
    }
241 242 243 244
    TOPOLOGIE_INDEX_BUILDING = {
        'building_name': ['name'],
        'default': ['name']
    }
245
    TOPOLOGIE_INDEX_BORNE = {
246 247 248 249
        'ap_name': ['interface__domain__name'],
        'ap_ip': ['interface__ipv4__ipv4'],
        'ap_mac': ['interface__mac_address'],
        'default': ['interface__domain__name']
250
    }
251
    TOPOLOGIE_INDEX_STACK = {
252 253
        'stack_name': ['name'],
        'stack_id': ['stack_id'],
254
        'default': ['stack_id'],
255
    }
256
    TOPOLOGIE_INDEX_MODEL_SWITCH = {
257 258
        'model-switch_name': ['reference'],
        'model-switch_contructor' : ['constructor__name'],
259 260
        'default': ['reference'],
    }
261 262 263 264 265
    TOPOLOGIE_INDEX_SWITCH_BAY = {
        'switch-bay_name': ['name'],
        'switch-bay_building': ['building__name'],
        'default': ['name'],
    }
266
    TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH = {
267
        'constructor-switch_name': ['name'],
268 269
        'default': ['name'],
    }
270
    LOGS_INDEX = {
271
        'sum_date': ['revision__date_created'],
272
        'default': ['-revision__date_created'],
273 274
    }
    LOGS_STATS_LOGS = {
275 276
        'logs_author': ['user__name'],
        'logs_date': ['date_created'],
277
        'default': ['-date_created']
278
    }
279 280

    @staticmethod
281
    def sort(request, col, order, values):
282 283
        """ Check if the given values are possible and add .order_by() and
        a .reverse() as specified according to those values """
284 285 286 287
        fields = values.get(col, None)
        if not fields:
            fields = values.get('default', [])
        request = request.order_by(*fields)
288
        if values.get(col, None) and order == 'desc':
289
            return request.reverse()
290
        else:
291
            return request
292

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
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
309 310 311 312 313 314 315 316 317

def remove_user_room(room):
    """ Déménage de force l'ancien locataire de la chambre """
    try:
        user = Adherent.objects.get(room=room)
    except Adherent.DoesNotExist:
        return
    user.room = None
    user.save()