views.py 58.8 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
from django.utils.translation import ugettext as _
44

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

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,
58
    can_view,
59 60 61 62 63 64 65
    can_delete,
    can_view_all,
    can_delete_set,
)
from re2o.views import form

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

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

142 143

def f_type_id(is_type_tt):
144 145 146
    """ 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
    """
147
    return 'id_Interface-type_hidden' if is_type_tt else 'id_Interface-type'
148

149

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

158 159 160 161
    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:
162 163
            mtype_id = ip.mtype_id
            used_mtype_id.append(mtype_id)
164
            choices += '],"{t}":[{{key:"",value:"{v}"}},'.format(
165 166
                t=mtype_id,
                v=f_ipv4.empty_label or '""'
167 168
            )
        choices += '{{key:{k},value:"{v}"}},'.format(
169 170
            k=ip.id,
            v=ip.ipv4
171
        )
172

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

179 180

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

194 195

def generate_ipv4_match_func(is_type_tt):
196
    """ Generate the parameter match_func for the massive_bootstrap_form tag
197
    """
198 199
    return (
        'function(q, sync) {{'
200 201 202 203 204 205
        '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);'
206
        '}}'
207 208 209 210
        '}}'
    ).format(
        type_id=f_type_id(is_type_tt)
    )
211

212

213
def generate_ipv4_mbf_param(form_obj, is_type_tt):
214
    """ Generate all the parameters to use with the massive_bootstrap_form
215
    tag """
216
    i_choices = {'ipv4': generate_ipv4_choices(form_obj)}
217 218 219 220
    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}
221
    i_mbf_param = {
222 223 224
        'choices': i_choices,
        'engine': i_engine,
        'match_func': i_match_func,
Maël Kervella's avatar
Maël Kervella committed
225 226
        'update_on': i_update_on,
        'gen_select': i_gen_select
227
    }
228
    return i_mbf_param
229

230

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

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

275

chirac's avatar
chirac committed
276
@login_required
277
@can_edit(Interface)
278
def edit_interface(request, interface_instance, **_kwargs):
279 280 281
    """ 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"""
282

283 284 285 286 287
    machine_form = EditMachineForm(
        request.POST or None,
        instance=interface_instance.machine,
        user=request.user
    )
288 289 290 291 292 293 294 295 296 297 298 299
    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()):
300 301 302
        new_machine_obj = machine_form.save(commit=False)
        new_interface_obj = interface_form.save(commit=False)
        new_domain_obj = domain_form.save(commit=False)
303
        if machine_form.changed_data:
304
            new_machine_obj.save()
305
        if interface_form.changed_data:
306
            new_interface_obj.save()
307
        if domain_form.changed_data:
308
            new_domain_obj.save()
309
        messages.success(request, "La machine a été modifiée")
