Blame view

src/core/pyros_django/scientific_program/views.py 61 KB
eefbbbd2   Etienne Pallier   Model splitting g...
1
2
3
4
5
6
7
# Standard imports
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
import matplotlib.pyplot as plt
import re,io,urllib,base64

# Django imports
5a434264   Alexis Koralewski   New version of Sc...
8
from django.http.response import HttpResponse
5a434264   Alexis Koralewski   New version of Sc...
9
10
from django.shortcuts import render, redirect, get_object_or_404, reverse
from django.contrib.auth import authenticate, login
089c0115   Alexis Koralewski   add new version (...
11
from django.contrib.auth.decorators import login_required
089c0115   Alexis Koralewski   add new version (...
12
from django.http import HttpResponseRedirect
5a434264   Alexis Koralewski   New version of Sc...
13
14
15
from django.conf import settings
from django.core.mail import send_mail
from django.db.models import Max
5a434264   Alexis Koralewski   New version of Sc...
16
17
from django.utils import timezone
from django.db.models import Q,F
5a434264   Alexis Koralewski   New version of Sc...
18
from django.views.decorators.csrf import csrf_exempt
b4f6db4d   Alexis Koralewski   Adding Sequences ...
19
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
eefbbbd2   Etienne Pallier   Model splitting g...
20
21

# Project imports
42bf33a2   Alexis Koralewski   renaming configpy...
22
from config.pyros.config_pyros import ConfigPyros
eefbbbd2   Etienne Pallier   Model splitting g...
23
24
25
26
27
28
29
30
31
32
33
from .functions import get_global_svg_timeline, get_svg_timeline, get_proposal_svg_timeline
from user_manager.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, SP_Period_Guest, ScienceTheme   #, UserLevel
from routine_manager.models import Sequence
#from src.core.pyros_django import scientific_program
from .forms import PeriodForm, ScienceThemeForm, ScientificProgramForm, InstituteForm, SP_PeriodForm,TACAssociationForm
from src.core.pyros_django.dashboard.decorator import level_required





089c0115   Alexis Koralewski   add new version (...
34
# Scientific program CRUD
5a434264   Alexis Koralewski   New version of Sc...
35

ad3b297c   Alexis Koralewski   add pagination to...
36
37
#NB_ELEMENT_PER_PAGE = configpyros(os.environ["pyros_config_file"]).pyros_config.get("general").get("nb_element_per_page")

5a434264   Alexis Koralewski   New version of Sc...
38
39
40
41
42

@login_required
@level_required("Admin", "Observer","TAC","Unit-PI","Unit-board")
def index_scientific_program(request):
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
43
44
    """

5a434264   Alexis Koralewski   New version of Sc...
45
46
47
48
49
50
    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()
077d5a23   Alexis Koralewski   adding science th...
51
    current_period = Period.objects.exploitation_period()
5a434264   Alexis Koralewski   New version of Sc...
52
53
54
55
56
57
    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)
077d5a23   Alexis Koralewski   adding science th...
58
    """
a6e63604   Alexis Koralewski   adding agentSP an...
59
    does_next_period_exist = Period.objects.next_period() != None
077d5a23   Alexis Koralewski   adding science th...
60
61
62
63
64
    current_period = Period.objects.exploitation_period()
    future_period = Period.objects.filter(start_date__gte=current_period.end_date).first()
    previous_period = Period.objects.previous_periods().first()
    evaluation_periods = Period.objects.evaluation_periods()
    validation_periods = Period.objects.validation_periods()
5a434264   Alexis Koralewski   New version of Sc...
65
66
    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
a6e63604   Alexis Koralewski   adding agentSP an...
67
    does_next_period_need_tac_association = Period.objects.next_period() in Period.objects.submission_periods()
5a434264   Alexis Koralewski   New version of Sc...
68
69
70
71
    # 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 
912ecc8f   Alexis Koralewski   Change location o...
72
        date_diff_today_end_of_property = temp.days * 0.85 
5a434264   Alexis Koralewski   New version of Sc...
73
74
    else:
        temp = today - current_period.start_date 
912ecc8f   Alexis Koralewski   Change location o...
75
        date_diff_today_end_of_property = (temp.days / 8) + 15
5a434264   Alexis Koralewski   New version of Sc...
76
77
78
79
80
81
82
    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")
a6e63604   Alexis Koralewski   adding agentSP an...
83
    CAN_ASSOCIATE_TAC_TO_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board") and does_next_period_need_tac_association
5a434264   Alexis Koralewski   New version of Sc...
84
85
86
87
88
89
90
91
92
93
94
95
96
    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,
a6e63604   Alexis Koralewski   adding agentSP an...
97
        "CAN_EVALUATE_SP": CAN_EVALUATE_SP,
5a434264   Alexis Koralewski   New version of Sc...
98
99
100
101
        "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,
641ec717   Alexis Koralewski   add form to assoc...
102
103
        "CAN_VIEW_ALL_SP": CAN_VIEW_ALL_SP,
        "CAN_ASSOCIATE_TAC_TO_SP":CAN_ASSOCIATE_TAC_TO_SP
5a434264   Alexis Koralewski   New version of Sc...
104
105
    })

089c0115   Alexis Koralewski   add new version (...
106
@login_required
5a434264   Alexis Koralewski   New version of Sc...
107
108
109
@level_required("Admin", "Observer")
def create_scientific_program(request):
    SP_form = ScientificProgramForm()
089c0115   Alexis Koralewski   add new version (...
110
    if request.POST:
5a434264   Alexis Koralewski   New version of Sc...
111
112
113
114
        SP_form = ScientificProgramForm(request.POST)
        if SP_form.is_valid():
            institute = request.user.institute
            temp_SP = SP_form.save(commit=False)
077d5a23   Alexis Koralewski   adding science th...
115
116
            if institute == "CNES":
                temp_SP.is_auto_validated = True
5a434264   Alexis Koralewski   New version of Sc...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
            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()
077d5a23   Alexis Koralewski   adding science th...
131
132
    #next_periods = Period.objects.filter(submission_start_date__lte=today,submission_end_date__gt=today, start_date__gt=today)
    next_periods = Period.objects.submission_periods()
e00964fc   Alexis Koralewski   new version of ti...
133
    is_sp_reproposed = False
5a434264   Alexis Koralewski   New version of Sc...
134
135
136
137
138
139
140
141
142
143
144
    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
        }
077d5a23   Alexis Koralewski   adding science th...
145
        
5a434264   Alexis Koralewski   New version of Sc...
146
        period_id_to_be_excluded = SP_Period.objects.filter(scientific_program=sp_period_template.scientific_program).values_list("period",flat=True)
077d5a23   Alexis Koralewski   adding science th...
147
        next_periods = Period.objects.submission_periods().exclude(id__in=period_id_to_be_excluded)
5a434264   Alexis Koralewski   New version of Sc...
148
        SP_Period_form = SP_PeriodForm(initial=initial_data)
e00964fc   Alexis Koralewski   new version of ti...
149
        is_sp_reproposed = True
5a434264   Alexis Koralewski   New version of Sc...
150
151
152
153
154
    #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...
155
    recipient_list = []
5a434264   Alexis Koralewski   New version of Sc...
156
157
158
159
160
    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 (...
161
162
163
                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...
164
            """
e00964fc   Alexis Koralewski   new version of ti...
165
            if not is_sp_reproposed and request.POST.get("users"):
5a434264   Alexis Koralewski   New version of Sc...
166
167
                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...
168
                
5a434264   Alexis Koralewski   New version of Sc...
169
170
171
172
173
174
                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...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
            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...
200
201
202
203
204
205
206
207
208
209
                    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...
210
211
                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...
212
                    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...
213
214
215
216
217
                    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...
218
219
220
221
222
    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...
223
224
        "next_periods": next_periods,
        "is_sp_reproposed":is_sp_reproposed
5a434264   Alexis Koralewski   New version of Sc...
225
226
227
228
229
230
    })





089c0115   Alexis Koralewski   add new version (...
231
@login_required
5a434264   Alexis Koralewski   New version of Sc...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
@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,
    })

641ec717   Alexis Koralewski   add form to assoc...
249
250
251
252
253
254
255

@login_required
@level_required("Admin","Unit-PI","Unit-board")
def list_drafted_scientific_program(request):
    select_message = "Select an SP to associate TAC users to it for the incomming evaluation time"
    none_message = f"There is no existing SP to be associated with TAC users for a new exploitation period"
    non_autovalidated_sp = ScientificProgram.objects.exclude(is_auto_validated=True)
a6e63604   Alexis Koralewski   adding agentSP an...
256
257
    #sp_periods_without_tac =  SP_Period.objects.filter(scientific_program__in=non_autovalidated_sp,period=Period.objects.submission_periods().first()).filter(Q(referee1=None)|Q(referee2=None)).order_by("scientific_program__science_theme")
    sp_periods_without_tac =  SP_Period.objects.filter(scientific_program__in=non_autovalidated_sp,period=Period.objects.submission_periods().first()).order_by("scientific_program__science_theme")
641ec717   Alexis Koralewski   add form to assoc...
258
259
260
261
262
263
264
    return render(request, "scientific_program/list_of_scientific_program_select.html", {
        "select_message": select_message,
        "none_message": none_message,
        "list_of_sp": sp_periods_without_tac,
        "associate_tac_to_sp":True
    })

5a434264   Alexis Koralewski   New version of Sc...
265
266
267
268
269
@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...
270
    sp_where_user_is_sp_pi = ScientificProgram.objects.filter(sp_pi=request.user)
e00964fc   Alexis Koralewski   new version of ti...
271
272
273
274
275
    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...
276
277
    #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")
077d5a23   Alexis Koralewski   adding science th...
278
    #sp_period_active_of_user = SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi,period=Period.objects.exploitation_period())
5a434264   Alexis Koralewski   New version of Sc...
279
    sp_period_of_user = []
b414eec1   Alexis Koralewski   improving user ac...
280
281
    # 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...
282
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
283
284
    #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)
    next_proposal_periods = Period.objects.submission_periods().values_list("id",flat=True)
5a434264   Alexis Koralewski   New version of Sc...
285
    for sp in sp_where_user_is_sp_pi:
e00964fc   Alexis Koralewski   new version of ti...
286
287
288
289
        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...
290
291
292
293
294
295
296
297
298
299
            # 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...
300
    #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...
301
302
303
304
    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...
305
    if len(list_of_sp) ==  0 and len(list_of_sp_to_be_proposed) == 0:
5a434264   Alexis Koralewski   New version of Sc...
306
307
308
309
310
311
312
        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...
313
        "list_of_sp_to_be_proposed":list_of_sp_to_be_proposed,
5a434264   Alexis Koralewski   New version of Sc...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
        "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()
077d5a23   Alexis Koralewski   adding science th...
345
346
347
    #next_period = Period.objects.filter(
    #    start_date__gte=today, submission_end_date__lte=today,unit_pi_validation_start_date_gt=today).first()
    next_period = Period.objects.evaluation_periods().first()
5a434264   Alexis Koralewski   New version of Sc...
348
349
    none_message = f"There is no SP to be evaluated for next exploitation period {next_period}"
    # Note : ~Q mean not query
a6e63604   Alexis Koralewski   adding agentSP an...
350
351
352
353
    #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_sp = SP_Period.objects.filter(status=SP_Period.STATUSES_SUBMITTED, period=next_period)
5a434264   Alexis Koralewski   New version of Sc...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
    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...
368
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
369
370
371
def list_evaluated_scientific_program(request):
    select_message = "Please select a SP from the list below for validation:"
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
372
373
374
    #next_period = Period.objects.filter(
    #    start_date__gte=today, submission_start_date__lte=today).first()
    next_period = Period.objects.validation_periods().first()
5a434264   Alexis Koralewski   New version of Sc...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
    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...
393
394
395
396
    """
    An invitation to join an SP is valid until the end of Exploitation period

    """
5a434264   Alexis Koralewski   New version of Sc...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
    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"))
a6e63604   Alexis Koralewski   adding agentSP an...
411

641ec717   Alexis Koralewski   add form to assoc...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
@login_required
@level_required("Admin", "Unit-PI", "Unit-board")
def associate_tac_to_scientific_program(request,id_sp,id_period):
    scientific_program = ScientificProgram.objects.get(id=id_sp)
    period = Period.objects.get(id=id_period)
    sp_period = SP_Period.objects.get(scientific_program=scientific_program,period=period)
    form = TACAssociationForm(request.POST or None,instance=sp_period)
    tac_users_of_science_theme = PyrosUser.objects.filter(user_level__name="TAC",referee_themes=scientific_program.science_theme)
    form.fields["referee1"].queryset = tac_users_of_science_theme
    form.fields["referee2"].queryset = tac_users_of_science_theme
    if request.POST:
        form = TACAssociationForm(request.POST)
        form.fields["referee1"].queryset = tac_users_of_science_theme
        form.fields["referee2"].queryset = tac_users_of_science_theme
        if form.is_valid():
            referee1 = PyrosUser.objects.get(id=request.POST.get("referee1"))
            referee2 = PyrosUser.objects.get(id=request.POST.get("referee2"))
            sp_period.referee1 = referee1
            sp_period.referee2 = referee2
            sp_period.save()
            return HttpResponseRedirect(reverse("list_drafted_scientific_program"))
    return render(request,"scientific_program/associate_tac_to_sp.html",{
        "form":form
    })
5a434264   Alexis Koralewski   New version of Sc...
436
437
438
439
440
441
442
443
444
445
446
447

@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...
448
    period=Period.objects.get(id=id_period)
5a434264   Alexis Koralewski   New version of Sc...
449
450
    SP_Period_form = SP_PeriodForm(request.POST or None, instance=sp_period)
    sp_pi = scientific_program.sp_pi
089c0115   Alexis Koralewski   add new version (...
451
    if request.session.get("role") == "Observer" and request.user.id != sp_pi.id:
5a434264   Alexis Koralewski   New version of Sc...
452
453
454
455
456
457
458
459
        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...
460
461
462
463
    error = False
    error_message = ""
    list_of_emails = None
    recipient_list = []
089c0115   Alexis Koralewski   add new version (...
464
    if request.POST:
a6e63604   Alexis Koralewski   adding agentSP an...
465
466
        if SPForm.is_valid() and sp_period.status == SP_Period.STATUSES_DRAFT:
            SPForm.save()
cffa6238   Alexis Koralewski   fixing who can su...
467
        if SP_Period_form.is_valid():
a6e63604   Alexis Koralewski   adding agentSP an...
468
469
            if sp_period.status == SP_Period.STATUSES_DRAFT:
                SP_period = SP_Period_form.save()   
cffa6238   Alexis Koralewski   fixing who can su...
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
499
500
501
502
503
504
505
506
507
            # 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,
                                )
a6e63604   Alexis Koralewski   adding agentSP an...
508
                    
cffa6238   Alexis Koralewski   fixing who can su...
509
                else:
a6e63604   Alexis Koralewski   adding agentSP an...
510
                    return render(request, 'scientific_program/scientific_program_period_detail_edit.html', {
cffa6238   Alexis Koralewski   fixing who can su...
511
512
513
514
515
516
517
518
519
520
                            '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
                        })
cffa6238   Alexis Koralewski   fixing who can su...
521
                # save changes on user list 
a6e63604   Alexis Koralewski   adding agentSP an...
522
                
cffa6238   Alexis Koralewski   fixing who can su...
523
                return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
5a434264   Alexis Koralewski   New version of Sc...
524
525
        if SP_Period_form.is_valid() and request.session.get("role") == "TAC" and sp_period.status != SP_Period.STATUSES_DRAFT:
            # vote TAC
641ec717   Alexis Koralewski   add form to assoc...
526
527
            if sp_period.referee1 == request.user:
                print("vote referee 1 ")
5a434264   Alexis Koralewski   New version of Sc...
528
529
530
531
532
533
                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()
5a434264   Alexis Koralewski   New version of Sc...
534
535
536
                #if sp_period.referee2 != None:
                    #sp_period.status = SP_Period.STATUSES_EVALUATED
                sp_period.save()
641ec717   Alexis Koralewski   add form to assoc...
537
538
            if sp_period.referee2 == request.user:
                print("vote referee 2 ")
5a434264   Alexis Koralewski   New version of Sc...
539
540
541
542
543
544
                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()
5a434264   Alexis Koralewski   New version of Sc...
545
546
547
548
                #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)
a6e63604   Alexis Koralewski   adding agentSP an...
549
        elif SP_Period_form.is_valid() and request.session.get("role") in ["Admin","Unit-PI", "Unit-board"] and sp_period.status in [SP_Period.STATUSES_EVALUATED, SP_Period.STATUSES_ACCEPTED, SP_Period.STATUSES_REJECTED]:
5a434264   Alexis Koralewski   New version of Sc...
550
551
552
            #if request.POST.get("is_valid") != None:
                #sp_period.status = request.POST.get("is_valid")
            SP_Period_form.save()
5a434264   Alexis Koralewski   New version of Sc...
553
554
555
            return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
        else:
            print(SP_Period_form.errors)
a6e63604   Alexis Koralewski   adding agentSP an...
556
557
558
        return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
    CAN_VIEW_TAC_VOTES = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    return render(request, 'scientific_program/scientific_program_period_detail_edit.html', {
5a434264   Alexis Koralewski   New version of Sc...
559
560
561
562
563
564
565
        '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...
566
        "sp_period": sp_period,
a6e63604   Alexis Koralewski   adding agentSP an...
567
568
        "error_message":error_message,
        "CAN_VIEW_TAC_VOTES":CAN_VIEW_TAC_VOTES
5a434264   Alexis Koralewski   New version of Sc...
569
    })
089c0115   Alexis Koralewski   add new version (...
570

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


@level_required("Admin", "Unit-PI", "Observer", "TAC")
089c0115   Alexis Koralewski   add new version (...
574
@login_required
5a434264   Alexis Koralewski   New version of Sc...
575
def detail_scientific_program(request, id):
089c0115   Alexis Koralewski   add new version (...
576
    scientific_program = get_object_or_404(ScientificProgram, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
577
578
579
    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 (...
580
    
5a434264   Alexis Koralewski   New version of Sc...
581
582
    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...
583
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
584
585
586
    #next_proposal_period =  Period.objects.filter(
    #    start_date__gt=today, submission_start_date__lte=today).order_by("start_date").first()
    next_proposal_period = Period.objects.filter(start_date__gte=Period.objects.exploitation_period().end_date).first()
6f505a1d   Alexis Koralewski   fixing delete but...
587
588
589
590
    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...
591
    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...
592
    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"))
077d5a23   Alexis Koralewski   adding science th...
593
    CAN_VIEW_IS_AUTOVALIDATED = 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...
594
595
596
597
    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...
598
        "CAN_REPROPOSE_SP": CAN_REPROPOSE_SP,
077d5a23   Alexis Koralewski   adding science th...
599
600
        "CAN_DELETE_SP": CAN_DELETE_SP,
        "CAN_VIEW_IS_AUTOVALIDATED": CAN_VIEW_IS_AUTOVALIDATED
5a434264   Alexis Koralewski   New version of Sc...
601
602
603
    })


a6e63604   Alexis Koralewski   adding agentSP an...
604
@level_required("Admin", "Unit-PI", "Observer")
5a434264   Alexis Koralewski   New version of Sc...
605
606
607
608
609
610
611
612
613
614
615
616
@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))
b4f6db4d   Alexis Koralewski   Adding Sequences ...
617
    sequences = Sequence.objects.filter(scientific_program=scientific_program,period_id=id_period).order_by("-id")
b4f6db4d   Alexis Koralewski   Adding Sequences ...
618
    page = request.GET.get('page', 1)
ad3b297c   Alexis Koralewski   add pagination to...
619
    sequences_paginator = Paginator(sequences,settings.NB_ELEMENT_PER_PAGE)
b4f6db4d   Alexis Koralewski   Adding Sequences ...
620
621
622
623
624
625
626
    try:
        sequences = sequences_paginator.page(page)
    except PageNotAnInteger:
        sequences = sequences_paginator.page(1)
    except EmptyPage:
        sequences = sequences_paginator.page(sequences_paginator.num_pages)

089c0115   Alexis Koralewski   add new version (...
627
    # User is observer and not from this SP
5a434264   Alexis Koralewski   New version of Sc...
628
629
630
631
632
633
634
    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...
635
    CAN_VIEW_TAC_VOTES = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
cffa6238   Alexis Koralewski   fixing who can su...
636
    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...
637
638
639
640
641
642
643
    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,
b4f6db4d   Alexis Koralewski   Adding Sequences ...
644
        "sequences": sequences,
5a434264   Alexis Koralewski   New version of Sc...
645
646
647
648
649
        "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...
650
651
        "CAN_VIEW_TAC_VOTES": CAN_VIEW_TAC_VOTES,
        "CAN_SUBMIT_PROPOSAL": CAN_SUBMIT_PROPOSAL
5a434264   Alexis Koralewski   New version of Sc...
652
    })
089c0115   Alexis Koralewski   add new version (...
653

5a434264   Alexis Koralewski   New version of Sc...
654
655

@level_required("Admin", "Unit-PI", "Observer")
089c0115   Alexis Koralewski   add new version (...
656
@login_required()
5a434264   Alexis Koralewski   New version of Sc...
657
658
659
660
661
662
663
664
665
666
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...
667
668
669
670
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:
a6e63604   Alexis Koralewski   adding agentSP an...
671
672
673
674
675
        # can't delete
        return HttpResponseRedirect(reverse("detail_scientific_program", args=[scientific_program.id ]))
    else:
        scientific_program.delete()
        return HttpResponseRedirect(reverse('index_scientific_program'))
e00964fc   Alexis Koralewski   new version of ti...
676
677
678
679
680
681
682
683

@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:
a6e63604   Alexis Koralewski   adding agentSP an...
684
        # Delete only if in draft status
e00964fc   Alexis Koralewski   new version of ti...
685
686
687
688
689
690
        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 (...
691
692
693


@login_required
b414eec1   Alexis Koralewski   improving user ac...
694
@level_required("Admin", "Unit-PI", "Observer", "Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
695
696
697
698
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...
699
700
    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...
701
702
703
704
705
    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...
706
707
708

    return render(request, 'scientific_program/scientific_programs.html', {
        'scientific_programs': scientific_programs,
b414eec1   Alexis Koralewski   improving user ac...
709
710
711
        "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...
712
713
714
715
716
717
718
719
720
    })


@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...
721
722
    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...
723
    if (len(scientific_programs) > 0):
6f505a1d   Alexis Koralewski   fixing delete but...
724
        # get all SP where user is sp_pi
5a434264   Alexis Koralewski   New version of Sc...
725
726
        sp_of_user = ScientificProgram.objects.filter(sp_pi=request.user).order_by("-id")
    else:
089c0115   Alexis Koralewski   add new version (...
727
728
        scientific_programs = None

5a434264   Alexis Koralewski   New version of Sc...
729
730
    return render(request, 'scientific_program/scientific_programs.html', {
        'scientific_programs': scientific_programs,
b414eec1   Alexis Koralewski   improving user ac...
731
732
733
        "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...
734
735
736
737
738
739
740
741
742
743
744
    })



#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"):
077d5a23   Alexis Koralewski   adding science th...
745
        return HttpResponse(get_proposal_svg_timeline(Period.objects.get(id=request.POST["period_id"]),request.POST["period"]))
5a434264   Alexis Koralewski   New version of Sc...
746

089c0115   Alexis Koralewski   add new version (...
747
748
749
750

# Institute CRUD

@login_required
b414eec1   Alexis Koralewski   improving user ac...
751
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
752
753
754
755
756
757
758
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...
759
    return render(request, "scientific_program/create_institute.html", {"form": form})
089c0115   Alexis Koralewski   add new version (...
760
761


b414eec1   Alexis Koralewski   improving user ac...
762
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
763
@login_required
5a434264   Alexis Koralewski   New version of Sc...
764
def edit_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
765
766
767
768
769
    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...
770
771
    return render(request, 'scientific_program/institute_detail_edit.html', {'id': id, 'form': form})

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

5a434264   Alexis Koralewski   New version of Sc...
773
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
089c0115   Alexis Koralewski   add new version (...
774
@login_required
5a434264   Alexis Koralewski   New version of Sc...
775
def detail_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
776
    institute = get_object_or_404(Institute, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
777
778
    representative_member = PyrosUser.objects.get(
        is_institute_representative=True, institute=institute)
089c0115   Alexis Koralewski   add new version (...
779
    scientific_programs = ScientificProgram.objects.filter(institute=institute)
b414eec1   Alexis Koralewski   improving user ac...
780
781
    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...
782
783
784
    return render(request, 'scientific_program/institute_detail.html', {
        'institute': institute,
        "representative_member": representative_member,
b414eec1   Alexis Koralewski   improving user ac...
785
786
787
        "scientific_programs": scientific_programs,
        "CAN_EDIT_INSTITUTE": CAN_EDIT_INSTITUTE,
        "CAN_DELETE_INSTITUTE": CAN_DELETE_INSTITUTE
5a434264   Alexis Koralewski   New version of Sc...
788
789
790
    })


b414eec1   Alexis Koralewski   improving user ac...
791
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
792
@login_required()
5a434264   Alexis Koralewski   New version of Sc...
793
def delete_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
794
795
796
797
798
799
    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...
800
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
089c0115   Alexis Koralewski   add new version (...
801
802
def institute_list(request):
    institutes = Institute.objects.all()
b414eec1   Alexis Koralewski   improving user ac...
803
804
805
806
807
    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 (...
808
809


5a434264   Alexis Koralewski   New version of Sc...
810
# Exploitation Periods CRUD
089c0115   Alexis Koralewski   add new version (...
811
812

@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
813
@level_required("Admin", "Unit-PI", "Unit-board")
089c0115   Alexis Koralewski   add new version (...
814
def create_period(request):
077d5a23   Alexis Koralewski   adding science th...
815
    form = PeriodForm()
5a434264   Alexis Koralewski   New version of Sc...
816
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
817
818
    possible_start_date = Period.objects.latest_period().end_date 
    possible_end_date = possible_start_date + \
5a434264   Alexis Koralewski   New version of Sc...
819
820
        relativedelta(months=+6)

077d5a23   Alexis Koralewski   adding science th...
821
822
    possible_start_date_as_datetime = possible_start_date
    possible_end_date_as_datetime = possible_start_date + relativedelta(
5a434264   Alexis Koralewski   New version of Sc...
823
824
825
        months=+6)

    possible_start_date = datetime.strftime(
077d5a23   Alexis Koralewski   adding science th...
826
        possible_start_date, "%d/%m/%Y")
5a434264   Alexis Koralewski   New version of Sc...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
    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...
854
    past_periods = []
077d5a23   Alexis Koralewski   adding science th...
855
    active_period = Period.objects.exploitation_period()
912ecc8f   Alexis Koralewski   Change location o...
856
857
858
    periods = Period.objects.all().order_by("-start_date")
    if active_period:
        periods.exclude(id=active_period.id)
b7becde4   Alexis Koralewski   Updating UI (foot...
859
    for period in periods:
5a434264   Alexis Koralewski   New version of Sc...
860
861
        if active_period != None:
            past_periods.append(period)
089c0115   Alexis Koralewski   add new version (...
862
863
864
    error = False
    error_message = ""
    if request.POST:
5a434264   Alexis Koralewski   New version of Sc...
865
866
        start_date = datetime.strptime(
            request.POST.get("start_date_picker"), "%d/%m/%Y")
077d5a23   Alexis Koralewski   adding science th...
867
868
        end_date = start_date + relativedelta(days=int(request.POST["exploitation_duration"]))
        """
5a434264   Alexis Koralewski   New version of Sc...
869
870
871
872
873
874
875
876
877
878
879
880
        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")
077d5a23   Alexis Koralewski   adding science th...
881
        """
089c0115   Alexis Koralewski   add new version (...
882
883
884
        # most common check
        if start_date != end_date and end_date > start_date:
            # get all future periods
5a434264   Alexis Koralewski   New version of Sc...
885
            future_periods = Period.objects.filter(
077d5a23   Alexis Koralewski   adding science th...
886
                start_date__gte=today).order_by("-start_date")
089c0115   Alexis Koralewski   add new version (...
887
            for future_period in future_periods:
5a434264   Alexis Koralewski   New version of Sc...
888
                # check if submitted period isn't covering an existing period
089c0115   Alexis Koralewski   add new version (...
889
890
891
892
                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
077d5a23   Alexis Koralewski   adding science th...
893
            """
5a434264   Alexis Koralewski   New version of Sc...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
            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
077d5a23   Alexis Koralewski   adding science th...
910
            """
089c0115   Alexis Koralewski   add new version (...
911
912
913
            if not error:
                new_period = Period.objects.create()
                new_period.start_date = start_date
077d5a23   Alexis Koralewski   adding science th...
914
915
916
917
918
919
920
921
                new_period.submission_duration = request.POST["submission_duration"]
                new_period.evaluation_duration = request.POST["evaluation_duration"]
                new_period.validation_duration = request.POST["validation_duration"]
                new_period.notification_duration = request.POST["notification_duration"]
                new_period.exploitation_duration = request.POST["exploitation_duration"]
                new_period.property_of_data_duration = request.POST["property_of_data_duration"]
                new_period.data_accessibility_duration = request.POST["data_accessibility_duration"]
                """
089c0115   Alexis Koralewski   add new version (...
922
                new_period.end_date = end_date
5a434264   Alexis Koralewski   New version of Sc...
923
924
925
926
927
                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
077d5a23   Alexis Koralewski   adding science th...
928
                """
089c0115   Alexis Koralewski   add new version (...
929
930
931
                new_period.save()
                return HttpResponseRedirect(reverse("period_list"))

5a434264   Alexis Koralewski   New version of Sc...
932
933
934
935
936
937
938
939
940
941
942
    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,
077d5a23   Alexis Koralewski   adding science th...
943
944
        "possible_accessibility_end_date": possible_accessibility_end_date,
        "form":form
5a434264   Alexis Koralewski   New version of Sc...
945
    })
089c0115   Alexis Koralewski   add new version (...
946
947
948


@login_required
b414eec1   Alexis Koralewski   improving user ac...
949
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
950
def edit_period(request, id):
089c0115   Alexis Koralewski   add new version (...
951
    edit = get_object_or_404(Period, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
952
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
953
    form = PeriodForm(instance=edit)
5a434264   Alexis Koralewski   New version of Sc...
954
    past_periods = []
077d5a23   Alexis Koralewski   adding science th...
955
956
    active_period = Period.objects.exploitation_period()
    periods = Period.objects.all().order_by("-start_date").exclude(id=active_period.id)
5a434264   Alexis Koralewski   New version of Sc...
957
958
959
960
961
    for period in periods:
        if active_period != None:
            past_periods.append(period)
    error = False
    error_message = ""
089c0115   Alexis Koralewski   add new version (...
962
    if request.POST:
5a434264   Alexis Koralewski   New version of Sc...
963
964
        start_date = datetime.strptime(
            request.POST.get("start_date_picker"), "%d/%m/%Y")
077d5a23   Alexis Koralewski   adding science th...
965
966
        end_date = start_date + relativedelta(days=request.POST["exploitation_duration"])
        """
5a434264   Alexis Koralewski   New version of Sc...
967
968
969
970
971
972
973
974
975
976
977
978
        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")
077d5a23   Alexis Koralewski   adding science th...
979
        """
5a434264   Alexis Koralewski   New version of Sc...
980
        # most common check
089c0115   Alexis Koralewski   add new version (...
981
        if start_date != end_date and end_date > start_date:
5a434264   Alexis Koralewski   New version of Sc...
982
983
            # get all future periods
            future_periods = Period.objects.filter(
077d5a23   Alexis Koralewski   adding science th...
984
                start_date__gte=today).order_by("-start_date").exclude(id=edit.id)
5a434264   Alexis Koralewski   New version of Sc...
985
986
987
988
989
990
            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
077d5a23   Alexis Koralewski   adding science th...
991
            """
5a434264   Alexis Koralewski   New version of Sc...
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
            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
077d5a23   Alexis Koralewski   adding science th...
1008
            """
5a434264   Alexis Koralewski   New version of Sc...
1009
            if not error:
5a434264   Alexis Koralewski   New version of Sc...
1010
                edit.start_date = start_date
077d5a23   Alexis Koralewski   adding science th...
1011
1012
1013
1014
1015
1016
1017
1018
                edit.submission_duration = request.POST["submission_duration"]
                edit.evaluation_duration = request.POST["evaluation_duration"]
                edit.validation_duration = request.POST["validation_duration"]
                edit.notification_duration = request.POST["notification_duration"]
                edit.exploitation_duration = request.POST["exploitation_duration"]
                edit.property_of_data_duration = request.POST["property_of_data_duration"]
                edit.data_accessibility_duration = request.POST["data_accessibility_duration"]
                """
5a434264   Alexis Koralewski   New version of Sc...
1019
1020
1021
1022
1023
1024
                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
077d5a23   Alexis Koralewski   adding science th...
1025
                """
5a434264   Alexis Koralewski   New version of Sc...
1026
                edit.save()
b414eec1   Alexis Koralewski   improving user ac...
1027
1028
                return redirect('detail_period', id=id)
            
5a434264   Alexis Koralewski   New version of Sc...
1029
1030
1031
1032
1033
1034
    return render(request, 'scientific_program/period_detail_edit.html', {
        'id': id,
        'period': edit,
        "error_message": error_message,
        "error": error,
        "past_periods": past_periods,
077d5a23   Alexis Koralewski   adding science th...
1035
1036
        "active_period": active_period,
        "form":form
5a434264   Alexis Koralewski   New version of Sc...
1037
    })
089c0115   Alexis Koralewski   add new version (...
1038
1039
1040


@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1041
@level_required("Admin", "Unit-PI",  "Observer")
5a434264   Alexis Koralewski   New version of Sc...
1042
def detail_period(request, id):
089c0115   Alexis Koralewski   add new version (...
1043
1044
    period = get_object_or_404(Period, pk=id)
    sp_periods = SP_Period.objects.filter(period=period)
5a434264   Alexis Koralewski   New version of Sc...
1045
1046
1047
1048
    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...
1049
1050
1051
1052
    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...
1053
1054
1055
1056
    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...
1057
1058
1059
1060
1061
        "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...
1062
1063
    })

089c0115   Alexis Koralewski   add new version (...
1064
1065

@login_required()
b414eec1   Alexis Koralewski   improving user ac...
1066
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
1067
def delete_period(request, id):
089c0115   Alexis Koralewski   add new version (...
1068
1069
1070
1071
1072
1073
    period = get_object_or_404(Period, pk=int(id))
    period.delete()
    return HttpResponseRedirect(reverse('period_list'))


@login_required
b414eec1   Alexis Koralewski   improving user ac...
1074
@level_required("Admin", "Unit-PI", "Observer", "Unit-board")
089c0115   Alexis Koralewski   add new version (...
1075
def period_list(request):
5a434264   Alexis Koralewski   New version of Sc...
1076
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
1077
    periods = Period.objects.all().order_by("-start_date")
089c0115   Alexis Koralewski   add new version (...
1078
1079
    future_periods = []
    past_periods = []
077d5a23   Alexis Koralewski   adding science th...
1080
    active_period = Period.objects.exploitation_period()
b414eec1   Alexis Koralewski   improving user ac...
1081
    CAN_ADD_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
1082
    for period in periods:
5a434264   Alexis Koralewski   New version of Sc...
1083
1084
        if period == active_period:
            future_periods.insert(0, period)
089c0115   Alexis Koralewski   add new version (...
1085
        else:
5a434264   Alexis Koralewski   New version of Sc...
1086
            if period.start_date >= today and period.end_date >= today:
089c0115   Alexis Koralewski   add new version (...
1087
1088
1089
                future_periods.append(period)
            else:
                past_periods.append(period)
b414eec1   Alexis Koralewski   improving user ac...
1090
1091
1092
1093
1094
    return render(request, 'scientific_program/periods.html', {
        'past_periods': past_periods,
        "future_periods": future_periods,
        "CAN_ADD_PERIOD": CAN_ADD_PERIOD
    })
077d5a23   Alexis Koralewski   adding science th...
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117


# Science Theme CRUD

@login_required
@level_required("Admin","Unit-PI","Unit-board")
def add_science_theme(request):
    form = ScienceThemeForm()
    if request.POST:
        form = ScienceThemeForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse("science_theme_list"))
        else:
            return render(request,"scientific_program/create_science_theme.html",{
              "form":form
            })
    return render(request,"scientific_program/create_science_theme.html",{
        "form":form
    })


@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1118
@level_required("Admin","Unit-PI","TAC")
077d5a23   Alexis Koralewski   adding science th...
1119
1120
def science_theme_list(request):
    science_themes = ScienceTheme.objects.all()
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1121
    CAN_ADD_SCIENCE_THEME = request.session.get("role") in ("Admin","Unit-PI","TAC")
077d5a23   Alexis Koralewski   adding science th...
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
    return render(request,"scientific_program/science_theme_list.html",{
        "science_themes":science_themes,
        "CAN_ADD_SCIENCE_THEME": CAN_ADD_SCIENCE_THEME
    })

@login_required
@level_required("Admin","Unit-PI","Unit-board")
def detail_science_theme(request,id):
    science_theme = get_object_or_404(ScienceTheme,pk=id)
    all_scientific_programs = ScientificProgram.objects.filter(science_theme=science_theme)
    sp_of_user = None 
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1133
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","TAC") 
077d5a23   Alexis Koralewski   adding science th...
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
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
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
    CAN_EDIT_SCIENCE_THEME = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    percentage_of_user_of_that_theme = (PyrosUser.objects.filter(referee_themes__in=[science_theme]).count() / PyrosUser.objects.all().count()) * 100
    if not CAN_VIEW_ALL_SP: 
        sp_periods_of_user = SP_Period_User.objects.filter(user=request.user).values_list("SP_Period",flat=True)
        if sp_periods_of_user:
            sp_of_user = SP_Period.objects.filter(id__in=sp_periods_of_user).values_list("scientific_program",flat=True)
            sp_of_user = ScientificProgram.objects.filter(id__in=sp_of_user)
        # current member is a member of at least, one scientific program
        if sp_of_user != None:
            sp_of_user = ScientificProgram.objects.filter(sp_pi=request.user).union(sp_of_user)
        else:
            sp_of_user = ScientificProgram.objects.filter(sp_pi=request.user)
    CAN_DELETE_SCIENCE_THEME = request.session.get("role") in ("Admin","Unit-PI","Unit-board") and not all_scientific_programs
    return render(request,"scientific_program/science_theme_detail.html",{
        "science_theme": science_theme,
        "all_scientific_programs" : all_scientific_programs,
        "sp_of_user": sp_of_user,
        "CAN_VIEW_ALL_SP": CAN_VIEW_ALL_SP,
        "CAN_EDIT_SCIENCE_THEME": CAN_EDIT_SCIENCE_THEME,
        "CAN_DELETE_SCIENCE_THEME": CAN_DELETE_SCIENCE_THEME,
        "percentage_of_user_of_that_theme":percentage_of_user_of_that_theme
    })


@login_required
@level_required("Admin","Unit-PI","Unit-board")
def edit_science_theme(request,id):
    edit = get_object_or_404(ScienceTheme, pk=id)
    form = ScienceThemeForm(request.POST or None, instance=edit)
    if form.is_valid():
        form.save()
        return redirect('detail_science_theme', id=id)
    
    return render(request,"scientific_program/edit_science_theme.html",{
        "edit":edit,
        "form":form
    })

@login_required
@level_required("Admin","Unit-PI","Unit-board")
def delete_science_theme(request,id):
    science_theme = get_object_or_404(ScienceTheme, pk=int(id))
    can_delete_science_theme = ScientificProgram.objects.filter(science_theme=science_theme).count() == 0
    if can_delete_science_theme:
        science_theme.delete()
        return HttpResponseRedirect(reverse('science_theme_list'))
    return HttpResponseRedirect(reverse('detail_science_theme',args=[science_theme.id]))
        
a6e63604   Alexis Koralewski   adding agentSP an...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
def test_tac_auto(request):
    next_period = Period.objects.next_period()
    themes = ScienceTheme.objects.all()
    tac_users = PyrosUser.objects.filter(user_level__name="TAC")
    sp_id = SP_Period.objects.filter(period=next_period).filter(Q(referee1=None)|Q(referee2=None)).values("scientific_program")
    sp = ScientificProgram.objects.filter(id__in=sp_id).order_by("name")

    matrix = associate_tac_sp_auto(themes,tac_users,sp)
    fig,ax = plt.subplots(1,1)
    plt.xlabel("scientific programs")
    plt.ylabel("Number of available TAC users")
    plt.pcolor(matrix,edgecolors='k', linewidths=2)
    plt.colorbar(ticks=[0,1])
    ax.set_xticklabels(sp.values_list("name",flat=True))
    plt.yticks([i for i in range(len(tac_users))],tac_users.values_list("last_name",flat=True),rotation="45")
    #ax.set_yticklabels()
    buf = io.BytesIO()
    fig.savefig(buf,format="png")
    buf.seek(0)
    string = base64.b64encode(buf.read())
    uri = urllib.parse.quote(string)
    return render(request,"scientific_program/test_tac_auto.html",{"data":uri})