Blame view

src/core/pyros_django/scientific_program/views.py 60.8 KB
5a434264   Alexis Koralewski   New version of Sc...
1
2
3
4
from django.http.response import HttpResponse
from src.core.pyros_django import scientific_program
from django.shortcuts import render, redirect, get_object_or_404, reverse
from django.contrib.auth import authenticate, login
089c0115   Alexis Koralewski   add new version (...
5
from django.contrib.auth.decorators import login_required
641ec717   Alexis Koralewski   add form to assoc...
6
from .forms import PeriodForm, ScienceThemeForm, ScientificProgramForm, InstituteForm, SP_PeriodForm,TACAssociationForm
089c0115   Alexis Koralewski   add new version (...
7
from src.core.pyros_django.dashboard.decorator import level_required
b4f6db4d   Alexis Koralewski   Adding Sequences ...
8
from common.models import ScientificProgram, Institute, Period, SP_Period_User, SP_Period, PyrosUser, UserLevel, SP_Period_Guest, ScienceTheme, Sequence
089c0115   Alexis Koralewski   add new version (...
9
from django.http import HttpResponseRedirect
5a434264   Alexis Koralewski   New version of Sc...
10
11
12
13
14
15
16
17
18
from datetime import date, datetime
from django.conf import settings
from django.core.mail import send_mail
from django.db.models import Max
from dateutil.relativedelta import relativedelta
from django.utils import timezone
from django.db.models import Q,F
from .functions import get_global_svg_timeline, get_svg_timeline, get_proposal_svg_timeline
from django.views.decorators.csrf import csrf_exempt
a6e63604   Alexis Koralewski   adding agentSP an...
19
20
import matplotlib.pyplot as plt
import re,io,urllib,base64
b4f6db4d   Alexis Koralewski   Adding Sequences ...
21
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
42bf33a2   Alexis Koralewski   renaming configpy...
22
from config.pyros.config_pyros import ConfigPyros
089c0115   Alexis Koralewski   add new version (...
23
# Scientific program CRUD
5a434264   Alexis Koralewski   New version of Sc...
24

ad3b297c   Alexis Koralewski   add pagination to...
25
26
#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...
27
28
29
30
31

@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...
32
33
    """

5a434264   Alexis Koralewski   New version of Sc...
34
35
36
37
38
39
    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...
40
    current_period = Period.objects.exploitation_period()
5a434264   Alexis Koralewski   New version of Sc...
41
42
43
44
45
46
    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...
47
    """
a6e63604   Alexis Koralewski   adding agentSP an...
48
    does_next_period_exist = Period.objects.next_period() != None
077d5a23   Alexis Koralewski   adding science th...
49
50
51
52
53
    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...
54
55
    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...
56
    does_next_period_need_tac_association = Period.objects.next_period() in Period.objects.submission_periods()
5a434264   Alexis Koralewski   New version of Sc...
57
58
59
60
61
62
63
64
65
66
67
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 
        date_diff_today_end_of_property = temp.days / 12.5 
    else:
        temp = today - current_period.start_date 
        date_diff_today_end_of_property = temp.days / 12.5 + 15
    CAN_VALIDATE_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board") and sp_to_be_validated
    CAN_EVALUATE_SP = request.session.get("role") in ("Admin","TAC") and sp_to_be_evaluated
    CAN_SUBMIT_SP =  request.session.get("role") in ("Admin","Observer") and does_next_period_exist
    CAN_VIEW_SP =  request.session.get("role") in ("Admin","Observer")
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_VIEW_EXPLOITATION_PERIOD = request.session.get("role") in ("Admin","Observer","Unit-PI","Unit-board")
    CAN_CREATE_EXPLOITATION_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
a6e63604   Alexis Koralewski   adding agentSP an...
72
    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...
73
74
75
76
77
78
79
80
81
82
83
84
85
    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...
86
        "CAN_EVALUATE_SP": CAN_EVALUATE_SP,
5a434264   Alexis Koralewski   New version of Sc...
87
88
89
90
        "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...
91
92
        "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...
93
94
    })

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





089c0115   Alexis Koralewski   add new version (...
220
@login_required
5a434264   Alexis Koralewski   New version of Sc...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
@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...
238
239
240
241
242
243
244

@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...
245
246
    #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...
247
248
249
250
251
252
253
    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...
254
255
256
257
258
@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...
259
    sp_where_user_is_sp_pi = ScientificProgram.objects.filter(sp_pi=request.user)
e00964fc   Alexis Koralewski   new version of ti...
260
261
262
263
264
    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...
265
266
    #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...
267
    #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...
268
    sp_period_of_user = []
b414eec1   Alexis Koralewski   improving user ac...
269
270
    # 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...
271
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
272
273
    #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...
274
    for sp in sp_where_user_is_sp_pi:
e00964fc   Alexis Koralewski   new version of ti...
275
276
277
278
        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...
279
280
281
282
283
284
285
286
287
288
            # 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...
289
    #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...
290
291
292
293
    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...
294
    if len(list_of_sp) ==  0 and len(list_of_sp_to_be_proposed) == 0:
5a434264   Alexis Koralewski   New version of Sc...
295
296
297
298
299
300
301
        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...
302
        "list_of_sp_to_be_proposed":list_of_sp_to_be_proposed,
5a434264   Alexis Koralewski   New version of Sc...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
        "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...
334
335
336
    #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...
337
338
    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...
339
340
341
342
    #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...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
    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...
357
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
358
359
360
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...
361
362
363
    #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...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    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...
382
383
384
385
    """
    An invitation to join an SP is valid until the end of Exploitation period

    """
5a434264   Alexis Koralewski   New version of Sc...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
    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...
400

641ec717   Alexis Koralewski   add form to assoc...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
@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...
425
426
427
428
429
430
431
432
433
434
435
436

@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...
437
    period=Period.objects.get(id=id_period)
5a434264   Alexis Koralewski   New version of Sc...
438
439
    SP_Period_form = SP_PeriodForm(request.POST or None, instance=sp_period)
    sp_pi = scientific_program.sp_pi
089c0115   Alexis Koralewski   add new version (...
440
    if request.session.get("role") == "Observer" and request.user.id != sp_pi.id:
5a434264   Alexis Koralewski   New version of Sc...
441
442
443
444
445
446
447
448
        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...
449
450
451
452
    error = False
    error_message = ""
    list_of_emails = None
    recipient_list = []
089c0115   Alexis Koralewski   add new version (...
453
    if request.POST:
a6e63604   Alexis Koralewski   adding agentSP an...
454
455
        if SPForm.is_valid() and sp_period.status == SP_Period.STATUSES_DRAFT:
            SPForm.save()
cffa6238   Alexis Koralewski   fixing who can su...
456
        if SP_Period_form.is_valid():
a6e63604   Alexis Koralewski   adding agentSP an...
457
458
            if sp_period.status == SP_Period.STATUSES_DRAFT:
                SP_period = SP_Period_form.save()   
cffa6238   Alexis Koralewski   fixing who can su...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
            # 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...
497
                    
cffa6238   Alexis Koralewski   fixing who can su...
498
                else:
a6e63604   Alexis Koralewski   adding agentSP an...
499
                    return render(request, 'scientific_program/scientific_program_period_detail_edit.html', {
cffa6238   Alexis Koralewski   fixing who can su...
500
501
502
503
504
505
506
507
508
509
                            '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...
510
                # save changes on user list 
a6e63604   Alexis Koralewski   adding agentSP an...
511
                
cffa6238   Alexis Koralewski   fixing who can su...
512
                return redirect('detail_scientific_program_period', id_sp=scientific_program.id, id_period=id_period)
5a434264   Alexis Koralewski   New version of Sc...
513
514
        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...
515
516
            if sp_period.referee1 == request.user:
                print("vote referee 1 ")
5a434264   Alexis Koralewski   New version of Sc...
517
518
519
520
521
522
                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...
523
524
525
                #if sp_period.referee2 != None:
                    #sp_period.status = SP_Period.STATUSES_EVALUATED
                sp_period.save()
641ec717   Alexis Koralewski   add form to assoc...
526
527
            if sp_period.referee2 == request.user:
                print("vote referee 2 ")
5a434264   Alexis Koralewski   New version of Sc...
528
529
530
531
532
533
                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...
534
535
536
537
                #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...
538
        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...
539
540
541
            #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...
542
543
544
            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...
545
546
547
        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...
548
549
550
551
552
553
554
        '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...
555
        "sp_period": sp_period,
a6e63604   Alexis Koralewski   adding agentSP an...
556
557
        "error_message":error_message,
        "CAN_VIEW_TAC_VOTES":CAN_VIEW_TAC_VOTES
5a434264   Alexis Koralewski   New version of Sc...
558
    })
089c0115   Alexis Koralewski   add new version (...
559

5a434264   Alexis Koralewski   New version of Sc...
560
561
562


@level_required("Admin", "Unit-PI", "Observer", "TAC")
089c0115   Alexis Koralewski   add new version (...
563
@login_required
5a434264   Alexis Koralewski   New version of Sc...
564
def detail_scientific_program(request, id):
089c0115   Alexis Koralewski   add new version (...
565
    scientific_program = get_object_or_404(ScientificProgram, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
566
567
568
    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 (...
569
    
5a434264   Alexis Koralewski   New version of Sc...
570
571
    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...
572
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
573
574
575
    #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...
576
577
578
579
    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...
580
    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...
581
    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...
582
    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...
583
584
585
586
    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...
587
        "CAN_REPROPOSE_SP": CAN_REPROPOSE_SP,
077d5a23   Alexis Koralewski   adding science th...
588
589
        "CAN_DELETE_SP": CAN_DELETE_SP,
        "CAN_VIEW_IS_AUTOVALIDATED": CAN_VIEW_IS_AUTOVALIDATED
5a434264   Alexis Koralewski   New version of Sc...
590
591
592
    })


a6e63604   Alexis Koralewski   adding agentSP an...
593
@level_required("Admin", "Unit-PI", "Observer")
5a434264   Alexis Koralewski   New version of Sc...
594
595
596
597
598
599
600
601
602
603
604
605
@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 ...
606
    sequences = Sequence.objects.filter(scientific_program=scientific_program,period_id=id_period).order_by("-id")
b4f6db4d   Alexis Koralewski   Adding Sequences ...
607
    page = request.GET.get('page', 1)
ad3b297c   Alexis Koralewski   add pagination to...
608
    sequences_paginator = Paginator(sequences,settings.NB_ELEMENT_PER_PAGE)
b4f6db4d   Alexis Koralewski   Adding Sequences ...
609
610
611
612
613
614
615
    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 (...
616
    # User is observer and not from this SP
5a434264   Alexis Koralewski   New version of Sc...
617
618
619
620
621
622
623
    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...
624
    CAN_VIEW_TAC_VOTES = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
cffa6238   Alexis Koralewski   fixing who can su...
625
    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...
626
627
628
629
630
631
632
    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 ...
633
        "sequences": sequences,
5a434264   Alexis Koralewski   New version of Sc...
634
635
636
637
638
        "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...
639
640
        "CAN_VIEW_TAC_VOTES": CAN_VIEW_TAC_VOTES,
        "CAN_SUBMIT_PROPOSAL": CAN_SUBMIT_PROPOSAL
5a434264   Alexis Koralewski   New version of Sc...
641
    })
089c0115   Alexis Koralewski   add new version (...
642

5a434264   Alexis Koralewski   New version of Sc...
643
644

@level_required("Admin", "Unit-PI", "Observer")
089c0115   Alexis Koralewski   add new version (...
645
@login_required()
5a434264   Alexis Koralewski   New version of Sc...
646
647
648
649
650
651
652
653
654
655
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...
656
657
658
659
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...
660
661
662
663
664
        # 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...
665
666
667
668
669
670
671
672

@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...
673
        # Delete only if in draft status
e00964fc   Alexis Koralewski   new version of ti...
674
675
676
677
678
679
        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 (...
680
681
682


@login_required
b414eec1   Alexis Koralewski   improving user ac...
683
@level_required("Admin", "Unit-PI", "Observer", "Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
684
685
686
687
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...
688
689
    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...
690
691
692
693
694
    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...
695
696
697

    return render(request, 'scientific_program/scientific_programs.html', {
        'scientific_programs': scientific_programs,
b414eec1   Alexis Koralewski   improving user ac...
698
699
700
        "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...
701
702
703
704
705
706
707
708
709
    })


@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...
710
711
    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...
712
    if (len(scientific_programs) > 0):
6f505a1d   Alexis Koralewski   fixing delete but...
713
        # get all SP where user is sp_pi
5a434264   Alexis Koralewski   New version of Sc...
714
715
        sp_of_user = ScientificProgram.objects.filter(sp_pi=request.user).order_by("-id")
    else:
089c0115   Alexis Koralewski   add new version (...
716
717
        scientific_programs = None

5a434264   Alexis Koralewski   New version of Sc...
718
719
    return render(request, 'scientific_program/scientific_programs.html', {
        'scientific_programs': scientific_programs,
b414eec1   Alexis Koralewski   improving user ac...
720
721
722
        "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...
723
724
725
726
727
728
729
730
731
732
733
    })



#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...
734
        return HttpResponse(get_proposal_svg_timeline(Period.objects.get(id=request.POST["period_id"]),request.POST["period"]))
5a434264   Alexis Koralewski   New version of Sc...
735

089c0115   Alexis Koralewski   add new version (...
736
737
738
739

# Institute CRUD

@login_required
b414eec1   Alexis Koralewski   improving user ac...
740
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
741
742
743
744
745
746
747
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...
748
    return render(request, "scientific_program/create_institute.html", {"form": form})
089c0115   Alexis Koralewski   add new version (...
749
750


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

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

5a434264   Alexis Koralewski   New version of Sc...
762
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
089c0115   Alexis Koralewski   add new version (...
763
@login_required
5a434264   Alexis Koralewski   New version of Sc...
764
def detail_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
765
    institute = get_object_or_404(Institute, pk=id)
5a434264   Alexis Koralewski   New version of Sc...
766
767
    representative_member = PyrosUser.objects.get(
        is_institute_representative=True, institute=institute)
089c0115   Alexis Koralewski   add new version (...
768
    scientific_programs = ScientificProgram.objects.filter(institute=institute)
b414eec1   Alexis Koralewski   improving user ac...
769
770
    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...
771
772
773
    return render(request, 'scientific_program/institute_detail.html', {
        'institute': institute,
        "representative_member": representative_member,
b414eec1   Alexis Koralewski   improving user ac...
774
775
776
        "scientific_programs": scientific_programs,
        "CAN_EDIT_INSTITUTE": CAN_EDIT_INSTITUTE,
        "CAN_DELETE_INSTITUTE": CAN_DELETE_INSTITUTE
5a434264   Alexis Koralewski   New version of Sc...
777
778
779
    })


b414eec1   Alexis Koralewski   improving user ac...
780
@level_required("Admin", "Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
781
@login_required()
5a434264   Alexis Koralewski   New version of Sc...
782
def delete_institute(request, id):
089c0115   Alexis Koralewski   add new version (...
783
784
785
786
787
788
    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...
789
@level_required("Admin", "Unit-PI", "Observer", "Operator", "TAC", "Management board member")
089c0115   Alexis Koralewski   add new version (...
790
791
def institute_list(request):
    institutes = Institute.objects.all()
b414eec1   Alexis Koralewski   improving user ac...
792
793
794
795
796
    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 (...
797
798


5a434264   Alexis Koralewski   New version of Sc...
799
# Exploitation Periods CRUD
089c0115   Alexis Koralewski   add new version (...
800
801

@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
802
@level_required("Admin", "Unit-PI", "Unit-board")
089c0115   Alexis Koralewski   add new version (...
803
def create_period(request):
077d5a23   Alexis Koralewski   adding science th...
804
    form = PeriodForm()
5a434264   Alexis Koralewski   New version of Sc...
805
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
806
807
    possible_start_date = Period.objects.latest_period().end_date 
    possible_end_date = possible_start_date + \
5a434264   Alexis Koralewski   New version of Sc...
808
809
        relativedelta(months=+6)

077d5a23   Alexis Koralewski   adding science th...
810
811
    possible_start_date_as_datetime = possible_start_date
    possible_end_date_as_datetime = possible_start_date + relativedelta(
5a434264   Alexis Koralewski   New version of Sc...
812
813
814
        months=+6)

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

5a434264   Alexis Koralewski   New version of Sc...
919
920
921
922
923
924
925
926
927
928
929
    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...
930
931
        "possible_accessibility_end_date": possible_accessibility_end_date,
        "form":form
5a434264   Alexis Koralewski   New version of Sc...
932
    })
089c0115   Alexis Koralewski   add new version (...
933
934
935


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


@login_required
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1028
@level_required("Admin", "Unit-PI",  "Observer")
5a434264   Alexis Koralewski   New version of Sc...
1029
def detail_period(request, id):
089c0115   Alexis Koralewski   add new version (...
1030
1031
    period = get_object_or_404(Period, pk=id)
    sp_periods = SP_Period.objects.filter(period=period)
5a434264   Alexis Koralewski   New version of Sc...
1032
1033
1034
1035
    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...
1036
1037
1038
1039
    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...
1040
1041
1042
1043
    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...
1044
1045
1046
1047
1048
        "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...
1049
1050
    })

089c0115   Alexis Koralewski   add new version (...
1051
1052

@login_required()
b414eec1   Alexis Koralewski   improving user ac...
1053
@level_required("Admin", "Unit-PI","Unit-board")
5a434264   Alexis Koralewski   New version of Sc...
1054
def delete_period(request, id):
089c0115   Alexis Koralewski   add new version (...
1055
1056
1057
1058
1059
1060
    period = get_object_or_404(Period, pk=int(id))
    period.delete()
    return HttpResponseRedirect(reverse('period_list'))


@login_required
b414eec1   Alexis Koralewski   improving user ac...
1061
@level_required("Admin", "Unit-PI", "Observer", "Unit-board")
089c0115   Alexis Koralewski   add new version (...
1062
def period_list(request):
5a434264   Alexis Koralewski   New version of Sc...
1063
    today = timezone.now().date()
077d5a23   Alexis Koralewski   adding science th...
1064
    periods = Period.objects.all().order_by("-start_date")
089c0115   Alexis Koralewski   add new version (...
1065
1066
    future_periods = []
    past_periods = []
077d5a23   Alexis Koralewski   adding science th...
1067
    active_period = Period.objects.exploitation_period()
b414eec1   Alexis Koralewski   improving user ac...
1068
    CAN_ADD_PERIOD = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
089c0115   Alexis Koralewski   add new version (...
1069
    for period in periods:
5a434264   Alexis Koralewski   New version of Sc...
1070
1071
        if period == active_period:
            future_periods.insert(0, period)
089c0115   Alexis Koralewski   add new version (...
1072
        else:
5a434264   Alexis Koralewski   New version of Sc...
1073
            if period.start_date >= today and period.end_date >= today:
089c0115   Alexis Koralewski   add new version (...
1074
1075
1076
                future_periods.append(period)
            else:
                past_periods.append(period)
b414eec1   Alexis Koralewski   improving user ac...
1077
1078
1079
1080
1081
    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...
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104


# 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...
1105
@level_required("Admin","Unit-PI","TAC")
077d5a23   Alexis Koralewski   adding science th...
1106
1107
def science_theme_list(request):
    science_themes = ScienceTheme.objects.all()
a61943b5   Alexis Koralewski   Reworking Unit-bo...
1108
    CAN_ADD_SCIENCE_THEME = request.session.get("role") in ("Admin","Unit-PI","TAC")
077d5a23   Alexis Koralewski   adding science th...
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
    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...
1120
    CAN_VIEW_ALL_SP = request.session.get("role") in ("Admin","Unit-PI","TAC") 
077d5a23   Alexis Koralewski   adding science th...
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
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
    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...
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
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})