views.py 20.2 KB
Newer Older
1
# -*- mode: python; coding: utf-8 -*-
Maël Kervella's avatar
Maël Kervella committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# 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 Maël Kervella
#
# 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.

22
"""Defines the views of the API
Maël Kervella's avatar
Maël Kervella committed
23

24 25 26
All views inherits the `rest_framework.views.APIview` to respect the
REST API requirements such as dealing with HTTP status code, format of
the response (JSON or other), the CSRF exempting, ...
Maël Kervella's avatar
Maël Kervella committed
27
"""
28

29
import datetime
30

31 32 33
from django.conf import settings
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
Maël Kervella's avatar
Maël Kervella committed
34
from rest_framework.response import Response
35
from rest_framework import viewsets, generics, views
Maël Kervella's avatar
Maël Kervella committed
36

Maël Kervella's avatar
Maël Kervella committed
37 38 39 40 41
import cotisations.models as cotisations
import machines.models as machines
import preferences.models as preferences
import topologie.models as topologie
import users.models as users
42
from re2o.utils import all_active_interfaces, all_has_access
43

Maël Kervella's avatar
Maël Kervella committed
44
from . import serializers
45
from .pagination import PageSizedPagination
46
from .permissions import ACLPermission
47

Maël Kervella's avatar
Maël Kervella committed
48

49
# COTISATIONS
50 51 52


class FactureViewSet(viewsets.ReadOnlyModelViewSet):
53 54
    """Exposes list and details of `cotisations.models.Facture` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
55 56
    queryset = cotisations.Facture.objects.all()
    serializer_class = serializers.FactureSerializer
57 58 59


class VenteViewSet(viewsets.ReadOnlyModelViewSet):
60 61
    """Exposes list and details of `cotisations.models.Vente` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
62 63
    queryset = cotisations.Vente.objects.all()
    serializer_class = serializers.VenteSerializer
64 65 66


class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
67 68
    """Exposes list and details of `cotisations.models.Article` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
69 70
    queryset = cotisations.Article.objects.all()
    serializer_class = serializers.ArticleSerializer
71 72 73


class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
74 75
    """Exposes list and details of `cotisations.models.Banque` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
76 77
    queryset = cotisations.Banque.objects.all()
    serializer_class = serializers.BanqueSerializer
78 79 80


class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
81 82
    """Exposes list and details of `cotisations.models.Paiement` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
83 84
    queryset = cotisations.Paiement.objects.all()
    serializer_class = serializers.PaiementSerializer
85 86 87


class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
88 89
    """Exposes list and details of `cotisations.models.Cotisation` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
90 91
    queryset = cotisations.Cotisation.objects.all()
    serializer_class = serializers.CotisationSerializer
92 93


94
# MACHINES
95 96 97


class MachineViewSet(viewsets.ReadOnlyModelViewSet):
98 99
    """Exposes list and details of `machines.models.Machine` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
100 101
    queryset = machines.Machine.objects.all()
    serializer_class = serializers.MachineSerializer
102 103 104


class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
105 106
    """Exposes list and details of `machines.models.MachineType` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
107 108
    queryset = machines.MachineType.objects.all()
    serializer_class = serializers.MachineTypeSerializer
109 110 111


class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
112 113
    """Exposes list and details of `machines.models.IpType` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
114 115
    queryset = machines.IpType.objects.all()
    serializer_class = serializers.IpTypeSerializer
116 117 118


class VlanViewSet(viewsets.ReadOnlyModelViewSet):
119 120
    """Exposes list and details of `machines.models.Vlan` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
121 122
    queryset = machines.Vlan.objects.all()
    serializer_class = serializers.VlanSerializer
123 124 125


class NasViewSet(viewsets.ReadOnlyModelViewSet):
126 127
    """Exposes list and details of `machines.models.Nas` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
128 129
    queryset = machines.Nas.objects.all()
    serializer_class = serializers.NasSerializer
130 131 132


class SOAViewSet(viewsets.ReadOnlyModelViewSet):
133 134
    """Exposes list and details of `machines.models.SOA` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
135 136
    queryset = machines.SOA.objects.all()
    serializer_class = serializers.SOASerializer
