views.py 56.6 KB
Newer Older
1
# -*- mode: python; coding: utf-8 -*-
2 3 4 5
# 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.
#
6
# Copyright © 2016-2018  Gabriel Détraz
7 8
# Copyright © 2017  Goulven Kermarec
# Copyright © 2017  Augustin Lemesle
9 10
# Copyright © 2017-2018  Maël Kervella
# Copyright © 2018  Charlie Jacomme
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#
# 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.

26
# App de gestion des machines pour re2o
Dalahro's avatar
Dalahro committed
27
# Gabriel Détraz, Augustin Lemesle
28
# Gplv2
29 30 31
"""machines.views
The views for the Machines app
"""
32 33 34

from __future__ import unicode_literals

35
from django.urls import reverse
Dalahro's avatar
Dalahro committed
36
from django.http import HttpResponse
37 38
from django.shortcuts import render, redirect
from django.contrib import messages
39
from django.contrib.auth.decorators import login_required, permission_required
40
from django.db.models import ProtectedError, F
41
from django.forms import modelformset_factory
Dalahro's avatar
Dalahro committed
42
from django.views.decorators.csrf import csrf_exempt
43

Dalahro's avatar
Dalahro committed
44
from rest_framework.renderers import JSONRenderer
45 46 47 48 49 50 51 52 53 54 55 56

from users.models import User
from preferences.models import GeneralOption
from re2o.utils import (
    all_active_assigned_interfaces,
    filter_active_interfaces,
    SortTable,
    re2o_paginator,
)
from re2o.acl import (
    can_create,
    can_edit,
57
    can_view,
58 59 60 61 62 63 64
    can_delete,
    can_view_all,
    can_delete_set,
)
from re2o.views import form

from .serializers import (
65
    FullInterfaceSerializer,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
66 67 68
    InterfaceSerializer,
    TypeSerializer,
    DomainSerializer,
Gabriel Detraz's avatar
Gabriel Detraz committed
69
    TxtSerializer,
Gabriel Detraz's avatar
Gabriel Detraz committed
70
    SrvSerializer,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
71 72 73 74 75
    MxSerializer,
    ExtensionSerializer,
    ServiceServersSerializer,
    NsSerializer,
)
Dalahro's avatar
Dalahro committed
76

LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
from .forms import (
    NewMachineForm,
    EditMachineForm,
    EditInterfaceForm,
    AddInterfaceForm,
    MachineTypeForm,
    DelMachineTypeForm,
    ExtensionForm,
    DelExtensionForm,
    EditIpTypeForm,
    IpTypeForm,
    DelIpTypeForm,
    DomainForm,
    AliasForm,
    DelAliasForm,
92 93
    SOAForm,
    DelSOAForm,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
94 95
    NsForm,
    DelNsForm,
96 97
    TxtForm,
    DelTxtForm,
Charlie Jacomme's avatar
Charlie Jacomme committed
98 99
    DNameForm,
    DelDNameForm,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
100 101 102 103 104 105
    MxForm,
    DelMxForm,
    VlanForm,
    DelVlanForm,
    ServiceForm,
    DelServiceForm,
106
    SshFpForm,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
107
    NasForm,
Gabriel Detraz's avatar
Gabriel Detraz committed
108 109 110
    DelNasForm,
    SrvForm,
    DelSrvForm,
111
    Ipv6ListForm,
112
    EditOuverturePortListForm,
113
    EditOuverturePortConfigForm,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
114 115 116 117 118 119 120
)
from .models import (
    IpType,
    Machine,
    Interface,
    MachineType,
    Extension,
121
    SOA,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
122 123 124 125 126 127 128
    Mx,
    Ns,
    Domain,
    Service,
    Service_link,
    Vlan,
    Nas,
Gabriel Detraz's avatar
Gabriel Detraz committed
129
    Txt,
Charlie Jacomme's avatar
Charlie Jacomme committed
130
    DName,
Gabriel Detraz's avatar
Gabriel Detraz committed
131
    Srv,
132
    SshFp,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
133
    OuverturePortList,
Gabriel Detraz's avatar
Gabriel Detraz committed
134
    OuverturePort,
135
    Ipv6List,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
136
)
137

138 139

def f_type_id(is_type_tt):
140 141 142
    """ The id that will be used in HTML to store the value of the field
    type. Depends on the fact that type is generate using typeahead or not
    """
143
    return 'id_Interface-type_hidden' if is_type_tt else 'id_Interface-type'
144

145

146
def generate_ipv4_choices(form_obj):
147
    """ Generate the parameter choices for the massive_bootstrap_form tag
148
    """
149
    f_ipv4 = form_obj.fields['ipv4']
150
    used_mtype_id = []
151
    choices = '{"":[{key:"",value:"Choisissez d\'abord un type de machine"},'
152 153
    mtype_id = -1

154 155 156 157
    for ip in (f_ipv4.queryset
               .annotate(mtype_id=F('ip_type__machinetype__id'))
               .order_by('mtype_id', 'id')):
        if mtype_id != ip.mtype_id:
158 159
            mtype_id = ip.mtype_id
            used_mtype_id.append(mtype_id)
