Blame view

src/core/pyros_django/scp_mgmt/views.py 61.4 KB
eefbbbd2   Etienne Pallier   Model splitting g...
1
2
3
4
# Standard imports
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
import matplotlib.pyplot as plt
46423b05   pyros_astroguita   add view for quota
5
import re,io,urllib,base64, os
eefbbbd2   Etienne Pallier   Model splitting g...
6
7

# 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
23a61124   Alexis Koralewski   Change obsconfig ...
22
from dashboard.config_pyros import ConfigPyros
eefbbbd2   Etienne Pallier   Model splitting g...
23
from .functions import get_global_svg_timeline, get_svg_timeline, get_proposal_svg_timeline
b95a693f   Alexis Koralewski   restructuration d...
24
from user_mgmt.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, SP_Period_Guest, ScienceTheme   #, UserLevel
46423b05   pyros_astroguita   add view for quota
25
from seq_submit.models import Sequence, Quota
eefbbbd2   Etienne Pallier   Model splitting g...
26
27
28
29
#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

46423b05   pyros_astroguita   add view for quota
30
from src.core.pyros_django.obs_config.obsconfig_class import OBSConfig
eefbbbd2   Etienne Pallier   Model splitting g...
31
32
33



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
    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)
b95a693f   Alexis Koralewski   restructuration d...
87
    return render(request, "scp_mgmt/index.html", {
5a434264   Alexis Koralewski   New version of Sc...
88
89
90
91
92
93
94
95
96
        "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
            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]))
b95a693f   Alexis Koralewski   restructuration d...
122
    return render(request, "scp_mgmt/create_scientific_program.html", {
5a434264   Alexis Koralewski   New version of Sc...
123
124
125
126
127
128
129
130
        "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"))