137 138 139


class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
140 141
    """Exposes list and details of `machines.models.Extension` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
142 143
    queryset = machines.Extension.objects.all()
    serializer_class = serializers.ExtensionSerializer
144 145 146


class MxViewSet(viewsets.ReadOnlyModelViewSet):
147 148
    """Exposes list and details of `machines.models.Mx` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
149 150
    queryset = machines.Mx.objects.all()
    serializer_class = serializers.MxSerializer
151 152 153


class NsViewSet(viewsets.ReadOnlyModelViewSet):
154 155
    """Exposes list and details of `machines.models.Ns` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
156 157
    queryset = machines.Ns.objects.all()
    serializer_class = serializers.NsSerializer
158 159 160


class TxtViewSet(viewsets.ReadOnlyModelViewSet):
161 162
    """Exposes list and details of `machines.models.Txt` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
163 164
    queryset = machines.Txt.objects.all()
    serializer_class = serializers.TxtSerializer
165 166 167 168 169 170

class DNameViewSet(viewsets.ReadOnlyModelViewSet):
    """Exposes list and details of `machines.models.DName` objects.
    """
    queryset = machines.DName.objects.all()
    serializer_class = serializers.DNameSerializer
171 172 173


class SrvViewSet(viewsets.ReadOnlyModelViewSet):
174 175
    """Exposes list and details of `machines.models.Srv` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
176 177
    queryset = machines.Srv.objects.all()
    serializer_class = serializers.SrvSerializer
178 179


180 181 182 183 184 185 186
class SshFpViewSet(viewsets.ReadOnlyModelViewSet):
    """Exposes list and details of `machines.models.SshFp` objects.
    """
    queryset = machines.SshFp.objects.all()
    serializer_class = serializers.SshFpSerializer


187
class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
188 189
    """Exposes list and details of `machines.models.Interface` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
190 191
    queryset = machines.Interface.objects.all()
    serializer_class = serializers.InterfaceSerializer
192 193 194


class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
195 196
    """Exposes list and details of `machines.models.Ipv6List` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
197 198
    queryset = machines.Ipv6List.objects.all()
    serializer_class = serializers.Ipv6ListSerializer
199 200 201


class DomainViewSet(viewsets.ReadOnlyModelViewSet):
202 203
    """Exposes list and details of `machines.models.Domain` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
204 205
    queryset = machines.Domain.objects.all()
    serializer_class = serializers.DomainSerializer
206 207 208


class IpListViewSet(viewsets.ReadOnlyModelViewSet):
209 210
    """Exposes list and details of `machines.models.IpList` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
211 212
    queryset = machines.IpList.objects.all()
    serializer_class = serializers.IpListSerializer
213 214 215


class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
216 217
    """Exposes list and details of `machines.models.Service` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
218 219
    queryset = machines.Service.objects.all()
    serializer_class = serializers.ServiceSerializer
220 221


222
class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet):
223 224
    """Exposes list and details of `machines.models.Service_link` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
225 226
    queryset = machines.Service_link.objects.all()
    serializer_class = serializers.ServiceLinkSerializer
227 228 229


class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
230 231 232
    """Exposes list and details of `machines.models.OuverturePortList`
    objects.
    """
Maël Kervella's avatar
Maël Kervella committed
233 234
    queryset = machines.OuverturePortList.objects.all()
    serializer_class = serializers.OuverturePortListSerializer
235 236 237


class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
238 239
    """Exposes list and details of `machines.models.OuverturePort` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
240 241
    queryset = machines.OuverturePort.objects.all()
    serializer_class = serializers.OuverturePortSerializer
242 243


244
# PREFERENCES
245 246
# Those views differ a bit because there is only one object
# to display, so we don't bother with the listing part
247

248
class OptionalUserView(generics.RetrieveAPIView):
249 250
    """Exposes details of `preferences.models.` settings.
    """
251 252 253 254 255 256 257 258 259
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.OptionalUser.can_view_all]}
    serializer_class = serializers.OptionalUserSerializer

    def get_object(self):
        return preferences.OptionalUser.objects.first()