160
            choices += '],"{t}":[{{key:"",value:"{v}"}},'.format(
161 162
                t=mtype_id,
                v=f_ipv4.empty_label or '""'
163 164
            )
        choices += '{{key:{k},value:"{v}"}},'.format(
165 166
            k=ip.id,
            v=ip.ipv4
167
        )
168

169
    for t in form_obj.fields['type'].queryset.exclude(id__in=used_mtype_id):
170 171 172 173 174
        choices += '], "'+str(t.id)+'": ['
        choices += '{key: "", value: "' + str(f_ipv4.empty_label) + '"},'
    choices += ']}'
    return choices

175 176

def generate_ipv4_engine(is_type_tt):
177
    """ Generate the parameter engine for the massive_bootstrap_form tag
178
    """
179 180 181 182 183 184 185 186
    return (
        'new Bloodhound( {{'
            'datumTokenizer: Bloodhound.tokenizers.obj.whitespace( "value" ),'
            'queryTokenizer: Bloodhound.tokenizers.whitespace,'
            'local: choices_ipv4[ $( "#{type_id}" ).val() ],'
            'identify: function( obj ) {{ return obj.key; }}'
        '}} )'
        ).format(
187
            type_id=f_type_id(is_type_tt)
188
        )
189

190 191

def generate_ipv4_match_func(is_type_tt):
192
    """ Generate the parameter match_func for the massive_bootstrap_form tag
193
    """
194 195 196 197 198 199 200 201 202 203 204
    return (
        'function(q, sync) {{'
            'if (q === "") {{'
                'var first = choices_ipv4[$("#{type_id}").val()].slice(0, 5);'
                'first = first.map( function (obj) {{ return obj.key; }} );'
                'sync(engine_ipv4.get(first));'
            '}} else {{'
                'engine_ipv4.search(q, sync);'
            '}}'
        '}}'
        ).format(
205
            type_id=f_type_id(is_type_tt)
206
        )
207

208

209
def generate_ipv4_mbf_param(form_obj, is_type_tt):
210
    """ Generate all the parameters to use with the massive_bootstrap_form
211
    tag """
212
    i_choices = {'ipv4': generate_ipv4_choices(form_obj)}
213 214 215 216
    i_engine = {'ipv4': generate_ipv4_engine(is_type_tt)}
    i_match_func = {'ipv4': generate_ipv4_match_func(is_type_tt)}
    i_update_on = {'ipv4': [f_type_id(is_type_tt)]}
    i_gen_select = {'ipv4': False}
217
    i_mbf_param = {
218 219 220
        'choices': i_choices,
        'engine': i_engine,
        'match_func': i_match_func,
Maël Kervella's avatar
Maël Kervella committed
221 222
        'update_on': i_update_on,
        'gen_select': i_gen_select
223
    }
224
    return i_mbf_param
225

226

chirac's avatar
chirac committed
227
@login_required
228
@can_create(Machine)
229
@can_edit(User)
230
def new_machine(request, user, **_kwargs):
231
    """ Fonction de creation d'une machine. Cree l'objet machine,
LEVY-FALK Hugo's avatar
LEVY-FALK Hugo committed
232
    le sous objet interface et l'objet domain à partir de model forms.
Gabriel Detraz's avatar
Gabriel Detraz committed
233
    Trop complexe, devrait être simplifié"""
Maël Kervella's avatar
Maël Kervella committed
234

235
    machine = NewMachineForm(request.POST or None, user=request.user)
Maël Kervella's avatar
Maël Kervella committed
236 237
    interface = AddInterfaceForm(
        request.POST or None,
238
        user=request.user
Maël Kervella's avatar
Maël Kervella committed
239
    )
240
    domain = DomainForm(request.POST or None, user=user)
241
    if machine.is_valid() and interface.is_valid():
242 243 244 245
        new_machine_obj = machine.save(commit=False)
        new_machine_obj.user = user
        new_interface_obj = interface.save(commit=False)
        domain.instance.interface_parent = new_interface_obj
246
        if domain.is_valid():
247
            new_domain = domain.save(commit=False)
248 249 250 251
            new_machine_obj.save()
            new_interface_obj.machine = new_machine_obj
            new_interface_obj.save()
            new_domain.interface_parent = new_interface_obj
252
            new_domain.save()
guimoz's avatar
guimoz committed
253
            messages.success(request, "La machine a été créée")
254 255
            return redirect(reverse(
                'users:profil',
256
                kwargs={'userid': str(user.id)}
Maël Kervella's avatar
Maël Kervella committed
257 258 259 260 261 262 263
            ))
    i_mbf_param = generate_ipv4_mbf_param(interface, False)
    return form(
        {
            'machineform': machine,
            'interfaceform': interface,
            'domainform': domain,
264
            'i_mbf_param': i_mbf_param,
265
            'action_name': 'Créer une machine'
Maël Kervella's avatar
Maël Kervella committed
266 267 268 269
        },
        'machines/machine.html',
        request
    )
270

271

chirac's avatar
chirac committed
272
@login_required
273
@can_edit(Interface)
274
def edit_interface(request, interface_instance, **_kwargs):
275 276 277
    """ Edition d'une interface. Distingue suivant les droits les valeurs
    de interfaces et machines que l'user peut modifier infra permet de
    modifier le propriétaire"""
278

