views.py 8.63 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
7
from django.urls import reverse
Enrico Zini's avatar
Enrico Zini committed
8
from backend.mixins import VisitPersonMixin
Enrico Zini's avatar
Enrico Zini committed
9
from nm2.lib.forms import BootstrapAttrsMixin
Enrico Zini's avatar
Enrico Zini committed
10
import backend.models as bmodels
Enrico Zini's avatar
Enrico Zini committed
11
import dsa.models as dmodels
12
import legacy.models as lmodels
Enrico Zini's avatar
Enrico Zini committed
13
from backend import const
14
import datetime
15
16
import markdown
import json
17
18
19
20
21
22
23


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

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

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

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

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

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

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

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

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

Enrico Zini's avatar
Enrico Zini committed
71
72
73
        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())
74

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

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

96
        return ctx
97
98
99
100
101
102
103


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

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

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

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


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

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

139
140
141
142
143
144
145
146
    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)
147
        self.object.save(audit_author=self.request.user, audit_notes="edited bio information")
148
        return super(EditBio, self).form_valid(form)
149
150
151
152
153
154
155
156
157
158
159


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"

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

165
166
167
168
169
170
171
172
    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)
173
        self.object.save(audit_author=self.request.user, audit_notes="edited email")
174
        return super(EditEmail, self).form_valid(form)
Enrico Zini's avatar
Enrico Zini committed
175
176
177
178
179
180
181
182


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):
183
        super().load_objects()
Enrico Zini's avatar
Enrico Zini committed
184
185
186
187
188
        try:
            self.am = bmodels.AM.objects.get(person=self.person)
        except bmodels.AM.DoesNotExist:
            self.am = None

189
        if self.request.user.is_authenticated:
190
191
192
193
194
            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
195
196
197
            self.visitor_am = None

    def check_permissions(self):
198
        super().check_permissions()
Enrico Zini's avatar
Enrico Zini committed
199
200
201
202
        if self.am is None:
            raise PermissionDenied
        if self.visitor_am is None:
            raise PermissionDenied
203
        if self.person.pk != self.request.user.pk and not self.request.user.is_superuser:
Enrico Zini's avatar
Enrico Zini committed
204
205
206
207
208
209
210
211
212
            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")
213
        if self.request.user.is_superuser:
Enrico Zini's avatar
Enrico Zini committed
214
215
            includes.append("fd_comment")

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

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

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

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


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
245
246
247
248


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

    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,
262
            today=datetime.date.today(),
263
264
            check_url=self.request.build_absolute_uri(
                reverse("person:show", kwargs={"key": self.person.lookup_key})),
265
266
267
        )

        return ctx