class OptionalMachineView(generics.RetrieveAPIView):
260 261
    """Exposes details of `preferences.models.OptionalMachine` settings.
    """
262 263 264 265 266 267 268 269 270
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.OptionalMachine.can_view_all]}
    serializer_class = serializers.OptionalMachineSerializer

    def get_object(self):
        return preferences.OptionalMachine.objects.first()


class OptionalTopologieView(generics.RetrieveAPIView):
271 272
    """Exposes details of `preferences.models.OptionalTopologie` settings.
    """
273 274 275 276 277 278 279 280 281
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.OptionalTopologie.can_view_all]}
    serializer_class = serializers.OptionalTopologieSerializer

    def get_object(self):
        return preferences.OptionalTopologie.objects.first()


class GeneralOptionView(generics.RetrieveAPIView):
282 283
    """Exposes details of `preferences.models.GeneralOption` settings.
    """
284 285 286 287 288 289 290 291
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.GeneralOption.can_view_all]}
    serializer_class = serializers.GeneralOptionSerializer

    def get_object(self):
        return preferences.GeneralOption.objects.first()


292
class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet):
293 294
    """Exposes list and details of `preferences.models.Service` objects.
    """
295
    queryset = preferences.Service.objects.all()
296
    serializer_class = serializers.HomeServiceSerializer
297 298 299


class AssoOptionView(generics.RetrieveAPIView):
300 301
    """Exposes details of `preferences.models.AssoOption` settings.
    """
302 303 304 305 306 307 308 309 310
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.AssoOption.can_view_all]}
    serializer_class = serializers.AssoOptionSerializer

    def get_object(self):
        return preferences.AssoOption.objects.first()


class HomeOptionView(generics.RetrieveAPIView):
311 312
    """Exposes details of `preferences.models.HomeOption` settings.
    """
313 314 315 316 317 318 319 320 321
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.HomeOption.can_view_all]}
    serializer_class = serializers.HomeOptionSerializer

    def get_object(self):
        return preferences.HomeOption.objects.first()


class MailMessageOptionView(generics.RetrieveAPIView):
322 323
    """Exposes details of `preferences.models.MailMessageOption` settings.
    """
324 325 326 327 328 329
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [preferences.MailMessageOption.can_view_all]}
    serializer_class = serializers.MailMessageOptionSerializer

    def get_object(self):
        return preferences.MailMessageOption.objects.first()
330 331


332
# TOPOLOGIE
333 334 335


class StackViewSet(viewsets.ReadOnlyModelViewSet):
336 337
    """Exposes list and details of `topologie.models.Stack` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
338 339
    queryset = topologie.Stack.objects.all()
    serializer_class = serializers.StackSerializer
340 341 342


class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
343 344
    """Exposes list and details of `topologie.models.AccessPoint` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
345 346
    queryset = topologie.AccessPoint.objects.all()
    serializer_class = serializers.AccessPointSerializer
347 348 349


class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
350 351
    """Exposes list and details of `topologie.models.Switch` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
352 353
    queryset = topologie.Switch.objects.all()
    serializer_class = serializers.SwitchSerializer
354 355


356 357 358 359 360 361 362
class ServerViewSet(viewsets.ReadOnlyModelViewSet):
    """Exposes list and details of `topologie.models.Server` objects.
    """
    queryset = topologie.Server.objects.all()
    serializer_class = serializers.ServerSerializer


363
class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet):
364 365
    """Exposes list and details of `topologie.models.ModelSwitch` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
366 367
    queryset = topologie.ModelSwitch.objects.all()
    serializer_class = serializers.ModelSwitchSerializer
368 369 370


class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
371 372 373
    """Exposes list and details of `topologie.models.ConstructorSwitch`
    objects.
    """
Maël Kervella's avatar
Maël Kervella committed
374 375
    queryset = topologie.ConstructorSwitch.objects.all()
    serializer_class = serializers.ConstructorSwitchSerializer
376 377 378


class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
379 380
    """Exposes list and details of `topologie.models.SwitchBay` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
381 382
    queryset = topologie.SwitchBay.objects.all()
    serializer_class = serializers.SwitchBaySerializer
383 384 385


class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
386 387
    """Exposes list and details of `topologie.models.Building` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
