views.py 8.46 KB
Newer Older
1
from __future__ import annotations
Enrico Zini's avatar
Enrico Zini committed
2
from django import forms
3
from django.utils.timezone import now
Enrico Zini's avatar
Enrico Zini committed
4
from django.views.generic import TemplateView
Enrico Zini's avatar
Enrico Zini committed
5
6
from django.views.generic.edit import UpdateView, FormView
from django.core.exceptions import PermissionDenied
Enrico Zini's avatar
Enrico Zini committed
7
from backend.mixins import VisitPersonMixin
Enrico Zini's avatar
Enrico Zini committed
8
from nm2.lib.forms import BootstrapAttrsMixin
Enrico Zini's avatar
Enrico Zini committed
9
import backend.models as bmodels
Enrico Zini's avatar
Enrico Zini committed
10
import dsa.models as dmodels
11
import legacy.models as lmodels
Enrico Zini's avatar
Enrico Zini committed
12
from backend import const
13
import datetime
14
15
import markdown
import json
16
17
18
19
20
21
22


class Person(VisitPersonMixin, TemplateView):
    template_name = "person/person.html"

    def get_context_data(self, **kw):
        from django.db.models import Min, Max
23
        ctx = super().get_context_data(**kw)
24

25
26
27
28
        processes = lmodels.Process.objects \
                           .filter(person=self.person) \
                           .annotate(started=Min("log__logdate"), ended=Max("log__logdate")) \
                           .order_by("is_active", "ended")
29
30

        import process.models as pmodels
31
        processes2 = pmodels.Process.objects.filter(person=self.person).order_by("-closed_time")
32
33

        adv_processes2 = []
Enrico Zini's avatar
Enrico Zini committed
34
35
        for req in pmodels.Requirement.objects.filter(
                type="advocate", statements__uploaded_by=self.person).distinct().select_related("process"):
36
37
            adv_processes2.append(req.process)

38
39
40
41
42
43
        try:
            am = bmodels.AM.objects.get(person=self.person)
        except bmodels.AM.DoesNotExist:
            am = None

        if am is not None:
44
            am_processes = lmodels.Process.objects.filter(manager=am) \
45
46
47
48
                    .annotate(started=Min("log__logdate"), ended=Max("log__logdate")) \
                    .order_by("is_active", "ended")

            am_processes2 = pmodels.Process.objects.filter(ams__am=am).distinct()
49
            count_processed = len(am_processes) + len(am_processes2)
50
51
52
        else:
            am_processes = []
            am_processes2 = []
53
            count_processed = 0
54
55
56
57

        audit_log = []
        if "view_person_audit_log" in self.visit_perms:
            for e in self.person.audit_log.order_by("-logdate"):
58
                if self.request.user.is_superuser:
Enrico Zini's avatar
Enrico Zini committed
59
                    changes = sorted((k, v[0], v[1]) for k, v in list(json.loads(e.changes).items()))
60
                else:
Enrico Zini's avatar
Enrico Zini committed
61
62
                    changes = sorted((k, v[0], v[1]) for k, v in list(json.loads(e.changes).items())
                                     if k not in ("fd_comment", "pending"))
63
64
65
66
67
68
69
                audit_log.append({
                    "logdate": e.logdate,
                    "author": e.author,
                    "notes": e.notes,
                    "changes": changes,
                })

Enrico Zini's avatar
Enrico Zini committed
70
71
72
        show_new_change_warning = (
                self.person.status in (const.STATUS_DD_U, const.STATUS_DD_NU)
                and self.person.status_changed + datetime.timedelta(days=15) > now())
73

74
75
76
77
78
79
        ctx.update(
            am=am,
            processes=processes,
            processes2=processes2,
            am_processes=am_processes,
            am_processes2=am_processes2,
80
            adv_processes=(lmodels.Process.objects.filter(advocates=self.person)
Enrico Zini's avatar
Enrico Zini committed
81
82
                           .annotate(started=Min("log__logdate"), ended=Max("log__logdate"))
                           .order_by("is_active", "ended")),
83
84
            adv_processes2=adv_processes2,
            audit_log=audit_log,
85
            show_new_change_warning=show_new_change_warning,
86
            count_processed=count_processed,
87
            picture=self.person.get_picture_url(),
88
89
90
91
92
93
        )

        if self.person.bio:
            ctx["bio_html"] = markdown.markdown(self.person.bio, safe_mode="escape")
        else:
            ctx["bio_html"] = ""
94

95
        return ctx
96
97
98
99
100
101
102


class EditLDAP(VisitPersonMixin, UpdateView):
    """
    Edit a person's information
    """
    require_visit_perms = "edit_ldap"
Enrico Zini's avatar
Enrico Zini committed
103
104
    model = dmodels.LDAPFields
    fields = ("cn", "mn", "sn", "email", "uid")
105
106
    template_name = "person/edit_ldap.html"

107
108
109
110
111
    def get_form_class(self):
        class Form(BootstrapAttrsMixin, super().get_form_class()):
            pass
        return Form

112
    def get_object(self):
Enrico Zini's avatar
Enrico Zini committed
113
        return self.person.ldap_fields
