Commit e00964fc414d616fa2b38368ada7c224bb2de483
1 parent
47667b81
Exists in
dev
new version of timeline, fixing SP repropose, add copy of users when reproposing…
… a SP for a new period, removing guest field as required
Showing
8 changed files
with
183 additions
and
121 deletions
Show diff stats
src/core/pyros_django/scientific_program/functions.py
... | ... | @@ -35,7 +35,7 @@ def get_svg_timeline(previous_period,current_period,future_period): |
35 | 35 | <text class="date_text" x="25%" y="45%" fontsize="2em" fill="black">{current_period.start_date.strftime("%d/%m/%Y")}</text>\ |
36 | 36 | <text x="32%" y="37%" fontsize="2em" fill="red">Exploitation</text>' |
37 | 37 | #<text x="40%" y="45%" fontsize="2em" fill="black">{current_period.end_date.strftime("%d/%m/%Y")}</text>\ |
38 | - data_access_current_period = f'<rect id="exploit_current_period" x=45% y=30% width="20%" height="10%" style="fill:rgb(192,192,220);stroke-width:1"></rect>\ | |
38 | + data_access_current_period = f'<rect id="data_access_current_period" x=45% y=30% width="20%" height="10%" style="fill:rgb(192,192,220);stroke-width:1"></rect>\ | |
39 | 39 | <text class="date_text" x="45%" y="45%" fontsize="2em" fill="black">{current_period.end_date.strftime("%d/%m/%Y")}</text>\ |
40 | 40 | <text class="date_text" x="60%" y="45%" fontsize="2em" fill="black">{current_period.property_of_data_end_date.strftime("%d/%m/%Y")}</text>\ |
41 | 41 | <text x="52%" y="37%" fontsize="2em" fill="white">Private data access</text>' |
... | ... | @@ -58,49 +58,56 @@ def get_svg_timeline(previous_period,current_period,future_period): |
58 | 58 | return svg_content |
59 | 59 | |
60 | 60 | def get_global_svg_timeline(previous_period,current_period,future_period): |
61 | - svg_content = '<svg id="global_svg" width="80vw" height="30vh">' | |
61 | + svg_content = '<svg id="global_svg" width="80vw" height="25vh">' | |
62 | 62 | svg_previous_period = "" |
63 | 63 | svg_current_period = "" |
64 | 64 | svg_future_period = "" |
65 | 65 | |
66 | 66 | if previous_period is not None: |
67 | 67 | previous_period_svg = f'<rect id="previous_period" x="5%" y=0% width="20%" height="10%" style="fill:rgb(230, 244, 177);stroke-width:1"></rect>\ |
68 | - <text class="date_text" x="5%" y="15%" fontsize="2em" fill="black">{previous_period.start_date.strftime("%d/%m/%Y")}</text>\ | |
69 | - <text class="date_text" x="20%" y="15%" fontsize="2e" fill="black">{previous_period.end_date.strftime("%d/%m/%Y")}</text>' | |
70 | - svg_content+=f'<text x="0%" y="7%" fontsize="2em" fill="black">Previous(P{current_period.id})</text>' + previous_period_svg | |
68 | + <rect id="previous_period" x="25%" y=0 width="40%" height="10%" style="fill:blue; stroke-width:1"></rect>\ | |
69 | + <text x="15%" y="7%" fontsize="2em" fill="black">Exploitation</text>' | |
70 | + #<text class="date_text" x="5%" y="15%" fontsize="2em" fill="black">{previous_period.start_date.strftime("%d/%m/%Y")}</text>\ | |
71 | + #<text class="date_text" x="20%" y="15%" fontsize="2e" fill="black">{previous_period.end_date.strftime("%d/%m/%Y")}</text>\ | |
72 | + svg_content+=f'<text x="0%" y="7%" fontsize="2em" fill="black">Period(P{current_period.id})</text>' + previous_period_svg | |
71 | 73 | |
72 | 74 | if current_period is not None: |
73 | 75 | current_period_svg = f'<rect id="current_period" x="25%" y=30% width="20%" height="10%" style="fill:rgb(230, 244, 177);stroke-width:1"></rect>\ |
74 | - <text class="date_text" x="25%" y="45%" fontsize="2em" fill="black">{current_period.start_date.strftime("%d/%m/%Y")}</text>\ | |
75 | - <text class="date_text" x="40%" y="45%" fontsize="2e" fill="black">{current_period.end_date.strftime("%d/%m/%Y")}</text>' | |
76 | - svg_content+=f'<text x="0%" y="37%" fontsize="2em" fill="black">Current(P{current_period.id})</text>' + current_period_svg | |
76 | + <rect id="current_period" x="5%" y=30% width="20%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
77 | + <rect id="current_period" x=45% y=30% width="20%" height="10%" style="fill:rgb(192,192,220);stroke-width:1"></rect>\ | |
78 | + <text x="32%" y="37%" fontsize="2em" fill="red">Exploitation</text>' | |
79 | + #<text class="date_text" x="25%" y="45%" fontsize="2em" fill="black">{current_period.start_date.strftime("%d/%m/%Y")}</text>\ | |
80 | + #<text class="date_text" x="40%" y="45%" fontsize="2e" fill="black">{current_period.end_date.strftime("%d/%m/%Y")}</text>\ | |
81 | + svg_content+=f'<text x="0%" y="37%" fontsize="2em" fill="black">Period (P{current_period.id})</text>' + current_period_svg | |
77 | 82 | |
78 | 83 | if future_period is not None: |
79 | - future_period_svg = f'<rect id="future_period" x="45%" y=60% width="20%" height="10%" style="fill:rgb(230, 244, 177);stroke-width:1"></rect>\ | |
80 | - <text class="date_text" x="45%" y="75%" fontsize="2em" fill="black">{future_period.start_date.strftime("%d/%m/%Y")}</text>\ | |
81 | - <text class="date_text" x="60%" y="75%" fontsize="2e" fill="black">{future_period.end_date.strftime("%d/%m/%Y")}</text>' | |
82 | - svg_content+=f'<text x="0%" y="67%" fontsize="2em" fill="black">Future(P{future_period.id})</text>' + future_period_svg | |
84 | + future_period_svg = f'<rect class="future_period" x="45%" y=60% width="20%" height="10%" style="fill:rgb(230, 244, 177);stroke-width:1"></rect>\ | |
85 | + <rect class="future_period" x="5%" y=60% width="40%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
86 | + <text x="52%" y="67%" fontsize="2em" fill="black">Exploitation</text>' | |
87 | + #<text class="date_text" x="45%" y="75%" fontsize="2em" fill="black">{future_period.start_date.strftime("%d/%m/%Y")}</text>\ | |
88 | + #<text class="date_text" x="60%" y="75%" fontsize="2e" fill="black">{future_period.end_date.strftime("%d/%m/%Y")}</text>\ | |
89 | + svg_content+=f'<text x="0%" y="67%" fontsize="2em" fill="black">Period(P{future_period.id})</text>' + future_period_svg | |
83 | 90 | |
84 | 91 | return svg_content |
85 | 92 | |
86 | 93 | def get_proposal_svg_timeline(period): |
87 | - proposal_svg = f'<svg id="proposal_detail" width="80vw" height="30vh"> <rect x="5%" y=5% width="20%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
94 | + proposal_svg = f'<svg id="proposal_detail" width="80vw" height="30vh"> <rect x="5%" y=5% width="19.9%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
88 | 95 | <text class="date_text" x="5%" y="35%" fontsize="2em" fill="black">{period.submission_start_date.strftime("%d/%m/%Y")}</text>\ |
89 | 96 | <text x="12%" y="12%" fontsize="2em" fill="black">Proposal submission</text>' |
90 | 97 | |
91 | - proposal_svg += f'<rect id="proposal_detail" x="25%" y=5% width="20%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
98 | + proposal_svg += f'<rect id="proposal_detail" x="25%" y=5% width="19.9%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
92 | 99 | <text class="date_text" x="25%" y="35%" fontsize="2em" fill="black">{period.submission_end_date.strftime("%d/%m/%Y")}</text>\ |
93 | 100 | <text x="32%" y="12%" fontsize="2em" fill="black">Evaluation</text>' |
94 | 101 | |
95 | - proposal_svg += f'<rect id="proposal_detail" x="45%" y=5% width="20%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
102 | + proposal_svg += f'<rect id="proposal_detail" x="45%" y=5% width="19.9%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
96 | 103 | <text class="date_text" x="45%" y="35%" fontsize="2em" fill="black">{period.unit_pi_validation_start_date.strftime("%d/%m/%Y")}</text>\ |
97 | 104 | <text x="52%" y="12%" fontsize="2em" fill="black">Validation</text>' |
98 | 105 | |
99 | 106 | information_start_date = period.start_date + relativedelta(days=-10) |
100 | - proposal_svg += f'<rect id="proposal_detail" x="65%" y=5% width="20%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
107 | + proposal_svg += f'<rect id="proposal_detail" x="65%" y=5% width="19.9%" height="10%" style="fill:silver;stroke-width:1"></rect>\ | |
101 | 108 | <text class="date_text" x="65%" y="35%" fontsize="2em" fill="black">{information_start_date.strftime("%d/%m/%Y")}</text>\ |
102 | 109 | <text class="date_text" x="80%" y="35%" fontsize="2em" fill="black">{period.start_date.strftime("%d/%m/%Y")}</text>\ |
103 | - <text x="72%" y="12%" fontsize="2em" fill="black">Information</text>' | |
110 | + <text x="72%" y="12%" fontsize="2em" fill="black">Notification</text>' | |
104 | 111 | proposal_svg +=f'<text x="0%" y="12%" fontsize="2em" fill="black">P{period.id}</text>' |
105 | 112 | proposal_svg += "</svg>" |
106 | 113 | return proposal_svg |
107 | 114 | \ No newline at end of file | ... | ... |
src/core/pyros_django/scientific_program/templates/scientific_program/create_scientific_program_period.html
... | ... | @@ -29,11 +29,13 @@ |
29 | 29 | {% endif %} |
30 | 30 | |
31 | 31 | {% endfor %} |
32 | - <label> Invite user(s) with their email adress: (list them separated by a ","):</label> | |
33 | - <div class="fieldWrapper"> | |
34 | - <textarea id="users" name="users">{{ list_of_emails|default_if_none:"" }}</textarea> | |
35 | - {{ error_message }} | |
36 | - </div> | |
32 | + {% if not is_sp_reproposed %} | |
33 | + <label> Invite user(s) with their email adress: (list them separated by a ","):</label> | |
34 | + <div class="fieldWrapper"> | |
35 | + <textarea id="users" name="users">{{ list_of_emails|default_if_none:"" }}</textarea> | |
36 | + {{ error_message }} | |
37 | + </div> | |
38 | + {% endif %} | |
37 | 39 | {% comment %} |
38 | 40 | |
39 | 41 | <div> | ... | ... |
src/core/pyros_django/scientific_program/templates/scientific_program/index.html
... | ... | @@ -349,7 +349,7 @@ p{ |
349 | 349 | <a href="{% url 'list_scientific_program_period_repropose' %}">Submit again an existing SP but for a new Exploitation Period (new instance)</a> |
350 | 350 | </li> |
351 | 351 | {% endif %} |
352 | - {% if CAN_VIEW_SP %} | |
352 | + {% if CAN_VIEW_SP and not CAN_VIEW_ALL_SP %} | |
353 | 353 | <p> SP list </p> |
354 | 354 | <li> |
355 | 355 | <a href="{% url 'own_scientific_program_list' %}">View my own submitted SP(s)</a> |
... | ... | @@ -404,7 +404,7 @@ $('#current_period').click( function(){ |
404 | 404 | $("#detail_proposal_period").hide(); |
405 | 405 | }); |
406 | 406 | |
407 | -$('#future_period').click( function(){ | |
407 | +$('.future_period').click( function(){ | |
408 | 408 | console.log('future_period'); |
409 | 409 | $("#detail_svg").toggle(); |
410 | 410 | $("#detail_previous_period").hide(); | ... | ... |
src/core/pyros_django/scientific_program/templates/scientific_program/period_detail.html
... | ... | @@ -42,10 +42,17 @@ |
42 | 42 | {% endwith %} |
43 | 43 | </tr> |
44 | 44 | {% endfor %} |
45 | + {% if not sp_of_user %} | |
46 | + {% for sp_period in sp_periods %} | |
47 | + {% if sp_period.scientific_program.sp_pi == request.user %} | |
48 | + <td><a href="{% url 'detail_scientific_program_period' id_sp=sp_period.scientific_program.id id_period=period.id %}">{{ sp_period.scientific_program.name }}</a></td> | |
49 | + {% endif %} | |
50 | + {% endfor %} | |
51 | + {% endif %} | |
45 | 52 | |
46 | 53 | {% elif USER_LEVEL|ifinlist:"Admin,Unit-PI,TAC,Unit board" or is_period_public %} |
47 | - {{ scientific_programs }} | |
48 | - {% for sp in scientific_programs %} | |
54 | + | |
55 | + {% for sp_period in sp_periods %} | |
49 | 56 | <tr> |
50 | 57 | <td><a href="{% url 'detail_scientific_program_period' id_sp=sp_period.scientific_program.id id_period=period.id %}">{{ sp_period.scientific_program.name }}</a></td> |
51 | 58 | <td>{{ sp.description_short }}</td> | ... | ... |
src/core/pyros_django/scientific_program/templates/scientific_program/scientific_program_detail.html
... | ... | @@ -11,44 +11,46 @@ |
11 | 11 | <p><strong>Institute: </strong><a href=" {% url 'detail_institute' scientific_program.institute.id %}">{{ scientific_program.institute }}</a></p> |
12 | 12 | <p><strong>SP PI: </strong><a href=" {% url 'user_detail' sp_pi.id %}">{{ sp_pi.username }}</a></p> |
13 | 13 | {% if sp_periods %} |
14 | - <table class="table table-bordered table-hover table-striped tablesorter" style="font-family: 'Montserra', sans-serif;"> | |
15 | - <thead> | |
16 | - <tr> | |
17 | - <th>Periods <i class="fa fa-sort"></i></th> | |
18 | - </tr> | |
19 | - </thead> | |
20 | - <tbody> | |
21 | - {% for sp_period in sp_periods %} | |
22 | - <tr><td><a href=" {% url 'detail_scientific_program_period' id_sp=scientific_program.id id_period=sp_period.period.pk %}" >{{ sp_period.period }} </a> </td></tr> | |
23 | - {% endfor %} | |
24 | - </tbody> | |
25 | - </table></p> | |
14 | + <table class="table table-bordered table-hover table-striped tablesorter" style="font-family: 'Montserra', sans-serif;"> | |
15 | + <thead> | |
16 | + <tr> | |
17 | + <th>Periods <i class="fa fa-sort"></i></th> | |
18 | + </tr> | |
19 | + </thead> | |
20 | + <tbody> | |
21 | + {% for sp_period in sp_periods %} | |
22 | + <tr><td><a href=" {% url 'detail_scientific_program_period' id_sp=scientific_program.id id_period=sp_period.period.pk %}" >{{ sp_period.period }} </a> </td></tr> | |
23 | + {% endfor %} | |
24 | + </tbody> | |
25 | + </table></p> | |
26 | 26 | {% endif %} |
27 | 27 | |
28 | - {% if USER_LEVEL|ifinlist:"Admin,Unit-PI" or request.user == sp_pi and USER_LEVEL == "Observer" %} | |
29 | - {% if CAN_REPROPOSE_SP %} | |
30 | - <a class="btn btn-info" href="{% url 'create_scientific_program_period' id_SP=scientific_program.id %}"> Repropose this SP for a new exploitation period </a> | |
31 | - {% endif %} | |
32 | - {% if sp_periods == None %} | |
33 | - <button type="button" class="btn btn-danger open-modal" id="open_modal_delete">Delete</button> | |
34 | - {# start of modal #} | |
35 | - <div id="modal_delete"> | |
36 | - <span id="close_modal_delete" class="close">x</span> | |
28 | + {% if CAN_REPROPOSE_SP %} | |
29 | + {% with sp_periods|first as last_sp_period %} | |
30 | + {% if last_sp_period %} | |
31 | + <a class="btn btn-info" href="{% url 'repropose_scientific_program' id_SP=scientific_program.id id_SP_Period=last_sp_period.period.id %}"> Repropose this SP for a new exploitation period </a> | |
32 | + {% endif %} | |
33 | + {% endwith %} | |
34 | + {% endif %} | |
35 | + {% if CAN_DELETE_SP %} | |
36 | + <button type="button" class="btn btn-danger open-modal" id="open_modal_delete">Delete</button> | |
37 | + {# start of modal #} | |
38 | + <div id="modal_delete"> | |
39 | + <span id="close_modal_delete" class="close">x</span> | |
40 | + | |
41 | + <form class="modal-content" action="{% url "delete_scientific_program" scientific_program.id %}" method="post"> | |
42 | + {% csrf_token %} | |
43 | + <div class="container"> | |
44 | + <h1> Delete Account </h1> | |
45 | + <p>Are you sure you want to delete this scientific program ?</p> | |
37 | 46 | |
38 | - <form class="modal-content" action="{% url "delete_scientific_program" scientific_program.id %}" method="post"> | |
39 | - {% csrf_token %} | |
40 | - <div class="container"> | |
41 | - <h1> Delete Account </h1> | |
42 | - <p>Are you sure you want to delete this scientific program ?</p> | |
43 | - | |
44 | - <div class="clearfix"> | |
45 | - <button type="button" class="btn btn-info" id="cancel_modal_delete_btn">Cancel</button> | |
46 | - <input class="btn btn-danger delete_modal_delete_btn" type="submit" value="Delete scientific program"> | |
47 | - </div> | |
47 | + <div class="clearfix"> | |
48 | + <button type="button" class="btn btn-info" id="cancel_modal_delete_btn">Cancel</button> | |
49 | + <input class="btn btn-danger delete_modal_delete_btn" type="submit" value="Delete scientific program"> | |
48 | 50 | </div> |
49 | - </form> | |
50 | - </div> | |
51 | - {% endif %} | |
51 | + </div> | |
52 | + </form> | |
53 | + </div> | |
52 | 54 | {% endif %} |
53 | 55 | {# end of modal #} |
54 | 56 | <a href="{% url "index_scientific_program" %}" class="btn btn-info" role="button">Return to index of scientific programs</a> | ... | ... |
src/core/pyros_django/scientific_program/templates/scientific_program/scientific_program_period_detail.html
... | ... | @@ -18,23 +18,27 @@ |
18 | 18 | <p><strong>Nominal quota: </strong>{{ sp_period.quota_nominal }}</p> |
19 | 19 | <p><strong>Over quota duration: </strong>{{ sp_period.over_quota_duration }}</p> |
20 | 20 | <p><strong>Token: </strong>{{ sp_period.token }}</p> |
21 | - {% if sp_period.referee1 != None %} | |
22 | - <p><strong>Vote referee 1: </strong>{{ sp_period.vote_referee1 }} </p> <p> <strong> Reason: </strong> {{ sp_period.reason_referee1 }} </p> <p> <strong> Referee 1: </strong>{{ sp_period.referee1.first_name }} {{ sp_period.referee1.last_name}} </p> | |
23 | - {% endif %} | |
24 | - {% if sp_period.referee2 != None %} | |
25 | - <p><strong>Vote referee 2: </strong>{{ sp_period.vote_referee1 }} </p> <p> <strong> Reason: </strong> {{ sp_period.reason_referee1 }} </p> <p> <strong> Referee 2: </strong> {{ sp_period.referee1.first_name }} {{ sp_period.referee1.last_name}} </p> | |
21 | + {% if CAN_VIEW_TAC_VOTES %} | |
22 | + {% if sp_period.referee1 != None %} | |
23 | + <p><strong>Vote referee 1: </strong>{{ sp_period.vote_referee1 }} </p> <p> <strong> Reason: </strong> {{ sp_period.reason_referee1 }} </p> <p> <strong> Referee 1: </strong>{{ sp_period.referee1.first_name }} {{ sp_period.referee1.last_name}} </p> | |
24 | + {% endif %} | |
25 | + {% if sp_period.referee2 != None %} | |
26 | + <p><strong>Vote referee 2: </strong>{{ sp_period.vote_referee1 }} </p> <p> <strong> Reason: </strong> {{ sp_period.reason_referee1 }} </p> <p> <strong> Referee 2: </strong> {{ sp_period.referee1.first_name }} {{ sp_period.referee1.last_name}} </p> | |
27 | + {% endif %} | |
26 | 28 | {% endif %} |
27 | 29 | {% if sp_period.status in "Accepted,Rejected" %} |
28 | 30 | <p><strong>Quota allocated: </strong>{{ sp_period.quota_allocated }}</p> |
29 | 31 | <p><strong>Over quota duration allocated: </strong>{{ sp_period.over_quota_duration_allocated }}</p> |
30 | 32 | <p><strong>Token allocated: </strong>{{ sp_period.token_allocated }}</p> |
31 | 33 | {% endif %} |
32 | - <p><strong>Guests: </strong></p> | |
33 | - <ul> | |
34 | - {% for guest in guests %} | |
35 | - <li><p> {{ guest }} </p></li> | |
36 | - {% endfor %} | |
37 | - </ul> | |
34 | + {% if guests %} | |
35 | + <p><strong>Guests: </strong></p> | |
36 | + <ul> | |
37 | + {% for guest in guests %} | |
38 | + <li><p> {{ guest }} </p></li> | |
39 | + {% endfor %} | |
40 | + </ul> | |
41 | + {% endif %} | |
38 | 42 | <table class="table table-bordered table-hover table-striped tablesorter" style="font-family: 'Montserra', sans-serif;"> |
39 | 43 | <thead> |
40 | 44 | <tr> |
... | ... | @@ -61,7 +65,7 @@ |
61 | 65 | <div id="modal_delete"> |
62 | 66 | <span id="close_modal_delete" class="close">x</span> |
63 | 67 | |
64 | - <form class="modal-content" action="{% url "delete_scientific_program" scientific_program.id %}" method="post"> | |
68 | + <form class="modal-content" action="{% url "delete_scientific_program_period" scientific_program.id sp_period.period.id %}" method="post"> | |
65 | 69 | {% csrf_token %} |
66 | 70 | <div class="container"> |
67 | 71 | <h1> Delete Account </h1> | ... | ... |
src/core/pyros_django/scientific_program/urls.py
... | ... | @@ -13,7 +13,8 @@ urlpatterns = [ |
13 | 13 | path('proposal_list', views.proposal_list,name='proposal_list'), |
14 | 14 | path('detail_scientific_program_period/<int:id_sp>/<int:id_period>', views.detail_scientific_program_period,name='detail_scientific_program_period'), |
15 | 15 | path('edit_scientific_program_period/<int:id_sp>/<int:id_period>', views.edit_scientific_program_period,name='edit_scientific_program_period'), |
16 | - path('delete_scientific_program/<int:id>/', views.delete_proposal,name='delete_scientific_program'), | |
16 | + path('delete_scientific_program_period/<int:id_sp>/<int:id_period>', views.delete_scientific_program_period,name='delete_scientific_program_period'), | |
17 | + path('delete_scientific_program/<int:id_sp>', views.delete_scientific_program,name='delete_scientific_program'), | |
17 | 18 | path('submit_proposal/<int:id>/',views.submit_proposal,name="submit_proposal"), |
18 | 19 | path('scientific_program_list', views.scientific_program_list,name='scientific_program_list'), |
19 | 20 | path('own_scientific_program_list', views.own_scientific_program_list,name='own_scientific_program_list'), | ... | ... |
src/core/pyros_django/scientific_program/views.py
... | ... | @@ -100,6 +100,7 @@ def create_scientific_program_period(request,id_SP,id_SP_Period=None): |
100 | 100 | SP = ScientificProgram.objects.get(id=id_SP) |
101 | 101 | today = timezone.now().date() |
102 | 102 | next_periods = Period.objects.filter(submission_start_date__lte=today,submission_end_date__gt=today, start_date__gt=today) |
103 | + is_sp_reproposed = False | |
103 | 104 | if SP.sp_pi != request.user: |
104 | 105 | HttpResponseRedirect(reverse("index_scientific_program")) |
105 | 106 | SP_Period_form = SP_PeriodForm() |
... | ... | @@ -114,12 +115,13 @@ def create_scientific_program_period(request,id_SP,id_SP_Period=None): |
114 | 115 | period_id_to_be_excluded = SP_Period.objects.filter(scientific_program=sp_period_template.scientific_program).values_list("period",flat=True) |
115 | 116 | next_periods = Period.objects.filter(submission_start_date__lte=today,submission_end_date__gt=today, start_date__gt=today).exclude(id__in=period_id_to_be_excluded) |
116 | 117 | SP_Period_form = SP_PeriodForm(initial=initial_data) |
118 | + is_sp_reproposed = True | |
117 | 119 | #next_period = Period.objects.filter( |
118 | 120 | # start_date__gt=today).order_by("start_date").first() |
119 | 121 | error = False |
120 | 122 | error_message = "" |
121 | 123 | list_of_emails = None |
122 | - | |
124 | + recipient_list = [] | |
123 | 125 | if request.POST: |
124 | 126 | SP_Period_form = SP_PeriodForm(request.POST) |
125 | 127 | if SP_Period_form.is_valid(): |
... | ... | @@ -129,40 +131,41 @@ def create_scientific_program_period(request,id_SP,id_SP_Period=None): |
129 | 131 | user_instance = PyrosUser.objects.get(id=int(user)) |
130 | 132 | SP_Period_User.objects.create(SP_Period=sp_period,user=user_instance,is_SP_PI=False) |
131 | 133 | """ |
132 | - if request.POST.get("users"): | |
134 | + if not is_sp_reproposed and request.POST.get("users"): | |
133 | 135 | regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' |
134 | 136 | list_of_emails = request.POST.get("users").strip() |
135 | - recipient_list = [] | |
137 | + | |
136 | 138 | for email in list_of_emails.split(","): |
137 | 139 | if re.fullmatch(regex, email): |
138 | 140 | recipient_list.append(email) |
139 | 141 | else: |
140 | 142 | error = True |
141 | 143 | error_message = f"Invalid mail for {email}" |
142 | - if not error: | |
143 | - institute = request.user.institute | |
144 | - selected_period = Period.objects.get(id=request.POST.get("period")) | |
145 | - | |
146 | - current_sp = ScientificProgram.objects.get(id=id_SP) | |
147 | - sp_period = SP_Period_form.save(commit=False) | |
148 | - sp_period.period = selected_period | |
149 | - #sp_period.period = next_period | |
150 | - sp_period.scientific_program = current_sp | |
151 | - sp_period.save() | |
152 | - | |
153 | - sp_pi_user = PyrosUser.objects.get(id=request.user.id) | |
154 | - #SP_Period_User.objects.create( | |
155 | - # SP_Period=sp_period, user=sp_pi_user, is_SP_PI=True) | |
156 | - domain = settings.DEFAULT_DOMAIN | |
157 | - url = f"{domain}{reverse('sp_register',args=(current_sp.pk,sp_period.period.pk))}" | |
158 | - mail_subject = '[PyROS CC] New registration to an observing proposal' | |
159 | - mail_message = (f"Hi,\n\nYou were invited to join an observing proposal that as been submitted using PyROS.\n" | |
160 | - 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" | |
161 | - f"To accept this invitation, click on the following link : {url}\n" | |
162 | - "You might be asked to login first and will be redirected to the proposal page.\n" | |
163 | - "If the redirection doesn't work, click again on the link after you've logged in.\n" | |
164 | - "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." | |
165 | - "\n\nCordially,\n\nPyROS Control Center") | |
144 | + if not error: | |
145 | + institute = request.user.institute | |
146 | + selected_period = Period.objects.get(id=request.POST.get("period")) | |
147 | + | |
148 | + current_sp = ScientificProgram.objects.get(id=id_SP) | |
149 | + sp_period = SP_Period_form.save(commit=False) | |
150 | + sp_period.period = selected_period | |
151 | + #sp_period.period = next_period | |
152 | + sp_period.scientific_program = current_sp | |
153 | + sp_period.save() | |
154 | + | |
155 | + sp_pi_user = PyrosUser.objects.get(id=request.user.id) | |
156 | + #SP_Period_User.objects.create( | |
157 | + # SP_Period=sp_period, user=sp_pi_user, is_SP_PI=True) | |
158 | + domain = settings.DEFAULT_DOMAIN | |
159 | + url = f"{domain}{reverse('sp_register',args=(current_sp.pk,sp_period.period.pk))}" | |
160 | + mail_subject = '[PyROS CC] New registration to an observing proposal' | |
161 | + mail_message = (f"Hi,\n\nYou were invited to join an observing proposal that as been submitted using PyROS.\n" | |
162 | + 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" | |
163 | + f"To accept this invitation, click on the following link : {url}\n" | |
164 | + "You might be asked to login first and will be redirected to the proposal page.\n" | |
165 | + "If the redirection doesn't work, click again on the link after you've logged in.\n" | |
166 | + "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." | |
167 | + "\n\nCordially,\n\nPyROS Control Center") | |
168 | + if len(recipient_list) > 0: | |
166 | 169 | for recipient in recipient_list: |
167 | 170 | guest = SP_Period_Guest.objects.create( |
168 | 171 | SP_Period=sp_period, email=recipient) |
... | ... | @@ -173,13 +176,21 @@ def create_scientific_program_period(request,id_SP,id_SP_Period=None): |
173 | 176 | recipient_list=[recipient], |
174 | 177 | fail_silently=False, |
175 | 178 | ) |
176 | - return HttpResponseRedirect(reverse("own_scientific_program_list")) | |
179 | + if is_sp_reproposed: | |
180 | + previous_sp_periods = SP_Period.objects.filter(scientific_program=current_sp,period__lt=selected_period) | |
181 | + users_of_previous_period_for_sp = SP_Period_User.objects.filter(SP_Period__in=previous_sp_periods).values_list("user",flat=True) | |
182 | + for user in users_of_previous_period_for_sp: | |
183 | + SP_Period_User.objects.create(SP_Period=sp_period,user=PyrosUser.objects.get(id=user)) | |
184 | + return HttpResponseRedirect(reverse("detail_scientific_program",args=[current_sp.id])) | |
185 | + | |
186 | + #return HttpResponseRedirect(reverse("own_scientific_program_list")) | |
177 | 187 | return render(request, "scientific_program/create_scientific_program_period.html", { |
178 | 188 | "scientific_program":SP, |
179 | 189 | "SP_PeriodForm": SP_Period_form, |
180 | 190 | "error_message": error_message, |
181 | 191 | "list_of_emails": list_of_emails, |
182 | - "next_periods": next_periods | |
192 | + "next_periods": next_periods, | |
193 | + "is_sp_reproposed":is_sp_reproposed | |
183 | 194 | }) |
184 | 195 | |
185 | 196 | |
... | ... | @@ -209,18 +220,27 @@ def create_scientific_program_with_template(request, id_SP): |
209 | 220 | def list_scientific_program_period_repropose(request): |
210 | 221 | select_message = "Submit again an existing SP but for a new exploitation period (instance)" |
211 | 222 | none_message = f"There is no existing SP to be submitted for a new exploitation period" |
212 | - # Note : ~Q mean not query | |
213 | 223 | sp_where_user_is_sp_pi = ScientificProgram.objects.filter(sp_pi=request.user) |
224 | + if sp_where_user_is_sp_pi is None: | |
225 | + return HttpResponseRedirect(reverse("index_scientific_program")) | |
226 | + sp_period_of_user = SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi) | |
227 | + if not sp_period_of_user and sp_where_user_is_sp_pi is None: | |
228 | + return HttpResponseRedirect(reverse("index_scientific_program")) | |
214 | 229 | #sp_of_user = SP_Period_User.objects.filter(user=request.user.id).values_list("SP_Period",flat=True) |
215 | 230 | #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") |
216 | 231 | #sp_period_active_of_user = SP_Period.objects.filter(scientific_program__in=sp_where_user_is_sp_pi,period=Period.objects.currently_active_period()) |
217 | 232 | sp_period_of_user = [] |
233 | + today = timezone.now().date() | |
234 | + 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) | |
218 | 235 | for sp in sp_where_user_is_sp_pi: |
219 | - max_period_of_sp = SP_Period.objects.filter(scientific_program=sp).aggregate(Max("period"))["period__max"] | |
220 | - if max_period_of_sp != None: | |
221 | - sp_period_of_user.append(SP_Period.objects.get(scientific_program=sp,period=max_period_of_sp)) | |
236 | + is_sp_associated_with_period = SP_Period.objects.filter(scientific_program=sp).count() > 0 | |
237 | + if is_sp_associated_with_period: | |
238 | + # get latest period that has been associated with that SP | |
239 | + max_period_of_sp = SP_Period.objects.filter(scientific_program=sp).aggregate(Max("period"))["period__max"] | |
240 | + if max_period_of_sp not in next_proposal_periods: | |
241 | + # this SP can be reproposed for a next proposal period | |
242 | + sp_period_of_user.append(SP_Period.objects.get(scientific_program=sp,period=max_period_of_sp)) | |
222 | 243 | #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") |
223 | - print(sp_period_of_user) | |
224 | 244 | list_of_sp = [] |
225 | 245 | are_there_only_sp = False |
226 | 246 | # SP_Period where user is a SP_PI |
... | ... | @@ -423,13 +443,18 @@ def detail_scientific_program(request, id): |
423 | 443 | |
424 | 444 | 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() : |
425 | 445 | return HttpResponseRedirect(reverse("index_scientific_program")) |
426 | - | |
427 | - CAN_REPROPOSE_SP = sp_pi == request.user and request.session.get("role") == "Observer" | |
446 | + today = timezone.now().date() | |
447 | + next_proposal_period = Period.objects.filter( | |
448 | + start_date__gt=today, submission_start_date__lte=today).order_by("start_date").first() | |
449 | + is_future_period_in_proposal = next_proposal_period.id not in sp_periods.values_list("period",flat=True) | |
450 | + CAN_REPROPOSE_SP = sp_pi == request.user and request.session.get("role") == "Observer" and is_future_period_in_proposal | |
451 | + 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") | |
428 | 452 | return render(request, 'scientific_program/scientific_program_detail.html', { |
429 | 453 | 'scientific_program': scientific_program, |
430 | 454 | "sp_pi": sp_pi, |
431 | 455 | "sp_periods": sp_periods, |
432 | - "CAN_REPROPOSE_SP":CAN_REPROPOSE_SP | |
456 | + "CAN_REPROPOSE_SP": CAN_REPROPOSE_SP, | |
457 | + "CAN_DELETE_SP": CAN_DELETE_SP | |
433 | 458 | }) |
434 | 459 | |
435 | 460 | |
... | ... | @@ -454,6 +479,7 @@ def detail_scientific_program_period(request, id_sp, id_period): |
454 | 479 | CAN_TAC_EVALUATE = request.session.get("role") in ("Admin","TAC") and sp_period.status == SP_Period.STATUSES_SUBMITTED |
455 | 480 | CAN_UNIT_PI_VALIDATE = request.session.get("role") in ("Unit-PI","Unit-board") and sp_period.status == SP_Period.STATUSES_EVALUATED |
456 | 481 | CAN_OBSERVER_DELETE = request.session.get("role") in ("Admin","Observer") and sp_period.status == SP_Period.STATUSES_DRAFT |
482 | + CAN_VIEW_TAC_VOTES = request.session.get("role") in ("Admin","Unit-PI","Unit-board") | |
457 | 483 | return render(request, 'scientific_program/scientific_program_period_detail.html', { |
458 | 484 | 'scientific_program': scientific_program, |
459 | 485 | "users": users_informations, |
... | ... | @@ -466,7 +492,7 @@ def detail_scientific_program_period(request, id_sp, id_period): |
466 | 492 | "CAN_UNIT_PI_VALIDATE": CAN_UNIT_PI_VALIDATE, |
467 | 493 | "CAN_OBSERVER_DELETE": CAN_OBSERVER_DELETE, |
468 | 494 | "is_proposal": True, |
469 | - | |
495 | + "CAN_VIEW_TAC_VOTES": CAN_VIEW_TAC_VOTES | |
470 | 496 | }) |
471 | 497 | |
472 | 498 | |
... | ... | @@ -482,17 +508,30 @@ def submit_proposal(request, id): |
482 | 508 | |
483 | 509 | @level_required("Admin", "Unit-PI", "Observer") |
484 | 510 | @login_required() |
485 | -def delete_proposal(request, id): | |
486 | - scientific_program = get_object_or_404(ScientificProgram, pk=int(id)) | |
487 | - sp_period = SP_Period.objects.get( | |
488 | - scientific_program=scientific_program, status=SP_Period.STATUSES_DRAFT) | |
489 | - sp_period_users = SP_Period_User.objects.filter(SP_Period=sp_period) | |
490 | - sp_period_guests = SP_Period_Guest.objects.filter(SP_Period=sp_period) | |
491 | - sp_period_guests.delete() | |
492 | - sp_period_users.delete() | |
493 | - sp_period.delete() | |
511 | +def delete_scientific_program(request, id_sp): | |
512 | + scientific_program = get_object_or_404(ScientificProgram, pk=id_sp) | |
513 | + sp_periods = SP_Period.objects.filter(scientific_program=scientific_program) | |
514 | + if sp_periods: | |
515 | + for sp_period in sp_periods: | |
516 | + SP_Period_User.objects.filter(SP_Period=sp_period).delete() | |
517 | + SP_Period_Guest.objects.filter(SP_Period=sp_period).delete() | |
518 | + sp_periods.delete() | |
494 | 519 | scientific_program.delete() |
495 | - return HttpResponseRedirect(reverse('proposal_list')) | |
520 | + return HttpResponseRedirect(reverse('index_scientific_program')) | |
521 | + | |
522 | +@level_required("Admin", "Unit-PI", "Observer") | |
523 | +@login_required() | |
524 | +def delete_scientific_program_period(request, id_sp, id_period): | |
525 | + scientific_program = get_object_or_404(ScientificProgram, pk=id_sp) | |
526 | + sp_period = SP_Period.objects.get( | |
527 | + scientific_program=scientific_program, period=Period.objects.get(id=id_period)) | |
528 | + if sp_period.status == SP_Period.STATUSES_DRAFT: | |
529 | + sp_period_users = SP_Period_User.objects.filter(SP_Period=sp_period) | |
530 | + sp_period_guests = SP_Period_Guest.objects.filter(SP_Period=sp_period) | |
531 | + sp_period_guests.delete() | |
532 | + sp_period_users.delete() | |
533 | + sp_period.delete() | |
534 | + return HttpResponseRedirect(reverse('detail_scientific_program',args=[scientific_program.id])) | |
496 | 535 | |
497 | 536 | |
498 | 537 | @login_required | ... | ... |