279 280 281 282 283
    machine_form = EditMachineForm(
        request.POST or None,
        instance=interface_instance.machine,
        user=request.user
    )
284 285 286 287 288 289 290 291 292 293 294 295
    interface_form = EditInterfaceForm(
        request.POST or None,
        instance=interface_instance,
        user=request.user
    )
    domain_form = DomainForm(
        request.POST or None,
        instance=interface_instance.domain
    )
    if (machine_form.is_valid() and
            interface_form.is_valid() and
            domain_form.is_valid()):
296 297 298
        new_machine_obj = machine_form.save(commit=False)
        new_interface_obj = interface_form.save(commit=False)
        new_domain_obj = domain_form.save(commit=False)
299
        if machine_form.changed_data:
300
            new_machine_obj.save()
301
        if interface_form.changed_data:
302
            new_interface_obj.save()
303
        if domain_form.changed_data:
304
            new_domain_obj.save()
305
        messages.success(request, "La machine a été modifiée")
306 307
        return redirect(reverse(
            'users:profil',
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
            kwargs={'userid': str(interface_instance.machine.user.id)}
        ))
    i_mbf_param = generate_ipv4_mbf_param(interface_form, False)
    return form(
        {
            'machineform': machine_form,
            'interfaceform': interface_form,
            'domainform': domain_form,
            'i_mbf_param': i_mbf_param,
            'action_name': 'Editer une interface'
        },
        'machines/machine.html',
        request
    )

323

324
@login_required
325
@can_delete(Machine)
326
def del_machine(request, machine, **_kwargs):
Gabriel Detraz's avatar
Gabriel Detraz committed
327
    """ Supprime une machine, interfaces en mode cascade"""
328
    if request.method == "POST":
329
        machine.delete()
330
        messages.success(request, "La machine a été détruite")
331 332
        return redirect(reverse(
            'users:profil',
333 334 335 336 337 338 339 340
            kwargs={'userid': str(machine.user.id)}
        ))
    return form(
        {'objet': machine, 'objet_name': 'machine'},
        'machines/delete.html',
        request
    )

341

chirac's avatar
chirac committed
342
@login_required
343
@can_create(Interface)
344
@can_edit(Machine)
345
def new_interface(request, machine, **_kwargs):
Gabriel Detraz's avatar
Gabriel Detraz committed
346
    """ Ajoute une interface et son domain associé à une machine existante"""
347

348
    interface_form = AddInterfaceForm(request.POST or None, user=request.user)
349
    domain_form = DomainForm(request.POST or None)
350
    if interface_form.is_valid():
351 352 353
        new_interface_obj = interface_form.save(commit=False)
        domain_form.instance.interface_parent = new_interface_obj
        new_interface_obj.machine = machine
354
        if domain_form.is_valid():
355 356 357 358
            new_domain_obj = domain_form.save(commit=False)
            new_interface_obj.save()
            new_domain_obj.interface_parent = new_interface_obj
            new_domain_obj.save()
359
            messages.success(request, "L'interface a été ajoutée")
360 361
            return redirect(reverse(
                'users:profil',
362 363 364 365 366 367 368 369 370 371 372 373 374 375
                kwargs={'userid': str(machine.user.id)}
            ))
    i_mbf_param = generate_ipv4_mbf_param(interface_form, False)
    return form(
        {
            'interfaceform': interface_form,
            'domainform': domain_form,
            'i_mbf_param': i_mbf_param,
            'action_name': 'Créer une interface'
        },
        'machines/machine.html',
        request
    )

376

377
@login_required
378
@can_delete(Interface)
379
def del_interface(request, interface, **_kwargs):
Gabriel Detraz's avatar
Gabriel Detraz committed
380
    """ Supprime une interface. Domain objet en mode cascade"""
381
    if request.method == "POST":
382
        machine = interface.machine
383 384 385
        interface.delete()
        if not machine.interface_set.all():
            machine.delete()
386
        messages.success(request, "L'interface a été détruite")
387 388
        return redirect(reverse(
            'users:profil',
389 390 391 392 393 394 395 396
            kwargs={'userid': str(request.user.id)}
        ))
    return form(
        {'objet': interface, 'objet_name': 'interface'},
        'machines/delete.html',
        request
    )

397

398 399 400
@login_required
@can_create(Ipv6List)
@can_edit(Interface)
401
def new_ipv6list(request, interface, **_kwargs):
402
    """Nouvelle ipv6"""
403
    ipv6list_instance = Ipv6List(interface=interface)
404 405 406 407 408
    ipv6 = Ipv6ListForm(
        request.POST or None,
        instance=ipv6list_instance,
        user=request.user
    )
409
    if ipv6.is_valid():
410
        ipv6.save()