b95a693f   Alexis Koralewski   restructuration d...
218
    return render(request, "scp_mgmt/create_scientific_program_period.html", {
5a434264   Alexis Koralewski   New version of Sc...
219
220
221
222
        "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
@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]))
b95a693f   Alexis Koralewski   restructuration d...
245
    return render(request, "scp_mgmt/create_scientific_program.html", {
5a434264   Alexis Koralewski   New version of Sc...
246
247
248
        "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")
b95a693f   Alexis Koralewski   restructuration d...
258
    return render(request, "scp_mgmt/list_of_scientific_program_select.html", {
641ec717   Alexis Koralewski   add form to assoc...
259
260
261
262
263
264
        "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
        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
b95a693f   Alexis Koralewski   restructuration d...
309
    return render(request, "scp_mgmt/list_of_scientific_program_select.html", {
5a434264   Alexis Koralewski   New version of Sc...
310
311
312
        "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
        "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
b95a693f   Alexis Koralewski   restructuration d...
331
    return render(request, "scp_mgmt/list_of_scientific_program_select.html", {
5a434264   Alexis Koralewski   New version of Sc...
332
333
334
335
336
337
338
339
340
341
342
343
344
        "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
    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)

b95a693f   Alexis Koralewski   restructuration d...
359
    return render(request, "scp_mgmt/list_of_scientific_program_select.html", {
5a434264   Alexis Koralewski   New version of Sc...
360
361
362
363
364
365
366
367
        "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
    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)

b95a693f   Alexis Koralewski   restructuration d...
383
    return render(request, "scp_mgmt/list_of_scientific_program_select.html", {
5a434264   Alexis Koralewski   New version of Sc...
384
385
386
387
388
389
390
391
392
        "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
@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"))
b95a693f   Alexis Koralewski   restructuration d...
433
    return render(request,"scp_mgmt/associate_tac_to_sp.html",{
641ec717   Alexis Koralewski   add form to assoc...
434
435
        "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:
b95a693f   Alexis Koralewski   restructuration d...
510
                    return render(request, 'scp_mgmt/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
        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")
b95a693f   Alexis Koralewski   restructuration d...
558
    return render(request, 'scp_mgmt/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")
b95a693f   Alexis Koralewski   restructuration d...
594
    return render(request, 'scp_mgmt/scientific_program_detail.html', {
5a434264   Alexis Koralewski   New version of Sc...
595
596
597
        '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
b95a693f   Alexis Koralewski   restructuration d...
637
    return render(request, 'scp_mgmt/scientific_program_period_detail.html', {
5a434264   Alexis Koralewski   New version of Sc...
638
639
640
641
642
643
        '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

b95a693f   Alexis Koralewski   restructuration d...
707
    return render(request, 'scp_mgmt/scientific_programs.html', {
5a434264   Alexis Koralewski   New version of Sc...
708
        '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

b95a693f   Alexis Koralewski   restructuration d...
729
    return render(request, 'scp_mgmt/scientific_programs.html', {
5a434264   Alexis Koralewski   New version of Sc...
730
        '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()
b95a693f   Alexis Koralewski   restructuration d...
759
    return render(request, "scp_mgmt/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)
b95a693f   Alexis Koralewski   restructuration d...
770
    return render(request, 'scp_mgmt/institute_detail_edit.html', {'id': id, 'form': form})
5a434264   Alexis Koralewski   New version of Sc...
771

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")
b95a693f   Alexis Koralewski   restructuration d...
782
    return render(request, 'scp_mgmt/institute_detail.html', {
5a434264   Alexis Koralewski   New version of Sc...
783
784
        '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
    CAN_ADD_INSTITUTE = request.session.get("role") in ("Admin", "Unit-PI", "Unit-board")
b95a693f   Alexis Koralewski   restructuration d...
804
    return render(request, 'scp_mgmt/institutes.html', {
b414eec1   Alexis Koralewski   improving user ac...
805
806
807
        'institutes': institutes,
        "CAN_ADD_INSTITUTE": CAN_ADD_INSTITUTE
    })
089c0115   Alexis Koralewski   add new version (...
808
809


46423b05   pyros_astroguita   add view for quota
810
811
812
813
814
815
816
817
@login_required
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
def quota_sp(request):
    institutes = Institute.objects.all()
    scientific_programs = ScientificProgram.objects.all()
    config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"],os.environ["unit_name"])
    current_night = config.fn.date2night("now")
    current_period = Period.objects.exploitation_period()
fafd18bd   pyros_astroguita   add quota related...
818
819
    # lowest id is period line
    quota_current_night = Quota.objects.filter(id_period=current_period.id, night_id=current_night).order_by("id").first()
46423b05   pyros_astroguita   add view for quota
820
821
822
    return render(request, 'scp_mgmt/quota_sp.html', locals())


5a434264   Alexis Koralewski   New version of Sc...
823
# Exploitation Periods CRUD
089c0115   Alexis Koralewski   add new version (...
824
825

@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
826
@level_required("Admin", "Unit-PI", "Unit-board")
089c0115   Alexis Koralewski   add new version (...
827
def create_period(request):
077d5a23   Alexis Koralewski   adding science th...
828
    form = PeriodForm()
5a434264   Alexis Koralewski   New version of Sc...
829
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
830
831
    possible_start_date = Period.objects.latest_period().end_date 
    possible_end_date = possible_start_date + \
5a434264   Alexis Koralewski   New version of Sc...
832
833
        relativedelta(months=+6)

077d5a23   Alexis Koralewski   adding science th...
834
835
    possible_start_date_as_datetime = possible_start_date
    possible_end_date_as_datetime = possible_start_date + relativedelta(
5a434264   Alexis Koralewski   New version of Sc...
836
837
838
        months=+6)

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

b95a693f   Alexis Koralewski   restructuration d...
945
    return render(request, "scp_mgmt/create_period.html", {
5a434264   Alexis Koralewski   New version of Sc...
946
947
948
949
950
951
952
953
954
955
        "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...
956
957
        "possible_accessibility_end_date": possible_accessibility_end_date,
        "form":form
5a434264   Alexis Koralewski   New version of Sc...
958
    })
089c0115   Alexis Koralewski   add new version (...
959
960
961


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


@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1054
@level_required("Admin", "Unit-PI",  "Observer")
5a434264   Alexis Koralewski   New version of Sc...
1055
def detail_period(request, id):
089c0115   Alexis Koralewski   add new version (...
1056
1057
    period = get_object_or_404(Period, pk=id)
    sp_periods = SP_Period.objects.filter(period=period)
5a434264   Alexis Koralewski   New version of Sc...
1058
1059
1060
1061
    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...
1062
1063
1064
1065
    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
b95a693f   Alexis Koralewski   restructuration d...
1066
    return render(request, 'scp_mgmt/period_detail.html', {
5a434264   Alexis Koralewski   New version of Sc...
1067
1068
1069
        'period': period,
        "sp_periods": sp_periods,
        "sp_of_user": sp_of_user,
b414eec1   Alexis Koralewski   improving user ac...
1070
1071
1072
1073
1074
        "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...
1075
1076
    })

089c0115   Alexis Koralewski   add new version (...
1077
1078

@login_required()
b414eec1   Alexis Koralewski   improving user ac...
1079
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
1080
def delete_period(request, id):
089c0115   Alexis Koralewski   add new version (...
1081
1082
1083
1084
1085
1086
    period = get_object_or_404(Period, pk=int(id))
    period.delete()
    return HttpResponseRedirect(reverse('period_list'))


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


# 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:
b95a693f   Alexis Koralewski   restructuration d...
1122
            return render(request,"scp_mgmt/create_science_theme.html",{
077d5a23   Alexis Koralewski   adding science th...
1123
1124
              "form":form
            })
b95a693f   Alexis Koralewski   restructuration d...
1125
    return render(request,"scp_mgmt/create_science_theme.html",{
077d5a23   Alexis Koralewski   adding science th...
1126
1127
1128
1129
1130
        "form":form
    })


@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1131
@level_required("Admin","Unit-PI","TAC")
077d5a23   Alexis Koralewski   adding science th...
1132
1133
def science_theme_list(request):
    science_themes = ScienceTheme.objects.all()
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1134
    CAN_ADD_SCIENCE_THEME = request.session.get("role") in ("Admin","Unit-PI","TAC")
b95a693f   Alexis Koralewski   restructuration d...
1135
    return render(request,"scp_mgmt/science_theme_list.html",{
077d5a23   Alexis Koralewski   adding science th...
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
        "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...
1146
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","TAC") 
077d5a23   Alexis Koralewski   adding science th...
1147
1148
1149
1150
1151
    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:
b95a693f   Alexis Koralewski   restructuration d...
1152
            sp_of_user = SP_Period.objects.filter(id__in=sp_periods_of_user).values_list("scp_mgmt",flat=True)
077d5a23   Alexis Koralewski   adding science th...
1153
1154
1155
1156
1157
1158
1159
            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
b95a693f   Alexis Koralewski   restructuration d...
1160
    return render(request,"scp_mgmt/science_theme_detail.html",{
077d5a23   Alexis Koralewski   adding science th...
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
        "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)
    
b95a693f   Alexis Koralewski   restructuration d...
1180
    return render(request,"scp_mgmt/edit_science_theme.html",{
077d5a23   Alexis Koralewski   adding science th...
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
        "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...
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
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)
b95a693f   Alexis Koralewski   restructuration d...
1216
    return render(request,"scp_mgmt/test_tac_auto.html",{"data":uri})