114
115
116
117
118
119

    def form_valid(self, form):
        """
        If the form is valid, save the associated model.
        """
        self.object = form.save(commit=False)
120
        self.object.save(audit_author=self.request.user, audit_notes="edited LDAP information")
121
122
123
124
125
126
127
128
129
        return super(EditLDAP, self).form_valid(form)


class EditBio(VisitPersonMixin, UpdateView):
    """
    Edit a person's information
    """
    require_visit_perms = "edit_bio"
    model = bmodels.Person
130
    fields = ("fullname", "bio")
131
132
    template_name = "person/edit_bio.html"

133
134
135
136
137
    def get_form_class(self):
        class Form(BootstrapAttrsMixin, super().get_form_class()):
            pass
        return Form

138
139
140
141
142
143
144
145
    def get_object(self):
        return self.person

    def form_valid(self, form):
        """
        If the form is valid, save the associated model.
        """
        self.object = form.save(commit=False)
146
        self.object.save(audit_author=self.request.user, audit_notes="edited bio information")
147
        return super(EditBio, self).form_valid(form)
148
149
150
151
152
153
154
155
156
157
158


class EditEmail(VisitPersonMixin, UpdateView):
    """
    Edit a person's information
    """
    require_visit_perms = "edit_email"
    model = bmodels.Person
    fields = ("email",)
    template_name = "person/edit_email.html"

159
160
161
162
163
    def get_form_class(self):
        class Form(BootstrapAttrsMixin, super().get_form_class()):
            pass
        return Form

164
165
166
167
168
169
170
171
    def get_object(self):
        return self.person

    def form_valid(self, form):
        """
        If the form is valid, save the associated model.
        """
        self.object = form.save(commit=False)
172
        self.object.save(audit_author=self.request.user, audit_notes="edited email")
173
        return super(EditEmail, self).form_valid(form)
Enrico Zini's avatar
Enrico Zini committed
174
175
176
177
178
179
180
181


class AMProfile(VisitPersonMixin, FormView):
    # Require DD instead of AM to give access to inactive AMs
    require_visitor = "dd"
    template_name = "person/amprofile.html"

    def load_objects(self):
182
        super().load_objects()
Enrico Zini's avatar
Enrico Zini committed
183
184
185
186
187
        try:
            self.am = bmodels.AM.objects.get(person=self.person)
        except bmodels.AM.DoesNotExist:
            self.am = None

188
        if self.request.user.is_authenticated:
189
190
191
192
193
            try:
                self.visitor_am = bmodels.AM.objects.get(person=self.request.user)
            except bmodels.AM.DoesNotExist:
                self.visitor_am = None
        else:
Enrico Zini's avatar
Enrico Zini committed
194
195
196
            self.visitor_am = None

    def check_permissions(self):
197
        super().check_permissions()
Enrico Zini's avatar
Enrico Zini committed
198
199
200
201
        if self.am is None:
            raise PermissionDenied
        if self.visitor_am is None:
            raise PermissionDenied
202
        if self.person.pk != self.request.user.pk and not self.request.user.is_superuser:
Enrico Zini's avatar
Enrico Zini committed
203
204
205
206
207
208
209
210
211
            raise PermissionDenied

    def get_form_class(self):
        includes = ["slots", "is_am"]

        if self.visitor_am.is_fd:
            includes.append("is_fd")
        if self.visitor_am.is_dam:
            includes.append("is_dam")
212
        if self.request.user.is_superuser:
Enrico Zini's avatar
Enrico Zini committed
213
214
            includes.append("fd_comment")

Enrico Zini's avatar
Enrico Zini committed
215
        class AMForm(BootstrapAttrsMixin, forms.ModelForm):
Enrico Zini's avatar
Enrico Zini committed
216
217
218
219
220
221
            class Meta:
                model = bmodels.AM
                fields = includes
        return AMForm

    def get_form_kwargs(self):
222
        res = super().get_form_kwargs()
Enrico Zini's avatar
Enrico Zini committed
223
224
225
226
        res["instance"] = self.am
        return res

    def get_context_data(self, **kw):
227
        ctx = super().get_context_data(**kw)
Enrico Zini's avatar
Enrico Zini committed
228
229
230
231
232
233
        ctx["am"] = self.am
        return ctx

    def form_valid(self, form):
        form.save()
        return self.render_to_response(self.get_context_data(form=form))
234
235
236
237
238
239
240
241
242
243


class Identities(VisitPersonMixin, TemplateView):
    template_name = "person/identities.html"
    require_visit_perms = "view_person_audit_log"

    def get_context_data(self, **kw):
        ctx = super().get_context_data(**kw)
        ctx["identities"] = self.person.identities.all()
        return ctx
244
245
246
247


class Certificate(VisitPersonMixin, TemplateView):
    template_name = "person/certificate.html"
248
    require_visit_perms = "view_certificate"
249
250
251
252
253
254
255
256
257
258
259
260

    def check_permissions(self):
        super().check_permissions()

        if not self.person.is_dd:
            raise PermissionDenied

    def get_context_data(self, **kw):
        ctx = super().get_context_data(**kw)

        ctx.update(
            upload_rights=self.person.status == const.STATUS_DD_U,
261
            today=datetime.date.today(),
262
263
264
        )

        return ctx