Blame view

src/core/pyros_django/scientific_program/views.py 50.3 KB
5a434264   Alexis Koralewski   New version of Sc...
1
2
3
4
from django.http.response import HttpResponse
from src.core.pyros_django import scientific_program
from django.shortcuts import render, redirect, get_object_or_404, reverse
from django.contrib.auth import authenticate, login
089c0115   Alexis Koralewski   add new version (...
5
from django.contrib.auth.decorators import login_required
5a434264   Alexis Koralewski   New version of Sc...
6
from .forms import PeriodForm, ScientificProgramForm, InstituteForm, SP_PeriodForm
089c0115   Alexis Koralewski   add new version (...
7
from src.core.pyros_django.dashboard.decorator import level_required
5a434264   Alexis Koralewski   New version of Sc...
8
from common.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, UserLevel, SP_Period_Guest
089c0115   Alexis Koralewski   add new version (...
9
from django.http import HttpResponseRedirect
5a434264   Alexis Koralewski   New version of Sc...
10
11
12
13
14
15
16
17
18
19
from datetime import date, datetime
from django.conf import settings
from django.core.mail import send_mail
from django.db.models import Max
from dateutil.relativedelta import relativedelta
from django.utils import timezone
from django.db.models import Q,F
from .functions import get_global_svg_timeline, get_svg_timeline, get_proposal_svg_timeline
from django.views.decorators.csrf import csrf_exempt
import re
089c0115   Alexis Koralewski   add new version (...
20
21

# Scientific program CRUD
5a434264   Alexis Koralewski   New version of Sc...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78


@login_required
@level_required("Admin", "Observer","TAC","Unit-PI","Unit-board")
def index_scientific_program(request):
    today = timezone.now().date()
    does_next_period_exist = Period.objects.filter(
        start_date__gt=today).order_by("start_date").first() != None
    future_period = Period.objects.filter(
        start_date__gt=today, submission_start_date__lte=today).order_by("start_date").first()
    previous_period = Period.objects.filter(
        end_date__lt=today, property_of_data_end_date__lt=today).first()
    current_period = Period.objects.currently_active_period()
    evaluation_periods = Period.objects.filter(
        start_date__gte=today, submission_end_date__lte=today,unit_pi_validation_start_date__gt=today)
    #validation_periods = Period.objects.filter(
    #    start_date__gte=today, submission_end_date__gt=today,unit_pi_validation_start_date__gte=today,start_date__lt=F("start_date") + relativedelta(days=-5)) 
    validation_periods = Period.objects.filter(
        start_date__gte=today, submission_end_date__gt=today,unit_pi_validation_start_date__gte=today)
    sp_to_be_evaluated = SP_Period.objects.filter(period__in=evaluation_periods,status__in=(SP_Period.STATUSES_SUBMITTED,SP_Period.STATUSES_EVALUATED)).count() > 0
    sp_to_be_validated = SP_Period.objects.filter(period__in=validation_periods,status__in=(SP_Period.STATUSES_EVALUATED,SP_Period.STATUSES_ACCEPTED,SP_Period.STATUSES_REJECTED)).count() > 0
    # date_diff_today_end_of_property will give a value to make
    # the date of today shift through the time line
    if previous_period:
        temp = today - previous_period.start_date 
        date_diff_today_end_of_property = temp.days / 12.5 
    else:
        temp = today - current_period.start_date 
        date_diff_today_end_of_property = temp.days / 12.5 + 15
    CAN_VALIDATE_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board") and sp_to_be_validated
    CAN_EVALUATE_SP = request.session.get("role") in ("Admin","TAC") and sp_to_be_evaluated
    CAN_SUBMIT_SP =  request.session.get("role") in ("Admin","Observer") and does_next_period_exist
    CAN_VIEW_SP =  request.session.get("role") in ("Admin","Observer")
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_VIEW_EXPLOITATION_PERIOD = request.session.get("role") in ("Admin","Observer","Unit-PI","Unit-board")
    CAN_CREATE_EXPLOITATION_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    svg = get_svg_timeline(previous_period,current_period,future_period)
    global_svg = get_global_svg_timeline(previous_period,current_period,future_period)
    #global_svg = get_global_svg_timeline(current_period,current_period,future_period)
    return render(request, "scientific_program/index.html", {
        "base_template": "base.html",
        "previous_period": previous_period,
        "current_period": current_period,
        "future_period": future_period,
        "today": today,
        "date_diff_today_end_of_property": date_diff_today_end_of_property,
        "svg":svg,
        "global_svg":global_svg,
        "CAN_VALIDATE_SP": CAN_VALIDATE_SP,
        "CAN_EVALUATE": CAN_EVALUATE_SP,
        "CAN_SUBMIT_SP":CAN_SUBMIT_SP,
        "CAN_VIEW_SP": CAN_VIEW_SP,
        "CAN_VIEW_EXPLOITATION_PERIOD": CAN_VIEW_EXPLOITATION_PERIOD,
        "CAN_CREATE_EXPLOITATION_PERIOD": CAN_CREATE_EXPLOITATION_PERIOD,
        "CAN_VIEW_ALL_SP": CAN_VIEW_ALL_SP
    })

089c0115   Alexis Koralewski   add new version (...
79
@login_required
5a434264   Alexis Koralewski   New version of Sc...
80
81
82
@level_required("Admin", "Observer")
def create_scientific_program(request):
    SP_form = ScientificProgramForm()
089c0115   Alexis Koralewski   add new version (...
83
    if request.POST:
5a434264   Alexis Koralewski   New version of Sc...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        SP_form = ScientificProgramForm(request.POST)
        if SP_form.is_valid():
            institute = request.user.institute
            temp_SP = SP_form.save(commit=False)
            temp_SP.institute = Institute.objects.get(name=institute)
            temp_SP.status = SP_Period.STATUSES_DRAFT
            temp_SP.sp_pi = request.user
            temp_SP.save()
            return HttpResponseRedirect(reverse("create_scientific_program_period",args=[temp_SP.id]))
    return render(request, "scientific_program/create_scientific_program.html", {
        "SPForm": SP_form,
    })

@level_required("Admin", "Observer")
@login_required
def create_scientific_program_period(request,id_SP,id_SP_Period=None):
    SP = ScientificProgram.objects.get(id=id_SP)
    today = timezone.now().date()
    next_periods = Period.objects.filter(submission_start_date__lte=today,submission_end_date__gt=today, start_date__gt=today)
e00964fc   Alexis Koralewski   new version of ti...
103
    is_sp_reproposed = False
5a434264   Alexis Koralewski   New version of Sc...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    if SP.sp_pi != request.user:
        HttpResponseRedirect(reverse("index_scientific_program"))
    SP_Period_form = SP_PeriodForm()
    if id_SP_Period != None:
        sp_period_template = SP_Period.objects.get(id=id_SP_Period)
        initial_data = {
            "quota_minimal":sp_period_template.quota_minimal,
            "quota_nominal":sp_period_template.quota_nominal,
            "over_quota_duration":sp_period_template.over_quota_duration,
            "token":sp_period_template.token
        }
        period_id_to_be_excluded = SP_Period.objects.filter(scientific_program=sp_period_template.scientific_program).values_list("period",flat=True)
        next_periods = Period.objects.filter(submission_start_date__lte=today,submission_end_date__gt=today, start_date__gt=today).exclude(id__in=period_id_to_be_excluded)
        SP_Period_form = SP_PeriodForm(initial=initial_data)
e00964fc   Alexis Koralewski   new version of ti...
118
        is_sp_reproposed = True
5a434264   Alexis Koralewski   New version of Sc...
119
120
121
122
123
    #next_period = Period.objects.filter(
    #    start_date__gt=today).order_by("start_date").first()
    error = False
    error_message = ""
    list_of_emails = None
e00964fc   Alexis Koralewski   new version of ti...
124
    recipient_list = []
5a434264   Alexis Koralewski   New version of Sc...
125
126
127
128
129
    if request.POST:
        SP_Period_form = SP_PeriodForm(request.POST)
        if SP_Period_form.is_valid():

            """ if request.POST.getlist("user"):
089c0115   Alexis Koralewski   add new version (...
130
131
132
                for user in request.POST.getlist("user"):
                    user_instance = PyrosUser.objects.get(id=int(user))
                    SP_Period_User.objects.create(SP_Period=sp_period,user=user_instance,is_SP_PI=False)
5a434264   Alexis Koralewski   New version of Sc...
133
            """
e00964fc   Alexis Koralewski   new version of ti...
134
            if not is_sp_reproposed and request.POST.get("users"):
5a434264   Alexis Koralewski   New version of Sc...
135
136
                regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
                list_of_emails = request.POST.get("users").strip()
e00964fc   Alexis Koralewski   new version of ti...
137
                
5a434264   Alexis Koralewski   New version of Sc...
138
139
140
141
142
143
                for email in list_of_emails.split(","):
                    if re.fullmatch(regex, email):
                        recipient_list.append(email)
                    else:
                        error = True
                        error_message = f"Invalid mail for {email}"
e00964fc   Alexis Koralewski   new version of ti...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
            if not error:
                institute = request.user.institute
                selected_period = Period.objects.get(id=request.POST.get("period"))

                current_sp = ScientificProgram.objects.get(id=id_SP)
                sp_period = SP_Period_form.save(commit=False)
                sp_period.period = selected_period
                #sp_period.period = next_period
                sp_period.scientific_program = current_sp
                sp_period.save()

                sp_pi_user = PyrosUser.objects.get(id=request.user.id)
                #SP_Period_User.objects.create(
                #    SP_Period=sp_period, user=sp_pi_user, is_SP_PI=True)
                domain = settings.DEFAULT_DOMAIN
                url = f"{domain}{reverse('sp_register',args=(current_sp.pk,sp_period.period.pk))}"
                mail_subject = '[PyROS CC] New registration to an observing proposal'
                mail_message = (f"Hi,\n\nYou were invited to join an observing proposal that as been submitted using PyROS.\n"
                                f"The name of the proposal is {current_sp.name} and his PI is {sp_pi_user.first_name} {sp_pi_user.last_name}.\n"
                                f"To accept this invitation, click on the following link : {url}\n"
                                "You might be asked to login first and will be redirected to the proposal page.\n"
                                "If the redirection doesn't work, click again on the link after you've logged in.\n"
                                "If you don't own an PyROS account, go on the website in order to create an account with the same mail adress that you are using to read this mail."
                                "\n\nCordially,\n\nPyROS Control Center")
                if len(recipient_list) > 0:
5a434264   Alexis Koralewski   New version of Sc...
169
170
171
172
173
174
175
176
177
178
                    for recipient in recipient_list:
                        guest = SP_Period_Guest.objects.create(
                            SP_Period=sp_period, email=recipient)
                        send_mail(
                            mail_subject,
                            mail_message,
                            from_email=None,
                            recipient_list=[recipient],
                            fail_silently=False,
                        )
e00964fc   Alexis Koralewski   new version of ti...
179
180
                if is_sp_reproposed:
                    previous_sp_periods = SP_Period.objects.filter(scientific_program=current_sp,period__lt=selected_period)
b414eec1   Alexis Koralewski   improving user ac...
181
                    users_of_previous_period_for_sp = SP_Period_User.objects.filter(SP_Period__in=previous_sp_periods).values_list("user",flat=True).distinct()
e00964fc   Alexis Koralewski   new version of ti...
182
183
184
185
186
                    for user in users_of_previous_period_for_sp:
                        SP_Period_User.objects.create(SP_Period=sp_period,user=PyrosUser.objects.get(id=user))
                return HttpResponseRedirect(reverse("detail_scientific_program",args=[current_sp.id]))

                #return HttpResponseRedirect(reverse("own_scientific_program_list"))
5a434264   Alexis Koralewski   New version of Sc...
187
188
189
190
191
    return render(request, "scientific_program/create_scientific_program_period.html", {
        "scientific_program":SP,
        "SP_PeriodForm": SP_Period_form,
        "error_message": error_message,
        "list_of_emails": list_of_emails,
e00964fc   Alexis Koralewski   new version of ti...
192
193
        "next_periods": next_periods,
        "is_sp_reproposed":is_sp_reproposed
5a434264   Alexis Koralewski   New version of Sc...
194
195
196
197
198
199
    })





089c0115   Alexis Koralewski   add new version (...
200
@login_required
5a434264   Alexis Koralewski   New version of Sc...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
@level_required("Admin", "Observer")
def create_scientific_program_with_template(request, id_SP):
    SP_form = ScientificProgramForm(instance=ScientificProgram.objects.get(id=id_SP))
    if request.POST:
        SP_form = ScientificProgramForm(request.POST)
        if SP_form.is_valid():
            institute = request.user.institute
            temp_SP = SP_form.save(commit=False)
            temp_SP.institute = Institute.objects.get(name=institute)
            temp_SP.status = SP_Period.STATUSES_DRAFT
            temp_SP.sp_pi = request.user
            temp_SP.save()
            return HttpResponseRedirect(reverse("create_scientific_program_period",args=[temp_SP.id]))
    return render(request, "scientific_program/create_scientific_program.html", {
        "SPForm": SP_form,
    })

@login_required
@level_required("Admin", "Observer")
def list_scientific_program_period_repropose(request):
    select_message = "Submit again an existing SP but for a new exploitation period (instance)"
    none_message = f"There is no existing SP to be submitted for a new exploitation period"
5a434264   Alexis Koralewski   New version of Sc...
223
    sp_where_user_is_sp_pi = ScientificProgram.objects.filter(sp_pi=request.user)
e00964fc   Alexis Koralewski   new version of ti...
224
225
226
227
228
    if sp_where_user_is_sp_pi is None:
        return HttpResponseRedirect(reverse("index_scientific_program"))
    sp_period_of_user = SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi)
    if not sp_period_of_user and sp_where_user_is_sp_pi is None: 
        return HttpResponseRedirect(reverse("index_scientific_program"))
5a434264   Alexis Koralewski   New version of Sc...
229
230
231
232
    #sp_of_user = SP_Period_User.objects.filter(user=request.user.id).values_list("SP_Period",flat=True)
    #sp_period_of_user =  SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi,status=SP_Period.STATUSES_ACCEPTED).values("scientific_program","id").annotate("scientific_program")
    #sp_period_active_of_user = SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi,period=Period.objects.currently_active_period())
    sp_period_of_user = []
b414eec1   Alexis Koralewski   improving user ac...
233
234
    # sp_to_be_proposed = list of Scientific Program that are NOT linked to a Period
    list_of_sp_to_be_proposed = []
e00964fc   Alexis Koralewski   new version of ti...
235
236
    today = timezone.now().date()
    next_proposal_periods = Period.objects.filter(submission_start_date__lte=today,submission_end_date__gt=today, start_date__gt=today).values_list("id",flat=True)
5a434264   Alexis Koralewski   New version of Sc...
237
    for sp in sp_where_user_is_sp_pi:
e00964fc   Alexis Koralewski   new version of ti...
238
239
240
241
        is_sp_associated_with_period = SP_Period.objects.filter(scientific_program=sp).count() > 0
        if is_sp_associated_with_period:
            # get latest period that has been associated with that SP
            max_period_of_sp = SP_Period.objects.filter(scientific_program=sp).aggregate(Max("period"))["period__max"]
b414eec1   Alexis Koralewski   improving user ac...
242
243
244
245
246
247
248
249
250
251
            # get all periods where this SP is associated
            periods_of_sp = SP_Period.objects.filter(scientific_program=sp).values("period")
            if max_period_of_sp :
                # remove the periods where this sp is associated
                next_proposal_periods = next_proposal_periods.exclude(id__in=periods_of_sp)
                if next_proposal_periods.count() > 0:
                    # this SP can be reproposed for a next proposal period
                    sp_period_of_user.append(SP_Period.objects.get(scientific_program=sp,period=max_period_of_sp))
        else:
            list_of_sp_to_be_proposed.append(sp)
5a434264   Alexis Koralewski   New version of Sc...
252
    #sp_period_active_of_user = SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi).annotate(Max("period")).distinct("scientific_program_id")
5a434264   Alexis Koralewski   New version of Sc...
253
254
255
256
    list_of_sp = []
    are_there_only_sp = False
    # SP_Period where user is a SP_PI
    list_of_sp = sp_period_of_user
b414eec1   Alexis Koralewski   improving user ac...
257
    if len(list_of_sp) ==  0 and len(list_of_sp_to_be_proposed) == 0:
5a434264   Alexis Koralewski   New version of Sc...
258
259
260
261
262
263
264
        list_of_sp = ScientificProgram.objects.filter(sp_pi=request.user).exclude(id__in=SP_Period.objects.all().values("scientific_program"))
        # This boolean will tell if we're using ScientificProgram objects within the view or SP_Period objects
        are_there_only_sp = True
    return render(request, "scientific_program/list_of_scientific_program_select.html", {
        "select_message": select_message,
        "none_message": none_message,
        "list_of_sp": list_of_sp,
b414eec1   Alexis Koralewski   improving user ac...
265
        "list_of_sp_to_be_proposed":list_of_sp_to_be_proposed,
5a434264   Alexis Koralewski   New version of Sc...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
        "list_of_sp_to_be_reproposed": True,
        "are_there_only_sp":are_there_only_sp
    })

@login_required
@level_required("Admin", "Observer")
def list_scientific_program_as_template(request):
    select_message = "Please select a SP from the list below as template:"
    none_message = f"There is no SP to be used as template"
    sp_of_user = SP_Period_User.objects.filter(user=request.user.id).values_list("SP_Period",flat=True)
    list_of_sp = []
    are_there_only_sp = False
    for sp_period in sp_of_user:
        list_of_sp.append(SP_Period.objects.get(id=sp_period).order_by("-id"))
    if len(list_of_sp) ==  0:
        list_of_sp = ScientificProgram.objects.filter(sp_pi=request.user).order_by("-id")
        are_there_only_sp = True
    return render(request, "scientific_program/list_of_scientific_program_select.html", {
        "select_message": select_message,
        "none_message": none_message,
        "list_of_sp": list_of_sp,
        "list_of_sp_as_template": True,
        "are_there_only_sp":are_there_only_sp
    })


@login_required
@level_required("Admin", "TAC")
def list_submitted_scientific_program(request):
    select_message = "Please select a SP from the list below for evaluation:"
    today = timezone.now().date()
    next_period = Period.objects.filter(
        start_date__gte=today, submission_end_date__lte=today,unit_pi_validation_start_date_gt=today).first()
    none_message = f"There is no SP to be evaluated for next exploitation period {next_period}"
    # Note : ~Q mean not query
    list_of_sp = SP_Period.objects.filter(Q(referee1=None) & ~Q(referee2=request.user) | ~Q(
        referee1=request.user) & Q(referee2=None), status=SP_Period.STATUSES_SUBMITTED, period=next_period)
    list_of_evaluated_sp = []
    for sp in list_of_sp:
        if sp.referee1 == request.user or sp.referee2 == request.user:
            list_of_evaluated_sp.append(sp)

    return render(request, "scientific_program/list_of_scientific_program_select.html", {
        "select_message": select_message,
        "none_message": none_message,
        "list_of_sp": list_of_sp,
        "list_of_evaluated_sp": list_of_evaluated_sp
    })


@login_required
b414eec1   Alexis Koralewski   improving user ac...
317
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
def list_evaluated_scientific_program(request):
    select_message = "Please select a SP from the list below for validation:"
    today = timezone.now().date()
    next_period = Period.objects.filter(
        start_date__gte=today, submission_start_date__lte=today).first()
    none_message = f"There is no SP to be validated for next exploitation period {next_period}"
    list_of_sp = SP_Period.objects.filter(
        status=SP_Period.STATUSES_EVALUATED, period=next_period)
    list_of_validated_sp = []
    for sp in list_of_sp:
        if sp.quota_allocated > 0 and sp.is_valid == SP_Period.IS_VALID_ACCEPTED or sp.is_valid == SP_Period.IS_VALID_REJECTED:
            list_of_validated_sp.append(sp)

    return render(request, "scientific_program/list_of_scientific_program_select.html", {
        "select_message": select_message,
        "none_message": none_message,
        "list_of_sp": list_of_sp,
        "list_of_validated_sp": list_of_validated_sp
    })


@login_required
def accept_sp_invitation(request, id_SP, id_period):
cffa6238   Alexis Koralewski   fixing who can su...
341
342
343
344
    """
    An invitation to join an SP is valid until the end of Exploitation period

    """
5a434264   Alexis Koralewski   New version of Sc...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
    sp_period = SP_Period.objects.get(scientific_program=id_SP, period=id_period)
    current_user = PyrosUser.objects.get(username=request.user)
    is_user_guest_of_sp = SP_Period_Guest.objects.filter(
        SP_Period=sp_period, email=current_user.email).exists()
    today = timezone.now().date()
    period = Period.objects.get(id=id_period)
    if is_user_guest_of_sp and period.end_date > today:
        new_user = SP_Period_User.objects.create(
            SP_Period=sp_period, user=current_user)
        if new_user:
            SP_Period_Guest.objects.get(
                SP_Period=sp_period, email=current_user.email).delete()
            return HttpResponseRedirect(reverse("detail_scientific_program_period", kwargs={"id_sp": id_SP, "id_period": id_period}))
    return HttpResponseRedirect(reverse("index"))


@level_required("Admin", "Unit-PI", "Observer", "TAC")
@login_required
def edit_scientific_program_period(request, id_sp, id_period):
    scientific_program = get_object_or_404(ScientificProgram, pk=id_sp)
    SPForm = ScientificProgramForm(
        request.POST or None, instance=scientific_program)
    error = False
    error_message = ""
    today = timezone.now().date()
    sp_period = SP_Period.objects.get(
        scientific_program=scientific_program, period=Period.objects.get(id=id_period))
cffa6238   Alexis Koralewski   fixing who can su...
372
    period=Period.objects.get(id=id_period)
5a434264   Alexis Koralewski   New version of Sc...
373
374
    SP_Period_form = SP_PeriodForm(request.POST or None, instance=sp_period)
    sp_pi = scientific_program.sp_pi
089c0115   Alexis Koralewski   add new version (...
375
    if request.session.get("role") == "Observer" and request.user.id != sp_pi.id:
5a434264   Alexis Koralewski   New version of Sc...
376
377
378
379
380
381
382
383
        return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
    guests = list(SP_Period_Guest.objects.filter(
        SP_Period=sp_period).values_list("email", flat=True))
    user_of_sp = SP_Period_User.objects.filter(
        SP_Period__exact=sp_period)
    users_informations = PyrosUser.objects.filter(
        id__in=user_of_sp.values_list("user", flat=True))
    guests = ",".join(guests)
cffa6238   Alexis Koralewski   fixing who can su...
384
385
386
387
    error = False
    error_message = ""
    list_of_emails = None
    recipient_list = []
089c0115   Alexis Koralewski   add new version (...
388
    if request.POST:
cffa6238   Alexis Koralewski   fixing who can su...
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
        if SP_Period_form.is_valid():
            # can send invitation until the end of exploitation
            if request.POST.get("users") and today < period.end_date:
                # Invite user to join the SP
                regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
                list_of_emails = request.POST.get("users").strip()
                
                for email in list_of_emails.split(","):
                    if re.fullmatch(regex, email):
                        recipient_list.append(email)
                    else:
                        error = True
                        error_message = f"Invalid mail for {email}"
                if not error:
                    domain = settings.DEFAULT_DOMAIN
                    url = f"{domain}{reverse('sp_register',args=(scientific_program.pk,sp_period.period.pk))}"
                    mail_subject = '[PyROS CC] New registration to an observing proposal'
                    mail_message = (f"Hi,\n\nYou were invited to join an observing proposal that as been submitted using PyROS.\n"
                                    f"The name of the proposal is {scientific_program.name} and his PI is {sp_pi.first_name} {sp_pi.last_name}.\n"
                                    f"To accept this invitation, click on the following link : {url}\n"
                                    "You might be asked to login first and will be redirected to the proposal page.\n"
                                    "If the redirection doesn't work, click again on the link after you've logged in.\n"
                                    "If you don't own an PyROS account, go on the website in order to create an account with the same mail adress that you are using to read this mail."
                                    "\n\nCordially,\n\nPyROS Control Center")
                    if len(recipient_list) > 0:
                        try:
                            # Delete previous guests (resetting list of guests)
                            SP_Period_Guest.objects.filter(SP_Period=sp_period).delete()
                        finally:
                            for recipient in recipient_list:
                                guest = SP_Period_Guest.objects.create(
                                    SP_Period=sp_period, email=recipient)
                                send_mail(
                                    mail_subject,
                                    mail_message,
                                    from_email=None,
                                    recipient_list=[recipient],
                                    fail_silently=False,
                                )
                else:
                    return render(request, 'scientific_program/scientific_program_detail_edit.html', {
                            'id_sp': id_sp,
                            "id_period": id_period,
                            "SPForm": SPForm,
                            "period": sp_period.period,
                            "guests": guests,
                            "users_of_sp_period": users_informations,
                            "SP_PeriodForm": SP_Period_form,
                            "sp_period": sp_period,
                            "error_message":error_message
                        })
                SP_period = SP_Period_form.save()
                # save changes on user list 
                if request.POST.getlist("user"):
                    for sp_period_user in users_informations:
                        if sp_period_user.id not in map(int, request.POST.getlist("user")):
                            sp_period_user.delete()

                    for user in request.POST.getlist("user"):
                        user_instance = PyrosUser.objects.get(id=int(user))
                        if user_instance not in users_informations:
                            SP_Period_User.objects.create(
                                SP_Period=sp_period, user=user_instance)
                else:
                    SP_Period_User.objects.filter(
                        SP_Period=sp_period).delete()
                return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
5a434264   Alexis Koralewski   New version of Sc...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
        if SP_Period_form.is_valid() and request.session.get("role") == "TAC" and sp_period.status != SP_Period.STATUSES_DRAFT:
            # vote TAC
            if sp_period.referee1 == None or sp_period.referee1 == request.user and request.POST.get("vote_referee1") and request.POST.get("reason_referee1"):
                tac = request.user.id
                SP_Period_form.save(commit=False)
                SP_Period_form.vote_referee1 = request.POST.get(
                    "vote_referee1")
                SP_Period_form.reason_referee1 = request.POST.get(
                    "reason_referee1")
                SP_Period_form.save()
                sp_period.referee1 = PyrosUser.objects.get(id=tac)
                #if sp_period.referee2 != None:
                    #sp_period.status = SP_Period.STATUSES_EVALUATED
                sp_period.save()
            if sp_period.referee1 != None and sp_period.referee2 == None or sp_period.referee2 == request.user and request.POST.get("vote_referee2") and len(request.POST.get("reason_referee2")) > 0:
                tac = request.user.id
                SP_Period_form.save(commit=False)
                SP_Period_form.vote_referee2 = request.POST.get(
                    "vote_referee2")
                SP_Period_form.reason_referee2 = request.POST.get(
                    "reason_referee2")
                SP_Period_form.save()
                sp_period.referee2 = PyrosUser.objects.get(id=tac)
                #if sp_period.referee1 != None:
                    #sp_period.status = SP_Period.STATUSES_EVALUATED
                sp_period.save()
            return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
        elif SP_Period_form.is_valid() and request.session.get("role") in ["Unit-PI", "Unit-board"] and sp_period.status in [SP_Period.STATUSES_EVALUATED, SP_Period.STATUSES_ACCEPTED, SP_Period.STATUSES_REJECTED]:
            #if request.POST.get("is_valid") != None:
                #sp_period.status = request.POST.get("is_valid")
            SP_Period_form.save()
            sp_period.save()
            return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
        else:
            print(SP_Period_form.errors)
    return render(request, 'scientific_program/scientific_program_detail_edit.html', {
        'id_sp': id_sp,
        "id_period": id_period,
        "SPForm": SPForm,
        "period": sp_period.period,
        "guests": guests,
        "users_of_sp_period": users_informations,
        "SP_PeriodForm": SP_Period_form,
cffa6238   Alexis Koralewski   fixing who can su...
499
500
        "sp_period": sp_period,
        "error_message":error_message
5a434264   Alexis Koralewski   New version of Sc...
501
    })
089c0115   Alexis Koralewski   add new version (...
502

5a434264   Alexis Koralewski   New version of Sc...
503
504
505


@level_required("Admin", "Unit-PI", "Observer", "TAC")
089c0115   Alexis Koralewski   add new version (...
506
@login_required
5a434264   Alexis Koralewski   New version of Sc...
507
def detail_scientific_program(request, id):
089c0115   Alexis Koralewski   add new version (...
508
    scientific_program = get_object_or_404(ScientificProgram, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
509
510
511
    sp_periods = SP_Period.objects.filter(
        scientific_program=scientific_program).order_by("-id")
    sp_pi = scientific_program.sp_pi
089c0115   Alexis Koralewski   add new version (...
512
    
5a434264   Alexis Koralewski   New version of Sc...
513
514
    if request.session.get("role") == "Observer" and sp_pi != request.user and not SP_Period_User.objects.filter(SP_Period__in=sp_periods, user=PyrosUser.objects.get(id=request.user.id)).exists() :
        return HttpResponseRedirect(reverse("index_scientific_program"))
e00964fc   Alexis Koralewski   new version of ti...
515
516
517
    today = timezone.now().date()
    next_proposal_period =  Period.objects.filter(
        start_date__gt=today, submission_start_date__lte=today).order_by("start_date").first()
6f505a1d   Alexis Koralewski   fixing delete but...
518
519
520
521
    if next_proposal_period:
        is_future_period_in_proposal = next_proposal_period.id not in sp_periods.values_list("period",flat=True)
    else:
        is_future_period_in_proposal = False
e00964fc   Alexis Koralewski   new version of ti...
522
    CAN_REPROPOSE_SP = sp_pi == request.user and request.session.get("role") == "Observer" and is_future_period_in_proposal
6f505a1d   Alexis Koralewski   fixing delete but...
523
    CAN_DELETE_SP = not sp_periods and (sp_pi == request.user and request.session.get("role") == "Observer") or (request.session.get("role") in ("Admin","Unit-PI","Unit-board"))
5a434264   Alexis Koralewski   New version of Sc...
524
525
526
527
    return render(request, 'scientific_program/scientific_program_detail.html', {
        'scientific_program': scientific_program,
        "sp_pi": sp_pi,
        "sp_periods": sp_periods,
e00964fc   Alexis Koralewski   new version of ti...
528
529
        "CAN_REPROPOSE_SP": CAN_REPROPOSE_SP,
        "CAN_DELETE_SP": CAN_DELETE_SP
5a434264   Alexis Koralewski   New version of Sc...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
    })


@level_required("Admin", "Unit-PI", "Observer", "TAC")
@login_required
def detail_scientific_program_period(request, id_sp, id_period):
    scientific_program = get_object_or_404(ScientificProgram, pk=id_sp)
    sp_period = SP_Period.objects.get(
        scientific_program=scientific_program, period=Period.objects.get(id=id_period))
    user_of_sp = SP_Period_User.objects.filter(
        SP_Period=sp_period)
    users_informations = PyrosUser.objects.filter(
        id__in=user_of_sp.values_list("user", flat=True))
    sp_pi = scientific_program.sp_pi
    guests = list(SP_Period_Guest.objects.filter(
        SP_Period=sp_period).values_list("email", flat=True))
089c0115   Alexis Koralewski   add new version (...
546
    # User is observer and not from this SP
5a434264   Alexis Koralewski   New version of Sc...
547
548
549
550
551
552
553
    if request.session.get("role") == "Observer":
        if sp_pi!=request.user and not SP_Period_User.objects.filter(SP_Period=sp_period, user=PyrosUser.objects.get(id=request.user.id)).exists():
            return HttpResponseRedirect(reverse("index_scientific_program"))
    CAN_OBSERVER_EDIT = request.session.get("role") in ("Admin","Observer") and sp_pi == request.user and sp_period.status == SP_Period.STATUSES_DRAFT
    CAN_TAC_EVALUATE = request.session.get("role") in ("Admin","TAC") and sp_period.status == SP_Period.STATUSES_SUBMITTED
    CAN_UNIT_PI_VALIDATE = request.session.get("role") in ("Unit-PI","Unit-board") and sp_period.status == SP_Period.STATUSES_EVALUATED
    CAN_OBSERVER_DELETE = request.session.get("role") in ("Admin","Observer") and sp_period.status == SP_Period.STATUSES_DRAFT
e00964fc   Alexis Koralewski   new version of ti...
554
    CAN_VIEW_TAC_VOTES = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
cffa6238   Alexis Koralewski   fixing who can su...
555
    CAN_SUBMIT_PROPOSAL = request.user == sp_pi and request.session.get("role") == "Observer" and sp_period.status == SP_Period.STATUSES_DRAFT
5a434264   Alexis Koralewski   New version of Sc...
556
557
558
559
560
561
562
563
564
565
566
567
    return render(request, 'scientific_program/scientific_program_period_detail.html', {
        'scientific_program': scientific_program,
        "users": users_informations,
        "sp_pi": sp_pi,
        "period": sp_period.period,
        "guests": guests,
        "sp_period": sp_period,
        "CAN_OBSERVER_EDIT": CAN_OBSERVER_EDIT,
        "CAN_TAC_EVALUATE": CAN_TAC_EVALUATE,
        "CAN_UNIT_PI_VALIDATE": CAN_UNIT_PI_VALIDATE,
        "CAN_OBSERVER_DELETE": CAN_OBSERVER_DELETE,
        "is_proposal": True,
cffa6238   Alexis Koralewski   fixing who can su...
568
569
        "CAN_VIEW_TAC_VOTES": CAN_VIEW_TAC_VOTES,
        "CAN_SUBMIT_PROPOSAL": CAN_SUBMIT_PROPOSAL
5a434264   Alexis Koralewski   New version of Sc...
570
    })
089c0115   Alexis Koralewski   add new version (...
571

5a434264   Alexis Koralewski   New version of Sc...
572
573

@level_required("Admin", "Unit-PI", "Observer")
089c0115   Alexis Koralewski   add new version (...
574
@login_required()
5a434264   Alexis Koralewski   New version of Sc...
575
576
577
578
579
580
581
582
583
584
def submit_proposal(request, id):
    sp_period = SP_Period.objects.get(id=id)
    if sp_period.status == SP_Period.STATUSES_DRAFT:
        sp_period.status = SP_Period.STATUSES_SUBMITTED
        sp_period.save()
    return HttpResponseRedirect(reverse("detail_scientific_program_period", args=[sp_period.scientific_program.id, sp_period.period.id]))


@level_required("Admin", "Unit-PI", "Observer")
@login_required()
e00964fc   Alexis Koralewski   new version of ti...
585
586
587
588
589
590
591
592
def delete_scientific_program(request, id_sp):
    scientific_program = get_object_or_404(ScientificProgram, pk=id_sp)
    sp_periods = SP_Period.objects.filter(scientific_program=scientific_program)
    if sp_periods:
        for sp_period in sp_periods:
            SP_Period_User.objects.filter(SP_Period=sp_period).delete()
            SP_Period_Guest.objects.filter(SP_Period=sp_period).delete()
        sp_periods.delete()
5a434264   Alexis Koralewski   New version of Sc...
593
    scientific_program.delete()
e00964fc   Alexis Koralewski   new version of ti...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
    return HttpResponseRedirect(reverse('index_scientific_program'))

@level_required("Admin", "Unit-PI", "Observer")
@login_required()
def delete_scientific_program_period(request, id_sp, id_period):
    scientific_program = get_object_or_404(ScientificProgram, pk=id_sp)
    sp_period = SP_Period.objects.get(
        scientific_program=scientific_program, period=Period.objects.get(id=id_period))
    if sp_period.status == SP_Period.STATUSES_DRAFT:
        sp_period_users = SP_Period_User.objects.filter(SP_Period=sp_period)
        sp_period_guests = SP_Period_Guest.objects.filter(SP_Period=sp_period)
        sp_period_guests.delete()
        sp_period_users.delete()
        sp_period.delete()
    return HttpResponseRedirect(reverse('detail_scientific_program',args=[scientific_program.id]))
089c0115   Alexis Koralewski   add new version (...
609
610
611


@login_required
b414eec1   Alexis Koralewski   improving user ac...
612
@level_required("Admin", "Unit-PI", "Observer", "Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
613
614
615
616
def scientific_program_list(request):
    sp_of_user = []
    # get sp_period where the period is an active period and are accepted
    scientific_programs = ScientificProgram.objects.all().order_by("-id")
b414eec1   Alexis Koralewski   improving user ac...
617
618
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_VIEW_HIS_SP = request.session.get("role") == "Observer"
a444ac84   Alexis Koralewski   fixing listing of...
619
620
621
622
623
    if not CAN_VIEW_ALL_SP:
        # get all SP associated to that user
        sp_periods_of_user = SP_Period_User.objects.filter(user=request.user.id).values_list("SP_Period",flat=True)
        list_of_sp_id = SP_Period.objects.filter(id__in=sp_periods_of_user).values("scientific_program")
        sp_of_user = ScientificProgram.objects.filter(id__in=list_of_sp_id)
5a434264   Alexis Koralewski   New version of Sc...
624
625
626

    return render(request, 'scientific_program/scientific_programs.html', {
        'scientific_programs': scientific_programs,
b414eec1   Alexis Koralewski   improving user ac...
627
628
629
        "sp_of_user": sp_of_user,
        "CAN_VIEW_ALL_SP": CAN_VIEW_ALL_SP,
        "CAN_VIEW_HIS_SP": CAN_VIEW_HIS_SP
5a434264   Alexis Koralewski   New version of Sc...
630
631
632
633
634
635
636
637
638
    })


@login_required
@level_required("Observer")
def own_scientific_program_list(request):
    sp_of_user = []
    # get sp_period where the period is an active period and are accepted
    scientific_programs = ScientificProgram.objects.all().order_by("-id")
b414eec1   Alexis Koralewski   improving user ac...
639
640
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_VIEW_HIS_SP = request.session.get("role") == "Observer"
5a434264   Alexis Koralewski   New version of Sc...
641
    if (len(scientific_programs) > 0):
6f505a1d   Alexis Koralewski   fixing delete but...
642
        # get all SP where user is sp_pi
5a434264   Alexis Koralewski   New version of Sc...
643
644
        sp_of_user = ScientificProgram.objects.filter(sp_pi=request.user).order_by("-id")
    else:
089c0115   Alexis Koralewski   add new version (...
645
646
        scientific_programs = None

5a434264   Alexis Koralewski   New version of Sc...
647
648
    return render(request, 'scientific_program/scientific_programs.html', {
        'scientific_programs': scientific_programs,
b414eec1   Alexis Koralewski   improving user ac...
649
650
651
        "sp_of_user": sp_of_user,
        "CAN_VIEW_ALL_SP": CAN_VIEW_ALL_SP,
        "CAN_VIEW_HIS_SP": CAN_VIEW_HIS_SP
5a434264   Alexis Koralewski   New version of Sc...
652
653
654
655
656
657
658
659
660
661
662
663
664
    })



#Get Proposal timeline of period 

@level_required("Admin", "Unit-PI", "Observer", "TAC")
@login_required
@csrf_exempt
def get_proposal_timeline(request):
    if request.POST.get("period_id"):
        return HttpResponse(get_proposal_svg_timeline(Period.objects.get(id=request.POST["period_id"])))

089c0115   Alexis Koralewski   add new version (...
665
666
667
668

# Institute CRUD

@login_required
b414eec1   Alexis Koralewski   improving user ac...
669
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
670
671
672
673
674
675
676
def create_institute(request):
    form = InstituteForm(request.POST)
    if request.POST:
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse("institute_list"))
    form = InstituteForm()
5a434264   Alexis Koralewski   New version of Sc...
677
    return render(request, "scientific_program/create_institute.html", {"form": form})
089c0115   Alexis Koralewski   add new version (...
678
679


b414eec1   Alexis Koralewski   improving user ac...
680
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
681
@login_required
5a434264   Alexis Koralewski   New version of Sc...
682
def edit_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
683
684
685
686
687
    edit = get_object_or_404(Institute, pk=id)
    form = InstituteForm(request.POST or None, instance=edit)
    if form.is_valid():
        form.save()
        return redirect('detail_institute', id=id)
5a434264   Alexis Koralewski   New version of Sc...
688
689
    return render(request, 'scientific_program/institute_detail_edit.html', {'id': id, 'form': form})

089c0115   Alexis Koralewski   add new version (...
690

5a434264   Alexis Koralewski   New version of Sc...
691
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
089c0115   Alexis Koralewski   add new version (...
692
@login_required
5a434264   Alexis Koralewski   New version of Sc...
693
def detail_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
694
    institute = get_object_or_404(Institute, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
695
696
    representative_member = PyrosUser.objects.get(
        is_institute_representative=True, institute=institute)
089c0115   Alexis Koralewski   add new version (...
697
    scientific_programs = ScientificProgram.objects.filter(institute=institute)
b414eec1   Alexis Koralewski   improving user ac...
698
699
    CAN_EDIT_INSTITUTE = request.session.get("role") in ("Admin", "Unit-PI","Unit-board")
    CAN_DELETE_INSTITUTE = request.session.get("role") in ("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
700
701
702
    return render(request, 'scientific_program/institute_detail.html', {
        'institute': institute,
        "representative_member": representative_member,
b414eec1   Alexis Koralewski   improving user ac...
703
704
705
        "scientific_programs": scientific_programs,
        "CAN_EDIT_INSTITUTE": CAN_EDIT_INSTITUTE,
        "CAN_DELETE_INSTITUTE": CAN_DELETE_INSTITUTE
5a434264   Alexis Koralewski   New version of Sc...
706
707
708
    })


b414eec1   Alexis Koralewski   improving user ac...
709
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
710
@login_required()
5a434264   Alexis Koralewski   New version of Sc...
711
def delete_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
712
713
714
715
716
717
    institute = get_object_or_404(Institute, pk=int(id))
    institute.delete()
    return HttpResponseRedirect(reverse('institute_list'))


@login_required
5a434264   Alexis Koralewski   New version of Sc...
718
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
089c0115   Alexis Koralewski   add new version (...
719
720
def institute_list(request):
    institutes = Institute.objects.all()
b414eec1   Alexis Koralewski   improving user ac...
721
722
723
724
725
    CAN_ADD_INSTITUTE = request.session.get("role") in ("Admin", "Unit-PI", "Unit-board")
    return render(request, 'scientific_program/institutes.html', {
        'institutes': institutes,
        "CAN_ADD_INSTITUTE": CAN_ADD_INSTITUTE
    })
089c0115   Alexis Koralewski   add new version (...
726
727


5a434264   Alexis Koralewski   New version of Sc...
728
# Exploitation Periods CRUD
089c0115   Alexis Koralewski   add new version (...
729
730

@login_required
5a434264   Alexis Koralewski   New version of Sc...
731
@level_required("Admin", "Unit-PI", "Unit board")
089c0115   Alexis Koralewski   add new version (...
732
def create_period(request):
5a434264   Alexis Koralewski   New version of Sc...
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
    today = timezone.now().date()
    possible_start_date = Period.objects.aggregate(Max("end_date"))
    possible_end_date = possible_start_date["end_date__max"] + \
        relativedelta(months=+6)

    possible_start_date_as_datetime = possible_start_date["end_date__max"]
    possible_end_date_as_datetime = possible_start_date["end_date__max"] + relativedelta(
        months=+6)

    possible_start_date = datetime.strftime(
        possible_start_date["end_date__max"], "%d/%m/%Y")
    possible_end_date = datetime.strftime(possible_end_date, "%d/%m/%Y")

    possible_submission_start_date = possible_start_date_as_datetime + \
        relativedelta(months=-6)
    possible_submission_start_date = datetime.strftime(
        possible_submission_start_date, "%d/%m/%Y")

    possible_submission_end_date = possible_start_date_as_datetime + \
        relativedelta(months=-1) + relativedelta(days=-15)
    possible_submission_end_date = datetime.strftime(
        possible_submission_end_date, "%d/%m/%Y")

    possible_validation_start_date = possible_start_date_as_datetime + \
        relativedelta(days=-15)
    possible_validation_start_date = datetime.strftime(
        possible_validation_start_date, "%d/%m/%Y")

    possible_property_end_date = possible_end_date_as_datetime + \
        relativedelta(years=+1)
    possible_property_end_date = datetime.strftime(
        possible_property_end_date, "%d/%m/%Y")

    possible_accessibility_end_date = possible_end_date_as_datetime + \
        relativedelta(years=+11)
    possible_accessibility_end_date = datetime.strftime(
        possible_accessibility_end_date, "%d/%m/%Y")

b7becde4   Alexis Koralewski   Updating UI (foot...
771
    past_periods = []
5a434264   Alexis Koralewski   New version of Sc...
772
773
    active_period = Period.objects.currently_active_period()
    periods = Period.objects.all().order_by("-end_date").exclude(id=active_period.id)
b7becde4   Alexis Koralewski   Updating UI (foot...
774
    for period in periods:
5a434264   Alexis Koralewski   New version of Sc...
775
776
        if active_period != None:
            past_periods.append(period)
089c0115   Alexis Koralewski   add new version (...
777
778
779
    error = False
    error_message = ""
    if request.POST:
5a434264   Alexis Koralewski   New version of Sc...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
        start_date = datetime.strptime(
            request.POST.get("start_date_picker"), "%d/%m/%Y")
        end_date = datetime.strptime(
            request.POST.get("end_date_picker"), "%d/%m/%Y")
        submission_start_date = datetime.strptime(
            request.POST.get("submission_start_date_picker"), "%d/%m/%Y")
        submission_end_date = datetime.strptime(
            request.POST.get("submission_end_date_picker"), "%d/%m/%Y")
        unit_pi_start_validation_date = datetime.strptime(
            request.POST.get("unit_pi_start_validation_date_picker"), "%d/%m/%Y")
        property_data_end_date = datetime.strptime(
            request.POST.get("property_data_end_date_picker"), "%d/%m/%Y")
        accessibility_data_end_date = datetime.strptime(
            request.POST.get("accessibility_data_end_date_picker"), "%d/%m/%Y")
089c0115   Alexis Koralewski   add new version (...
794
795
796
        # most common check
        if start_date != end_date and end_date > start_date:
            # get all future periods
5a434264   Alexis Koralewski   New version of Sc...
797
798
            future_periods = Period.objects.filter(
                end_date__gte=today).order_by("end_date")
089c0115   Alexis Koralewski   add new version (...
799
            for future_period in future_periods:
5a434264   Alexis Koralewski   New version of Sc...
800
                # check if submitted period isn't covering an existing period
089c0115   Alexis Koralewski   add new version (...
801
802
803
804
                if start_date.date() < future_period.end_date and end_date.date() > future_period.start_date:
                    error_message = f"Period already covered ({future_period})"
                    error = True
                    break
5a434264   Alexis Koralewski   New version of Sc...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
            if submission_start_date > unit_pi_start_validation_date:
                error_message += f"submission start date ({submission_start_date}) should start before Unit-PI validation date ({unit_pi_start_validation_date})"
                error = True

            if submission_end_date > unit_pi_start_validation_date:
                error_message += f"submission end date ({submission_end_date}) should end before Unit-PI validation date ({unit_pi_start_validation_date})"
                error = True
            if unit_pi_start_validation_date > start_date:
                error_message += f"Unit-PI validation date ({unit_pi_start_validation_date}) should end before period start date ({start_date})"
                error = True
            if property_data_end_date < end_date:
                error_message += f"Property data end date ({property_data_end_date}) should start after period end date ({end_date})"
                error = True
            if accessibility_data_end_date < property_data_end_date:
                error_message += f"Accessibility data end date ({accessibility_data_end_date}) should start after property data end date ({property_data_end_date})"
                error = True
089c0115   Alexis Koralewski   add new version (...
821
822
823
824
            if not error:
                new_period = Period.objects.create()
                new_period.start_date = start_date
                new_period.end_date = end_date
5a434264   Alexis Koralewski   New version of Sc...
825
826
827
828
829
                new_period.submission_start_date = submission_start_date
                new_period.submission_end_date = submission_end_date
                new_period.unit_pi_validation_start_date = unit_pi_start_validation_date
                new_period.property_of_data_end_date = property_data_end_date
                new_period.data_accessibility_end_date = accessibility_data_end_date
089c0115   Alexis Koralewski   add new version (...
830
831
832
                new_period.save()
                return HttpResponseRedirect(reverse("period_list"))

5a434264   Alexis Koralewski   New version of Sc...
833
834
835
836
837
838
839
840
841
842
843
844
845
    return render(request, "scientific_program/create_period.html", {
        "error_message": error_message,
        "error": error,
        "past_periods": past_periods,
        "active_period": active_period,
        "possible_start_date": possible_start_date,
        "possible_end_date": possible_end_date,
        "possible_submission_start_date": possible_submission_start_date,
        "possible_submission_end_date": possible_submission_end_date,
        "possible_validation_start_date": possible_validation_start_date,
        "possible_property_end_date": possible_property_end_date,
        "possible_accessibility_end_date": possible_accessibility_end_date
    })
089c0115   Alexis Koralewski   add new version (...
846
847
848


@login_required
b414eec1   Alexis Koralewski   improving user ac...
849
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
850
def edit_period(request, id):
089c0115   Alexis Koralewski   add new version (...
851
    edit = get_object_or_404(Period, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
852
853
854
855
856
857
858
859
860
    today = timezone.now().date()
    past_periods = []
    active_period = Period.objects.currently_active_period()
    periods = Period.objects.all().order_by("-end_date").exclude(id=active_period.id)
    for period in periods:
        if active_period != None:
            past_periods.append(period)
    error = False
    error_message = ""
089c0115   Alexis Koralewski   add new version (...
861
    if request.POST:
5a434264   Alexis Koralewski   New version of Sc...
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
        start_date = datetime.strptime(
            request.POST.get("start_date_picker"), "%d/%m/%Y")
        end_date = datetime.strptime(
            request.POST.get("end_date_picker"), "%d/%m/%Y")
        submission_start_date = datetime.strptime(
            request.POST.get("submission_start_date_picker"), "%d/%m/%Y")
        submission_end_date = datetime.strptime(
            request.POST.get("submission_end_date_picker"), "%d/%m/%Y")
        unit_pi_start_validation_date = datetime.strptime(
            request.POST.get("unit_pi_start_validation_date_picker"), "%d/%m/%Y")
        property_data_end_date = datetime.strptime(
            request.POST.get("property_data_end_date_picker"), "%d/%m/%Y")
        accessibility_data_end_date = datetime.strptime(
            request.POST.get("accessibility_data_end_date_picker"), "%d/%m/%Y")
        # most common check
089c0115   Alexis Koralewski   add new version (...
877
        if start_date != end_date and end_date > start_date:
5a434264   Alexis Koralewski   New version of Sc...
878
879
            # get all future periods
            future_periods = Period.objects.filter(
b414eec1   Alexis Koralewski   improving user ac...
880
                end_date__gte=today).order_by("end_date").exclude(id=edit.id)
5a434264   Alexis Koralewski   New version of Sc...
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
            for future_period in future_periods:
                # check if submitted period isn't covering an existing period
                if start_date.date() < future_period.end_date and end_date.date() > future_period.start_date:
                    error_message = f"Period already covered ({future_period})"
                    error = True
                    break
            if submission_start_date > unit_pi_start_validation_date:
                error_message += f"submission start date ({submission_start_date}) should start before Unit-PI validation date ({unit_pi_start_validation_date})"
                error = True

            if submission_end_date > unit_pi_start_validation_date:
                error_message += f"submission end date ({submission_end_date}) should end before Unit-PI validation date ({unit_pi_start_validation_date})"
                error = True
            if unit_pi_start_validation_date > start_date:
                error_message += f"Unit-PI validation date ({unit_pi_start_validation_date}) should end before period start date ({start_date})"
                error = True
            if property_data_end_date < end_date:
                error_message += f"Property data end date ({property_data_end_date}) should start after period end date ({end_date})"
                error = True
            if accessibility_data_end_date < property_data_end_date:
                error_message += f"Accessibility data end date ({accessibility_data_end_date}) should start after property data end date ({property_data_end_date})"
                error = True
            if not error:
5a434264   Alexis Koralewski   New version of Sc...
904
905
906
907
908
909
910
911
                edit.start_date = start_date
                edit.end_date = end_date
                edit.submission_start_date = submission_start_date
                edit.submission_end_date = submission_end_date
                edit.unit_pi_validation_start_date = unit_pi_start_validation_date
                edit.property_of_data_end_date = property_data_end_date
                edit.data_accessibility_end_date = accessibility_data_end_date
                edit.save()
b414eec1   Alexis Koralewski   improving user ac...
912
913
                return redirect('detail_period', id=id)
            
5a434264   Alexis Koralewski   New version of Sc...
914
915
916
917
918
919
920
921
    return render(request, 'scientific_program/period_detail_edit.html', {
        'id': id,
        'period': edit,
        "error_message": error_message,
        "error": error,
        "past_periods": past_periods,
        "active_period": active_period
    })
089c0115   Alexis Koralewski   add new version (...
922
923
924


@login_required
b414eec1   Alexis Koralewski   improving user ac...
925
@level_required("Admin", "Unit-PI", "Unit-board", "Observer")
5a434264   Alexis Koralewski   New version of Sc...
926
def detail_period(request, id):
089c0115   Alexis Koralewski   add new version (...
927
928
    period = get_object_or_404(Period, pk=id)
    sp_periods = SP_Period.objects.filter(period=period)
5a434264   Alexis Koralewski   New version of Sc...
929
930
931
932
    sp_of_user = SP_Period_User.objects.filter(
        user=request.user.id, SP_Period__in=sp_periods)
    today = timezone.now().date()
    is_period_public = period.end_date < today and period.start_date < today
b414eec1   Alexis Koralewski   improving user ac...
933
934
935
936
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_VIEW_HIS_SP = request.session.get("role") == "Observer"
    CAN_EDIT_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_DELETE_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board") and not sp_periods
5a434264   Alexis Koralewski   New version of Sc...
937
938
939
940
    return render(request, 'scientific_program/period_detail.html', {
        'period': period,
        "sp_periods": sp_periods,
        "sp_of_user": sp_of_user,
b414eec1   Alexis Koralewski   improving user ac...
941
942
943
944
945
        "is_period_public": is_period_public,
        "CAN_VIEW_ALL_SP": CAN_VIEW_ALL_SP,
        "CAN_VIEW_HIS_SP": CAN_VIEW_HIS_SP,
        "CAN_EDIT_PERIOD": CAN_EDIT_PERIOD,
        "CAN_DELETE_PERIOD": CAN_DELETE_PERIOD
5a434264   Alexis Koralewski   New version of Sc...
946
947
    })

089c0115   Alexis Koralewski   add new version (...
948
949

@login_required()
b414eec1   Alexis Koralewski   improving user ac...
950
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
951
def delete_period(request, id):
089c0115   Alexis Koralewski   add new version (...
952
953
954
955
956
957
    period = get_object_or_404(Period, pk=int(id))
    period.delete()
    return HttpResponseRedirect(reverse('period_list'))


@login_required
b414eec1   Alexis Koralewski   improving user ac...
958
@level_required("Admin", "Unit-PI", "Observer", "Unit-board")
089c0115   Alexis Koralewski   add new version (...
959
def period_list(request):
5a434264   Alexis Koralewski   New version of Sc...
960
961
    today = timezone.now().date()
    periods = Period.objects.all().order_by("-end_date")
089c0115   Alexis Koralewski   add new version (...
962
963
    future_periods = []
    past_periods = []
5a434264   Alexis Koralewski   New version of Sc...
964
    active_period = Period.objects.currently_active_period()
b414eec1   Alexis Koralewski   improving user ac...
965
    CAN_ADD_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
966
    for period in periods:
5a434264   Alexis Koralewski   New version of Sc...
967
968
        if period == active_period:
            future_periods.insert(0, period)
089c0115   Alexis Koralewski   add new version (...
969
        else:
5a434264   Alexis Koralewski   New version of Sc...
970
            if period.start_date >= today and period.end_date >= today:
089c0115   Alexis Koralewski   add new version (...
971
972
973
                future_periods.append(period)
            else:
                past_periods.append(period)
b414eec1   Alexis Koralewski   improving user ac...
974
975
976
977
978
    return render(request, 'scientific_program/periods.html', {
        'past_periods': past_periods,
        "future_periods": future_periods,
        "CAN_ADD_PERIOD": CAN_ADD_PERIOD
    })