310 311
        return redirect(reverse(
            'users:profil',
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
            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
    )

327

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

345

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

352
    interface_form = AddInterfaceForm(request.POST or None, user=request.user)
353
    domain_form = DomainForm(request.POST or None)
354
    if interface_form.is_valid():
355 356 357
        new_interface_obj = interface_form.save(commit=False)
        domain_form.instance.interface_parent = new_interface_obj
        new_interface_obj.machine = machine
358
        if domain_form.is_valid():
359 360 361 362
            new_domain_obj = domain_form.save(commit=False)
            new_interface_obj.save()
            new_domain_obj.interface_parent = new_interface_obj
            new_domain_obj.save()
363
            messages.success(request, "L'interface a été ajoutée")
364 365
            return redirect(reverse(
                'users:profil',
366 367 368 369 370 371 372 373 374 375 376 377 378 379
                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
    )

380

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

401

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

426 427 428

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

450 451 452

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

469

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


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


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


536
@login_required
537
@can_create(IpType)
538
def add_iptype(request):
539 540
    """ Ajoute un range d'ip. Intelligence dans le models, fonction views
    minimaliste"""
541

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

553 554

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

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

572 573

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

597

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

613

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

633

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

659

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

675 676

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

695 696

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

721

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

737 738

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

754 755

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

779

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

795 796

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

812 813

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

837

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

853 854

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

870 871

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

Charlie Jacomme's avatar
Charlie Jacomme committed
895 896 897 898 899 900 901
@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
902
        messages.success(request, "This DNAME record has been added")
Charlie Jacomme's avatar
Charlie Jacomme committed
903 904
        return redirect(reverse('machines:index-extension'))
    return form(
Maël Kervella's avatar
Maël Kervella committed
905
        {'dnameform': dname, 'action_name': "Create"},
Charlie Jacomme's avatar
Charlie Jacomme committed
906 907 908 909 910 911 912 913 914 915 916 917 918
        '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
919
            messages.success(request, "DName successfully edited")
Charlie Jacomme's avatar
Charlie Jacomme committed
920 921
        return redirect(reverse('machines:index-extension'))
    return form(
Maël Kervella's avatar
Maël Kervella committed
922
        {'dnameform': dname, 'action_name': "Edit"},
Charlie Jacomme's avatar
Charlie Jacomme committed
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
        '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
938 939
                messages.success(request,
                                 "The DNAME %s has been deleted" % dname_del)
Charlie Jacomme's avatar
Charlie Jacomme committed
940 941 942
            except ProtectedError:
                messages.error(
                    request,
Maël Kervella's avatar
Maël Kervella committed
943
                    "The DNAME %s can not be deleted" % dname_del
Charlie Jacomme's avatar
Charlie Jacomme committed
944 945 946
                )
        return redirect(reverse('machines:index-extension'))
    return form(
Maël Kervella's avatar
Maël Kervella committed
947
        {'dnameform': dname, 'action_name': 'Delete'},
Charlie Jacomme's avatar
Charlie Jacomme committed
948 949 950 951
        'machines/machine.html',
        request
    )

952

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

Gabriel Detraz's avatar
Gabriel Detraz committed
968 969

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

Gabriel Detraz's avatar
Gabriel Detraz committed
985 986

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

Gabriel Detraz's avatar
Gabriel Detraz committed
1010

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

Gabriel Detraz's avatar
Gabriel Detraz committed
1026 1027

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

Gabriel Detraz's avatar
Gabriel Detraz committed
1043 1044

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

Gabriel Detraz's avatar
Gabriel Detraz committed
1068

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

1090 1091

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

1116 1117

@login_required
1118 1119
@can_edit(Interface)
def del_alias(request, interface, interfaceid):
1120
    """ View used to delete an Alias object """
1121 1122 1123 1124 1125
    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:
1126
                alias_del.delete()
1127 1128 1129 1130
                messages.success(
                    request,
                    "L'alias %s a été supprimé" % alias_del
                )
1131
            except ProtectedError:
1132 1133 1134 1135 1136
                messages.error(
                    request,
                    ("Erreur l'alias suivant %s ne peut être supprimé"
                     % alias_del)
                )
1137
        return redirect(reverse(
1138
            'machines:index-alias',
1139 1140 1141 1142 1143 1144 1145
            kwargs={'interfaceid': str(interfaceid)}
        ))
    return form(
        {'aliasform': alias, 'action_name': 'Supprimer'},
        'machines/machine.html',
        request
    )
1146

1147

1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
@login_required
@can_create(Role)
def add_role(request):
    """ View used to add a Role object """
    role = RoleForm(request.POST or None)
    if role.is_valid():
        role.save()
        messages.success(request, "Cet enregistrement role a été ajouté")
        return redirect(reverse('machines:index-role'))
    return form(
        {'roleform': role, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )


@login_required
@can_edit(Role)
def edit_role(request, role_instance, **_kwargs):
    """ View used to edit a Role object """
    role = RoleForm(request.POST or None, instance=role_instance)
    if role.is_valid():
        if role.changed_data:
            role.save()
1172
            messages.success(request, _("Role updated"))
1173 1174
        return redirect(reverse('machines:index-role'))
    return form(
1175
        {'roleform': role, 'action_name': _('Edit')},
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
        'machines/machine.html',
        request
    )


@login_required
@can_delete_set(Role)
def del_role(request, instances):
    """ View used to delete a Service object """
    role = DelRoleForm(request.POST or None, instances=instances)
    if role.is_valid():
        role_dels = role.cleaned_data['role']
        for role_del in role_dels:
            try:
                role_del.delete()
1191
                messages.success(request, _("The role has been deleted."))
1192 1193 1194
            except ProtectedError:
                messages.error(
                    request,
1195 1196 1197
                    (_("Error: The following role cannot be deleted: %(role)")
                        % {'role': role_del}
                     )
1198 1199 1200
                )
        return redirect(reverse('machines:index-role'))
    return form(
1201
        {'roleform': role, 'action_name': _('Delete')},
1202 1203 1204 1205 1206
        'machines/machine.html',
        request
    )


1207
@login_required
1208
@can_create(Service)
1209
def add_service(request):
1210
    """ View used to add a Service object """
1211 1212
    service = ServiceForm(request.POST or None)
    if service.is_valid():
1213
        service.save()
1214
        messages.success(request, "Cet enregistrement service a été ajouté")
1215
        return redirect(reverse('machines:index-service'))
1216 1217 1218 1219 1220 1221
    return form(
        {'serviceform': service, 'action_name': 'Créer'},
        'machines/machine.html',
        request
    )

Gabriel Detraz's avatar