388 389
    queryset = topologie.Building.objects.all()
    serializer_class = serializers.BuildingSerializer
390 391 392


class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
393 394
    """Exposes list and details of `topologie.models.Port` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
395 396
    queryset = topologie.Port.objects.all()
    serializer_class = serializers.SwitchPortSerializer
397 398 399


class RoomViewSet(viewsets.ReadOnlyModelViewSet):
400 401
    """Exposes list and details of `topologie.models.Room` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
402 403
    queryset = topologie.Room.objects.all()
    serializer_class = serializers.RoomSerializer
404 405


406 407 408 409 410 411
class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
    """Exposes list and details of `topologie.models.PortProfile` objects.
    """
    queryset = topologie.PortProfile.objects.all()
    serializer_class = serializers.PortProfileSerializer

412
# USER
413 414


Maël Kervella's avatar
Maël Kervella committed
415
class UserViewSet(viewsets.ReadOnlyModelViewSet):
416 417
    """Exposes list and details of `users.models.Users` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
418 419
    queryset = users.User.objects.all()
    serializer_class = serializers.UserSerializer
Maël Kervella's avatar
Maël Kervella committed
420 421 422


class ClubViewSet(viewsets.ReadOnlyModelViewSet):
423 424
    """Exposes list and details of `users.models.Club` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
425 426
    queryset = users.Club.objects.all()
    serializer_class = serializers.ClubSerializer
Maël Kervella's avatar
Maël Kervella committed
427 428 429


class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
430 431
    """Exposes list and details of `users.models.Adherent` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
432 433
    queryset = users.Adherent.objects.all()
    serializer_class = serializers.AdherentSerializer
Maël Kervella's avatar
Maël Kervella committed
434 435 436


class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
437 438
    """Exposes list and details of `users.models.ServiceUser` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
439 440
    queryset = users.ServiceUser.objects.all()
    serializer_class = serializers.ServiceUserSerializer
Maël Kervella's avatar
Maël Kervella committed
441 442 443


class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
444 445
    """Exposes list and details of `users.models.School` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
446 447
    queryset = users.School.objects.all()
    serializer_class = serializers.SchoolSerializer
Maël Kervella's avatar
Maël Kervella committed
448 449 450


class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
451 452
    """Exposes list and details of `users.models.ListRight` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
453 454
    queryset = users.ListRight.objects.all()
    serializer_class = serializers.ListRightSerializer
Maël Kervella's avatar
Maël Kervella committed
455 456 457


class ShellViewSet(viewsets.ReadOnlyModelViewSet):
458 459
    """Exposes list and details of `users.models.ListShell` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
460 461
    queryset = users.ListShell.objects.all()
    serializer_class = serializers.ShellSerializer
Maël Kervella's avatar
Maël Kervella committed
462 463 464


class BanViewSet(viewsets.ReadOnlyModelViewSet):
465 466
    """Exposes list and details of `users.models.Ban` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
467 468
    queryset = users.Ban.objects.all()
    serializer_class = serializers.BanSerializer
Maël Kervella's avatar
Maël Kervella committed
469 470 471


class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
472 473
    """Exposes list and details of `users.models.Whitelist` objects.
    """
Maël Kervella's avatar
Maël Kervella committed
474 475
    queryset = users.Whitelist.objects.all()
    serializer_class = serializers.WhitelistSerializer
Maël Kervella's avatar
Maël Kervella committed
476

477

478 479
class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet):
    """Exposes list and details of `users.models.EMailAddress` objects.
480
    """
481 482
    serializer_class = serializers.EMailAddressSerializer
    queryset = users.EMailAddress.objects.none()
483 484 485 486

    def get_queryset(self):
        if preferences.OptionalUser.get_cached_value(
            'local_email_accounts_enabled'):
487
            return (users.EMailAddress.objects
488 489
                    .filter(user__local_email_enabled=True))
        else:
490
            return users.EMailAddress.objects.none()
491 492


493
# SERVICE REGEN
494 495