411 412 413
        messages.success(request, "Ipv6 ajoutée")
        return redirect(reverse(
            'machines:index-ipv6',
414 415 416 417 418 419 420 421
            kwargs={'interfaceid': str(interface.id)}
        ))
    return form(
        {'ipv6form': ipv6, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

422 423 424

@login_required
@can_edit(Ipv6List)
425
def edit_ipv6list(request, ipv6list_instance, **_kwargs):
426
    """Edition d'une ipv6"""
427 428 429 430 431
    ipv6 = Ipv6ListForm(
        request.POST or None,
        instance=ipv6list_instance,
        user=request.user
    )
432
    if ipv6.is_valid():
433 434 435
        if ipv6.changed_data:
            ipv6.save()
            messages.success(request, "Ipv6 modifiée")
436 437
        return redirect(reverse(
            'machines:index-ipv6',
438 439 440 441 442 443 444 445
            kwargs={'interfaceid': str(ipv6list_instance.interface.id)}
        ))
    return form(
        {'ipv6form': ipv6, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

446 447 448

@login_required
@can_delete(Ipv6List)
449
def del_ipv6list(request, ipv6list, **_kwargs):
450 451 452
    """ Supprime une ipv6"""
    if request.method == "POST":
        interfaceid = ipv6list.interface.id
453
        ipv6list.delete()
454 455 456
        messages.success(request, "L'ipv6 a été détruite")
        return redirect(reverse(
            'machines:index-ipv6',
457 458 459 460 461 462 463 464
            kwargs={'interfaceid': str(interfaceid)}
        ))
    return form(
        {'objet': ipv6list, 'objet_name': 'ipv6'},
        'machines/delete.html',
        request
    )

465

466
@login_required
467
@can_create(SshFp)
468
@can_edit(Machine)
469 470 471 472
def new_sshfp(request, machine, **_kwargs):
    """Creates an SSHFP record associated with a machine"""
    sshfp_instance = SshFp(machine=machine)
    sshfp = SshFpForm(
473
        request.POST or None,
474
        instance=sshfp_instance
475
    )
476 477 478
    if sshfp.is_valid():
        sshfp.save()
        messages.success(request, "The SSHFP record was added")
479
        return redirect(reverse(
480
            'machines:index-sshfp',
481
            kwargs={'machineid': str(machine.id)}
482 483
        ))
    return form(
484
        {'sshfpform': sshfp, 'action_name': 'Create'},
485 486 487 488 489 490
        'machines/machine.html',
        request
    )


@login_required
491 492 493 494
@can_edit(SshFp)
def edit_sshfp(request, sshfp_instance, **_kwargs):
    """Edits an SSHFP record"""
    sshfp = SshFpForm(
495
        request.POST or None,
496
        instance=sshfp_instance
497
    )
498 499 500 501
    if sshfp.is_valid():
        if sshfp.changed_data:
            sshfp.save()
            messages.success(request, "The SSHFP record was edited")
502
        return redirect(reverse(
503 504
            'machines:index-sshfp',
            kwargs={'machineid': str(sshfp_instance.machine.id)}
505 506
        ))
    return form(
507
        {'sshfpform': sshfp, 'action_name': 'Edit'},
508 509 510 511 512 513
        'machines/machine.html',
        request
    )


@login_required
514 515 516
@can_delete(SshFp)
def del_sshfp(request, sshfp, **_kwargs):
    """Deletes an SSHFP record"""
517
    if request.method == "POST":
518 519 520
        machineid = sshfp.machine.id
        sshfp.delete()
        messages.success(request, "The SSHFP record was deleted")
521
        return redirect(reverse(
522
            'machines:index-sshfp',
523 524 525
            kwargs={'machineid': str(machineid)}
        ))
    return form(
526
        {'objet': sshfp, 'objet_name': 'sshfp'},
527 528 529 530 531
        'machines/delete.html',
        request
    )


532
@login_required
533
@can_create(IpType)
534
def add_iptype(request):
535 536
    """ Ajoute un range d'ip. Intelligence dans le models, fonction views
    minimaliste"""
537

538 539
    iptype = IpTypeForm(request.POST or None)
    if iptype.is_valid():
540
        iptype.save()
541
        messages.success(request, "Ce type d'ip a été ajouté")
542
        return redirect(reverse('machines:index-iptype'))
543 544 545 546 547 548
    return form(
        {'iptypeform': iptype, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

549 550

@login_required
551
@can_edit(IpType)
552
def edit_iptype(request, iptype_instance, **_kwargs):
553 554
    """ Edition d'un range. Ne permet pas de le redimensionner pour éviter
    l'incohérence"""
555

556
    iptype = EditIpTypeForm(request.POST or None, instance=iptype_instance)
557
    if iptype.is_valid():
558 559 560
        if iptype.changed_data:
            iptype.save()
            messages.success(request, "Type d'ip modifié")
561
        return redirect(reverse('machines:index-iptype'))
562 563 564 565 566 567
    return form(
        {'iptypeform': iptype, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

568 569

@login_required
570 571
@can_delete_set(IpType)
def del_iptype(request, instances):
Gabriel Detraz's avatar
Gabriel Detraz committed
572
    """ Suppression d'un range ip. Supprime les objets ip associés"""
573
    iptype = DelIpTypeForm(request.POST or None, instances=instances)
574 575 576 577
    if iptype.is_valid():
        iptype_dels = iptype.cleaned_data['iptypes']
        for iptype_del in iptype_dels:
            try:
578
                iptype_del.delete()
579 580
                messages.success(request, "Le type d'ip a été supprimé")
            except ProtectedError:
581 582 583 584 585
                messages.error(
                    request,
                    ("Le type d'ip %s est affectée à au moins une machine, "
                     "vous ne pouvez pas le supprimer" % iptype_del)
                )
586
        return redirect(reverse('machines:index-iptype'))
587 588 589 590 591 592
    return form(
        {'iptypeform': iptype, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

593

chirac's avatar
chirac committed
594
@login_required
595
@can_create(MachineType)
596
def add_machinetype(request):
597
    """ View used to add a Machinetype object """
598 599
    machinetype = MachineTypeForm(request.POST or None)
    if machinetype.is_valid():
600
        machinetype.save()
601
        messages.success(request, "Ce type de machine a été ajouté")
602
        return redirect(reverse('machines:index-machinetype'))
603 604 605 606 607 608
    return form(
        {'machinetypeform': machinetype, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

609

chirac's avatar
chirac committed
610
@login_required
611
@can_edit(MachineType)
612
def edit_machinetype(request, machinetype_instance, **_kwargs):
613
    """ View used to edit a MachineType object """
614 615 616 617
    machinetype = MachineTypeForm(
        request.POST or None,
        instance=machinetype_instance
    )
618
    if machinetype.is_valid():
619 620 621
        if machinetype.changed_data:
            machinetype.save()
            messages.success(request, "Type de machine modifié")
622
        return redirect(reverse('machines:index-machinetype'))
623 624 625 626 627 628
    return form(
        {'machinetypeform': machinetype, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

629

chirac's avatar
chirac committed
630
@login_required
631 632
@can_delete_set(MachineType)
def del_machinetype(request, instances):
633
    """ View used to delete a MachineType object """
634
    machinetype = DelMachineTypeForm(request.POST or None, instances=instances)
635 636 637 638
    if machinetype.is_valid():
        machinetype_dels = machinetype.cleaned_data['machinetypes']
        for machinetype_del in machinetype_dels:
            try:
639
                machinetype_del.delete()
640 641
                messages.success(request, "Le type de machine a été supprimé")
            except ProtectedError:
642 643 644 645 646 647
                messages.error(
                    request,
                    ("Le type de machine %s est affectée à au moins une "
                     "machine, vous ne pouvez pas le supprimer"
                     % machinetype_del)
                )
648
        return redirect(reverse('machines:index-machinetype'))
649 650 651 652 653 654
    return form(
        {'machinetypeform': machinetype, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

655

656
@login_required
657
@can_create(Extension)
658
def add_extension(request):
659
    """ View used to add an Extension object """
660 661
    extension = ExtensionForm(request.POST or None)
    if extension.is_valid():
662
        extension.save()
663
        messages.success(request, "Cette extension a été ajoutée")
664
        return redirect(reverse('machines:index-extension'))
665 666 667 668 669 670
    return form(
        {'extensionform': extension, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

671 672

@login_required
673
@can_edit(Extension)
674
def edit_extension(request, extension_instance, **_kwargs):
675
    """ View used to edit an Extension object """
676 677 678 679
    extension = ExtensionForm(
        request.POST or None,
        instance=extension_instance
    )
680
    if extension.is_valid():
681 682 683
        if extension.changed_data:
            extension.save()
            messages.success(request, "Extension modifiée")
684
        return redirect(reverse('machines:index-extension'))
685 686 687 688 689 690
    return form(
        {'extensionform': extension, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

691 692

@login_required
693 694
@can_delete_set(Extension)
def del_extension(request, instances):
695
    """ View used to delete an Extension object """
696
    extension = DelExtensionForm(request.POST or None, instances=instances)
697 698 699 700
    if extension.is_valid():
        extension_dels = extension.cleaned_data['extensions']
        for extension_del in extension_dels:
            try:
701
                extension_del.delete()
702 703
                messages.success(request, "L'extension a été supprimée")
            except ProtectedError:
704 705 706 707 708 709
                messages.error(
                    request,
                    ("L'extension %s est affectée à au moins un type de "
                     "machine, vous ne pouvez pas la supprimer"
                     % extension_del)
                )
710
        return redirect(reverse('machines:index-extension'))
711 712 713 714 715 716
    return form(
        {'extensionform': extension, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

717

718
@login_required
719
@can_create(SOA)
720
def add_soa(request):
721
    """ View used to add a SOA object """
722 723
    soa = SOAForm(request.POST or None)
    if soa.is_valid():
724
        soa.save()
725
        messages.success(request, "Cet enregistrement SOA a été ajouté")
726
        return redirect(reverse('machines:index-extension'))
727 728 729 730 731 732
    return form(
        {'soaform': soa, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

733 734

@login_required
735
@can_edit(SOA)
736
def edit_soa(request, soa_instance, **_kwargs):
737
    """ View used to edit a SOA object """
738 739
    soa = SOAForm(request.POST or None, instance=soa_instance)
    if soa.is_valid():
740 741 742
        if soa.changed_data:
            soa.save()
            messages.success(request, "SOA modifié")
743
        return redirect(reverse('machines:index-extension'))
744 745 746 747 748 749
    return form(
        {'soaform': soa, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

750 751

@login_required
752 753
@can_delete_set(SOA)
def del_soa(request, instances):
754
    """ View used to delete a SOA object """
755
    soa = DelSOAForm(request.POST or None, instances=instances)
756 757 758 759
    if soa.is_valid():
        soa_dels = soa.cleaned_data['soa']
        for soa_del in soa_dels:
            try:
760
                soa_del.delete()
761 762
                messages.success(request, "Le SOA a été supprimée")
            except ProtectedError:
763 764 765 766 767
                messages.error(
                    request,
                    ("Erreur le SOA suivant %s ne peut être supprimé"
                     % soa_del)
                )
768
        return redirect(reverse('machines:index-extension'))
769 770 771 772 773 774
    return form(
        {'soaform': soa, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

775

776
@login_required
777
@can_create(Mx)
778
def add_mx(request):
779
    """ View used to add a MX object """
780 781
    mx = MxForm(request.POST or None)
    if mx.is_valid():
782
        mx.save()
783
        messages.success(request, "Cet enregistrement mx a été ajouté")
784
        return redirect(reverse('machines:index-extension'))
785 786 787 788 789 790
    return form(
        {'mxform': mx, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

791 792

@login_required
793
@can_edit(Mx)
794
def edit_mx(request, mx_instance, **_kwargs):
795
    """ View used to edit a MX object """
796 797
    mx = MxForm(request.POST or None, instance=mx_instance)
    if mx.is_valid():
798 799 800
        if mx.changed_data:
            mx.save()
            messages.success(request, "Mx modifié")
801
        return redirect(reverse('machines:index-extension'))
802 803 804 805 806 807
    return form(
        {'mxform': mx, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

808 809

@login_required
810 811
@can_delete_set(Mx)
def del_mx(request, instances):
812
    """ View used to delete a MX object """
813
    mx = DelMxForm(request.POST or None, instances=instances)
814 815 816 817
    if mx.is_valid():
        mx_dels = mx.cleaned_data['mx']
        for mx_del in mx_dels:
            try:
818
                mx_del.delete()
819 820
                messages.success(request, "L'mx a été supprimée")
            except ProtectedError:
821 822 823 824 825
                messages.error(
                    request,
                    ("Erreur le Mx suivant %s ne peut être supprimé"
                     % mx_del)
                )
826
        return redirect(reverse('machines:index-extension'))
827 828 829 830 831 832
    return form(
        {'mxform': mx, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

833

834
@login_required
835
@can_create(Ns)
836
def add_ns(request):
837
    """ View used to add a NS object """
838 839
    ns = NsForm(request.POST or None)
    if ns.is_valid():
840
        ns.save()
841
        messages.success(request, "Cet enregistrement ns a été ajouté")
842
        return redirect(reverse('machines:index-extension'))
843 844 845 846 847 848
    return form(
        {'nsform': ns, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

849 850

@login_required
851
@can_edit(Ns)
852
def edit_ns(request, ns_instance, **_kwargs):
853
    """ View used to edit a NS object """
854 855
    ns = NsForm(request.POST or None, instance=ns_instance)
    if ns.is_valid():
856 857 858
        if ns.changed_data:
            ns.save()
            messages.success(request, "Ns modifié")
859
        return redirect(reverse('machines:index-extension'))
860 861 862 863 864 865
    return form(
        {'nsform': ns, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

866 867

@login_required
868 869
@can_delete_set(Ns)
def del_ns(request, instances):
870
    """ View used to delete a NS object """
871
    ns = DelNsForm(request.POST or None, instances=instances)
872 873 874 875
    if ns.is_valid():
        ns_dels = ns.cleaned_data['ns']
        for ns_del in ns_dels:
            try:
876
                ns_del.delete()
877 878
                messages.success(request, "Le ns a été supprimée")
            except ProtectedError:
879 880 881 882 883
                messages.error(
                    request,
                    ("Erreur le Ns suivant %s ne peut être supprimé"
                     % ns_del)
                )
884
        return redirect(reverse('machines:index-extension'))
885 886 887 888 889 890
    return form(
        {'nsform': ns, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

Charlie Jacomme's avatar
Charlie Jacomme committed
891 892 893 894 895 896 897
@login_required
@can_create(DName)
def add_dname(request):
    """ View used to add a DName object """
    dname = DNameForm(request.POST or None)
    if dname.is_valid():
        dname.save()
Maël Kervella's avatar
Maël Kervella committed
898
        messages.success(request, "This DNAME record has been added")
Charlie Jacomme's avatar
Charlie Jacomme committed
899 900
        return redirect(reverse('machines:index-extension'))
    return form(
Maël Kervella's avatar
Maël Kervella committed
901
        {'dnameform': dname, 'action_name': "Create"},
Charlie Jacomme's avatar
Charlie Jacomme committed
902 903 904 905 906 907 908 909 910 911 912 913 914
        'machines/machine.html',
        request
    )


@login_required
@can_edit(DName)
def edit_dname(request, dname_instance, **_kwargs):
    """ View used to edit a DName object """
    dname = DNameForm(request.POST or None, instance=dname_instance)
    if dname.is_valid():
        if dname.changed_data:
            dname.save()
Maël Kervella's avatar
Maël Kervella committed
915
            messages.success(request, "DName successfully edited")
Charlie Jacomme's avatar
Charlie Jacomme committed
916 917
        return redirect(reverse('machines:index-extension'))
    return form(
Maël Kervella's avatar
Maël Kervella committed
918
        {'dnameform': dname, 'action_name': "Edit"},
Charlie Jacomme's avatar
Charlie Jacomme committed
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
        'machines/machine.html',
        request
    )


@login_required
@can_delete_set(DName)
def del_dname(request, instances):
    """ View used to delete a DName object """
    dname = DelDNameForm(request.POST or None, instances=instances)
    if dname.is_valid():
        dname_dels = dname.cleaned_data['dname']
        for dname_del in dname_dels:
            try:
                dname_del.delete()
Maël Kervella's avatar
Maël Kervella committed
934 935
                messages.success(request,
                                 "The DNAME %s has been deleted" % dname_del)
Charlie Jacomme's avatar
Charlie Jacomme committed
936 937 938
            except ProtectedError:
                messages.error(
                    request,
Maël Kervella's avatar
Maël Kervella committed
939
                    "The DNAME %s can not be deleted" % dname_del
Charlie Jacomme's avatar
Charlie Jacomme committed
940 941 942
                )
        return redirect(reverse('machines:index-extension'))
    return form(
Maël Kervella's avatar
Maël Kervella committed
943
        {'dnameform': dname, 'action_name': 'Delete'},
Charlie Jacomme's avatar
Charlie Jacomme committed
944 945 946 947
        'machines/machine.html',
        request
    )

948

Gabriel Detraz's avatar
Gabriel Detraz committed
949
@login_required
950
@can_create(Txt)
951
def add_txt(request):
952
    """ View used to add a TXT object """
953 954
    txt = TxtForm(request.POST or None)
    if txt.is_valid():
955
        txt.save()
Gabriel Detraz's avatar
Gabriel Detraz committed
956
        messages.success(request, "Cet enregistrement text a été ajouté")
957
        return redirect(reverse('machines:index-extension'))
958 959 960 961 962 963
    return form(
        {'txtform': txt, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar
Gabriel Detraz committed
964 965

@login_required
966
@can_edit(Txt)
967
def edit_txt(request, txt_instance, **_kwargs):
968
    """ View used to edit a TXT object """
969 970
    txt = TxtForm(request.POST or None, instance=txt_instance)
    if txt.is_valid():
971 972 973
        if txt.changed_data:
            txt.save()
            messages.success(request, "Txt modifié")
974
        return redirect(reverse('machines:index-extension'))
975 976 977 978 979 980
    return form(
        {'txtform': txt, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar
Gabriel Detraz committed
981 982

@login_required
983 984
@can_delete_set(Txt)
def del_txt(request, instances):
985
    """ View used to delete a TXT object """
986
    txt = DelTxtForm(request.POST or None, instances=instances)
987 988 989
    if txt.is_valid():
        txt_dels = txt.cleaned_data['txt']
        for txt_del in txt_dels:
Gabriel Detraz's avatar
Gabriel Detraz committed
990
            try:
991
                txt_del.delete()
992
                messages.success(request, "Le txt a été supprimé")
Gabriel Detraz's avatar
Gabriel Detraz committed
993
            except ProtectedError:
994 995 996 997 998
                messages.error(
                    request,
                    ("Erreur le Txt suivant %s ne peut être supprimé"
                     % txt_del)
                )
999
        return redirect(reverse('machines:index-extension'))
1000 1001 1002 1003 1004 1005
    return form(
        {'txtform': txt, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar
Gabriel Detraz committed
1006

Gabriel Detraz's avatar
Gabriel Detraz committed
1007
@login_required
1008
@can_create(Srv)
Gabriel Detraz's avatar
Gabriel Detraz committed
1009
def add_srv(request):
1010
    """ View used to add a SRV object """
Gabriel Detraz's avatar
Gabriel Detraz committed
1011 1012
    srv = SrvForm(request.POST or None)
    if srv.is_valid():
1013
        srv.save()
Gabriel Detraz's avatar
Gabriel Detraz committed
1014 1015
        messages.success(request, "Cet enregistrement srv a été ajouté")
        return redirect(reverse('machines:index-extension'))
1016 1017 1018 1019 1020 1021
    return form(
        {'srvform': srv, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar
Gabriel Detraz committed
1022 1023

@login_required
1024
@can_edit(Srv)
1025
def edit_srv(request, srv_instance, **_kwargs):
1026
    """ View used to edit a SRV object """
Gabriel Detraz's avatar
Gabriel Detraz committed
1027 1028
    srv = SrvForm(request.POST or None, instance=srv_instance)
    if srv.is_valid():
1029 1030 1031
        if srv.changed_data:
            srv.save()
            messages.success(request, "Srv modifié")
Gabriel Detraz's avatar
Gabriel Detraz committed
1032
        return redirect(reverse('machines:index-extension'))
1033 1034 1035 1036 1037 1038
    return form(
        {'srvform': srv, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar
Gabriel Detraz committed
1039 1040

@login_required
1041 1042
@can_delete_set(Srv)
def del_srv(request, instances):
1043
    """ View used to delete a SRV object """
1044
    srv = DelSrvForm(request.POST or None, instances=instances)
Gabriel Detraz's avatar
Gabriel Detraz committed
1045 1046 1047 1048
    if srv.is_valid():
        srv_dels = srv.cleaned_data['srv']
        for srv_del in srv_dels:
            try:
1049
                srv_del.delete()
Gabriel Detraz's avatar
Gabriel Detraz committed
1050 1051
                messages.success(request, "L'srv a été supprimée")
            except ProtectedError:
1052 1053 1054 1055 1056
                messages.error(
                    request,
                    ("Erreur le Srv suivant %s ne peut être supprimé"
                     % srv_del)
                )
Gabriel Detraz's avatar
Gabriel Detraz committed
1057
        return redirect(reverse('machines:index-extension'))
1058 1059 1060 1061 1062 1063
    return form(
        {'srvform': srv, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar
Gabriel Detraz committed
1064

1065
@login_required
1066
@can_create(Domain)
1067 1068
@can_edit(Interface)
def add_alias(request, interface, interfaceid):
1069
    """ View used to add an Alias object """
1070
    alias = AliasForm(request.POST or None, user=request.user)
1071 1072
    if alias.is_valid():
        alias = alias.save(commit=False)
chirac's avatar
chirac committed
1073
        alias.cname = interface.domain
1074
        alias.save()
1075
        messages.success(request, "Cet alias a été ajouté")
1076
        return redirect(reverse(
1077
            'machines:index-alias',
1078 1079 1080 1081 1082 1083 1084 1085
            kwargs={'interfaceid': str(interfaceid)}
        ))
    return form(
        {'aliasform': alias, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

1086 1087

@login_required
1088
@can_edit(Domain)
1089
def edit_alias(request, domain_instance, **_kwargs):
1090
    """ View used to edit an Alias object """
1091 1092 1093 1094 1095
    alias = AliasForm(
        request.POST or None,
        instance=domain_instance,
        user=request.user
    )
1096
    if alias.is_valid():
1097 1098 1099
        if alias.changed_data:
            domain_instance = alias.save()
            messages.success(request, "Alias modifié")
1100
        return redirect(reverse(
1101
            'machines:index-alias',
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
            kwargs={
                'interfaceid': str(domain_instance.cname.interface_parent.id)
            }
        ))
    return form(
        {'aliasform': alias, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

1112 1113

@login_required
1114 1115
@can_edit(Interface)
def del_alias(request, interface, interfaceid):
1116
    """ View used to delete an Alias object """
1117 1118 1119 1120 1121
    alias = DelAliasForm(request.POST or None, interface=interface)
    if alias.is_valid():
        alias_dels = alias.cleaned_data['alias']
        for alias_del in alias_dels:
            try:
1122
                alias_del.delete()
1123 1124 1125 1126
                messages.success(
                    request,
                    "L'alias %s a été supprimé" % alias_del
                )
1127
            except ProtectedError:
1128 1129 1130 1131 1132
                messages.error(
                    request,
                    ("Erreur l'alias suivant %s ne peut être supprimé"
                     % alias_del)
                )
1133
        return redirect(reverse(
1134
            'machines:index-alias',
1135 1136 1137 1138 1139 1140 1141
            kwargs={'interfaceid': str(interfaceid)}
        ))
    return form(
        {'aliasform': alias, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )
1142

1143 1144

@login_required
1145
@can_create(Service)
1146
def add_service(request):
1147
    """ View used to add a Service object """
1148 1149
    service = ServiceForm(request.POST or None)
    if service.is_valid():
1150
        service.save()
1151
        messages.success(request, "Cet enregistrement service a été ajouté")
1152
        return redirect(reverse('machines:index-service'))
1153 1154 1155 1156 1157 1158
    return form(
        {'serviceform': service, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

1159 1160

@login_required
1161
@can_edit(Service)
1162
def edit_service(request, service_instance, **_kwargs):
1163
    """ View used to edit a Service object """
1164 1165
    service = ServiceForm(request.POST or None, instance=service_instance)
    if service.is_valid():
1166 1167 1168
        if service.changed_data:
            service.save()
            messages.success(request, "Service modifié")
1169
        return redirect(reverse('machines:index-service'))
1170 1171 1172 1173 1174 1175
    return form(
        {'serviceform': service, 'action_name': 'Editer'},
        'machines/machine.html',
        request
    )

1176 1177

@login_required
1178 1179
@can_delete_set(Service)
def del_service(request, instances):
1180
    """ View used to delete a Service object """
1181
    service = DelServiceForm(request.POST or None, instances=instances)
1182 1183 1184 1185
    if service.is_valid():
        service_dels = service.cleaned_data['service']
        for service_del in service_dels:
            try:
1186
                service_del.delete()
1187 1188
                messages.success(request, "Le service a été supprimée")
            except ProtectedError:
1189 1190 1191 1192 1193
                messages.error(
                    request,
                    ("Erreur le service suivant %s ne peut être supprimé"
                     % service_del)
                )
1194
        return redirect(reverse('machines:index-service'))
1195 1196 1197 1198 1199 1200
    return form(
        {'serviceform': service, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )

1201

1202
@login_required
1203
@can_create(Vlan)
1204
def add_vlan(request):
1205
    """ View used to add a VLAN object """
1206 1207
    vlan = VlanForm(request.POST or None)
    if vlan.is_valid():
1208
        vlan.save()
1209
        messages.success(request, "Cet enregistrement vlan a été ajouté")
1210
        return redirect(reverse('machines:index-vlan'))
1211 1212 1213 1214 1215 1216
    return form(
        {'vlanform': vlan, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

1217 1218

@login_required
1219
@can_edit(Vlan)