496
class ServiceRegenViewSet(viewsets.ModelViewSet):
497 498
    """Exposes list and details of the services to regen
    """
499 500 501 502 503 504 505 506 507 508 509 510 511 512
    serializer_class = serializers.ServiceRegenSerializer

    def get_queryset(self):
        queryset = machines.Service_link.objects.select_related(
            'server__domain'
        ).select_related(
            'service'
        )
        if 'hostname' in self.request.GET:
            hostname = self.request.GET['hostname']
            queryset = queryset.filter(server__domain__name__iexact=hostname)
        return queryset


513
# LOCAL EMAILS
514 515


516 517
class LocalEmailUsersView(generics.ListAPIView):
    """Exposes all the aliases of the users that activated the internal address
518
    """
519
    serializer_class = serializers.LocalEmailUsersSerializer
520

521 522 523 524 525 526 527
    def get_queryset(self):
        if preferences.OptionalUser.get_cached_value(
            'local_email_accounts_enabled'):
            return (users.User.objects
                    .filter(local_email_enabled=True))
        else:
            return users.User.objects.none()
528 529


530
# DHCP
531

532

533
class HostMacIpView(generics.ListAPIView):
534 535 536
    """Exposes the associations between hostname, mac address and IPv4 in
    order to build the DHCP lease files.
    """
537 538 539 540
    queryset = all_active_interfaces()
    serializer_class = serializers.HostMacIpSerializer


541 542 543 544 545 546
#Firewall

class SubnetPortsOpenView(generics.ListAPIView):
    queryset = machines.IpType.objects.all()
    serializer_class = serializers.SubnetPortsOpenSerializer

547
# DNS
548

549

550
class DNSZonesView(generics.ListAPIView):
551
    """Exposes the detailed information about each extension (hostnames,
552 553
    IPs, DNS records, etc.) in order to build the DNS zone files.
    """
554 555 556 557 558 559 560 561
    queryset = (machines.Extension.objects
                .prefetch_related('soa')
                .prefetch_related('ns_set').prefetch_related('ns_set__ns')
                .prefetch_related('origin')
                .prefetch_related('mx_set').prefetch_related('mx_set__name')
                .prefetch_related('txt_set')
                .prefetch_related('srv_set').prefetch_related('srv_set__target')
                .all())
562 563 564
    serializer_class = serializers.DNSZonesSerializer


565
# MAILING
566 567 568


class StandardMailingView(views.APIView):
569 570 571
    """Exposes list and details of standard mailings (name and members) in
    order to building the corresponding mailing lists.
    """
572
    pagination_class = PageSizedPagination
573 574
    permission_classes = (ACLPermission, )
    perms_map = {'GET' : [users.User.can_view_all]}
575 576

    def get(self, request, format=None):
577
        adherents_data = serializers.MailingMemberSerializer(all_has_access(), many=True).data
578 579 580 581 582 583 584
        data = [{'name': 'adherents', 'members': adherents_data}]
        paginator = self.pagination_class()
        paginator.paginate_queryset(data, request)
        return paginator.get_paginated_response(data)


class ClubMailingView(generics.ListAPIView):
585 586 587
    """Exposes list and details of club mailings (name, members and admins) in
    order to build the corresponding mailing lists.
    """
588 589 590 591
    queryset = users.Club.objects.all()
    serializer_class = serializers.MailingSerializer


592 593 594
# TOKEN AUTHENTICATION


595
class ObtainExpiringAuthToken(ObtainAuthToken):
596 597 598 599 600 601
    """Exposes a view to obtain a authentication token.

    This view as the same behavior as the
    `rest_framework.auth_token.views.ObtainAuthToken` view except that the
    expiration time is send along with the token as an addtional information.
    """
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)

        token_duration = datetime.timedelta(
            seconds=settings.API_TOKEN_DURATION
        )
        utc_now = datetime.datetime.now(datetime.timezone.utc)
        if not created and token.created < utc_now - token_duration:
            token.delete()
            token = Token.objects.create(user=user)
            token.created = datetime.datetime.utcnow()
            token.save()

        return Response({
            'token': token.key,
620
            'expiration': token.created + token_duration
621
        })