AgentSP.py
12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
import sys
import os
pwd = os.environ['PROJECT_ROOT_PATH']
if pwd not in sys.path:
sys.path.append(pwd)
from src.core.pyros_django.agent.Agent import Agent, build_agent
from common.models import Period, SP_Period, PyrosUser, SP_Period_Guest, SP_PeriodWorkflow, ScientificProgram,SP_Period_User, ScienceTheme
from django.shortcuts import reverse
from django.conf import settings
from django.core.mail import send_mail
from dateutil.relativedelta import relativedelta
from django.db.models import Q
from django.utils import timezone
from django.test.utils import setup_test_environment
import numpy as np
class AgentSP(Agent):
period = None
# old config init
# def __init__(self, config_filename=None, RUN_IN_THREAD=True,use_db_test=False):
# ##if name is None: name = self.__class__.__name__
# if use_db_test:
# print("USE DB TEST")
# setup_test_environment()
# self.TEST_COMMANDS_LIST = [""]
# super().__init__(None, RUN_IN_THREAD)
# next_period = Period.objects.next_period()
# period = next_period
# new init with obsconfig
def __init__(self,use_db_test=False):
##if name is None: name = self.__class__.__name__
if use_db_test:
print("USE DB TEST")
setup_test_environment()
super().__init__()
next_period = Period.objects.next_period()
period = next_period
# @override
def _init(self):
super()._init()
def associate_tac_sp_auto(self,themes,tac_users,scientific_programs):
print("Associating tac to sp")
matrix_tac_themes = np.zeros([len(tac_users),len(themes)])
maxtrix_themes_sp = np.zeros([len(themes),len(scientific_programs)])
matrix_tac_sp = np.zeros([len(tac_users),len(scientific_programs)])
for i,tac_user in enumerate(tac_users):
for j,theme in enumerate(themes):
if theme.name in tac_user.get_referee_themes_as_str():
matrix_tac_themes[i,j] = 1
for i,theme in enumerate(themes):
for j,sp in enumerate(scientific_programs):
if theme.id == sp.science_theme.id:
maxtrix_themes_sp[i,j] = 1
matrix_tac_sp = np.dot(matrix_tac_themes,maxtrix_themes_sp)
nb_tac_per_sp = np.sum(matrix_tac_sp,axis=0)
next_period = Period.objects.next_period()
for i,sp in enumerate(scientific_programs):
if nb_tac_per_sp[i-1] == 2:
# We auto assign the tac users to scientific programs
print(sp)
sp_period = SP_Period.objects.get(scientific_program=sp,period=next_period)
available_tac_users = PyrosUser.objects.filter(referee_themes=sp.science_theme)
print("available tacs :")
print(available_tac_users)
sp_period.referee1 = available_tac_users[0]
sp_period.referee2 = available_tac_users[1]
sp_period.save()
#return matrix_tac_sp
def change_sp_status(self,scientific_programs,new_status):
print(f"---- CHANGE STATUS FOR {scientific_programs} TO {new_status}------- ")
for sp in scientific_programs:
if sp.status != new_status:
sp.status = new_status
sp.save()
def send_mail_to_tac_for_evaluation(self,tac_users,next_period):
domain = settings.DEFAULT_DOMAIN
url = f"{domain}{reverse('list_submitted_scientific_program')}"
mail_subject = '[PyROS CC] The evaluation period is now opened'
mail_message = (f"Hi,\n\nYou can now evaluate scientific programs for the next period ({next_period}).\n"
f"Click on the following link {url} to evaluate your assignated scientific programs."
"\n\nCordially,\n\nPyROS Control Center")
email_list = tac_users.values_list("email")
for email in email_list:
send_mail(
mail_subject,
mail_message,
from_email=None,
recipient_list=[email],
fail_silently=False,
)
def send_mail_to_observers_for_notification(self,sp_periods):
for sp_period in sp_periods:
sp_pi = sp_period.scientific_program.sp_pi
scientific_program = sp_period.scientific_program
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 a scientific program'
mail_message = (f"Hi,\n\nYou were invited to join a scientific program that as been submitted using PyROS.\n"
f"The name of the scientific program 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"
f"Once you have joined the scientific program, you can start to submit sequences"
"You might be asked to login first and will be redirected to the scientific program 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")
invited_observers_of_sp = SP_Period_Guest.objects.filter(SP_Period=sp_period).values("user")
recipient_list = invited_observers_of_sp
for invited_observer in recipient_list:
send_mail(
mail_subject,
mail_message,
from_email=None,
recipient_list=[invited_observer],
fail_silently=False,
)
def send_mail_to_unit_users_for_tac_assignation(self):
domain = settings.DEFAULT_DOMAIN
url = f"{domain}{reverse('list_drafted_scientific_program')}"
mail_subject = '[PyROS CC] TAC assignation to scientific programs for the next period'
mail_message = (f"Hi,\n\nYou can assign TAC users to scientific programs by choosing them in the {url} page.\n"
"PyROS has suggested TAC to some of the scientific programs but you can change those assignations.\n"
f"The TAC assignation will be effective and couldn't be modified at the {self.period.submission_end_date}.\n"
"\n\nCordially,\n\nPyROS Control Center")
unit_users = PyrosUser.objects.unit_users().values_list("email",flat=True)
send_mail(
mail_subject,
mail_message,
from_email=None,
recipient_list=unit_users,
fail_silently=False,
)
print("--------- SEND MAIL TO UNIT USERS ----------")
def automatic_period_workflow(self):
today = timezone.now().date()
next_period = Period.objects.next_period()
# check if next_period has changed
if self.period != next_period:
self.period = next_period
# get scientific program for next_period
next_sp = SP_Period.objects.filter(period=next_period)
auto_validated_sp = ScientificProgram.objects.filter(is_auto_validated=True)
auto_validated_sp_periods = SP_Period.objects.filter(scientific_program__in=auto_validated_sp,period=next_period)
# remove auto validated sp from next_sp
next_sp = next_sp.exclude(scientific_program__in=auto_validated_sp)
# get all tac users
tac_users = PyrosUser.objects.filter(user_level__name="TAC")
# submission workflow
if not SP_PeriodWorkflow.objects.filter(action=SP_PeriodWorkflow.SUBMISSION, period=self.period).exists():
print("routine automatic period workflow SUBMISSION")
# if the next_period is actually in the "submission" subperiod
if next_period in Period.objects.submission_periods():
# we have to assign TAC to SP
themes = ScienceTheme.objects.all()
# get id of scientific programs from SP_Period
sp_id = next_sp.exclude(scientific_program__is_auto_validated=True).filter(Q(referee1=None)|Q(referee2=None)).values("scientific_program")
# get scientific programs
sp = ScientificProgram.objects.filter(id__in=sp_id).order_by("name")
# if we are ten days before the end of the submission period, we have to assign TAC to scientific programs
# and send a mail to the Unit users to they assign the TAC users to SP
if next_period.submission_end_date + relativedelta(days=-10) == today :
self.associate_tac_sp_auto(themes,tac_users,sp)
# send mail to unit pi to tell him to associate TAC to SP
self.send_mail_to_unit_users_for_tac_assignation()
SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.SUBMISSION)
if not SP_PeriodWorkflow.objects.filter(action=SP_PeriodWorkflow.EVALUATION, period=self.period).exists():
print("routine automatic period workflow EVALUATION")
if next_period in Period.objects.evaluation_periods() and next_period.submission_end_date == today :
next_sp = SP_Period.objects.filter(period=next_period).exclude(scientific_program__in=auto_validated_sp).filter(status=SP_Period.STATUSES_DRAFT)
self.change_sp_status(next_sp,SP_Period.STATUSES_SUBMITTED)
self.send_mail_to_tac_for_evaluation(tac_users,next_period)
# for auto validated sp, we have to change their status
self.change_sp_status(auto_validated_sp_periods,SP_Period.STATUSES_ACCEPTED)
for sp in auto_validated_sp_periods:
sp.is_valid = SP_Period.IS_VALID_ACCEPTED
sp.save()
SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.EVALUATION)
if not SP_PeriodWorkflow.objects.filter(action=SP_PeriodWorkflow.VALIDATION, period=self.period).exists():
print("routine automatic period workflow VALIDATION")
if next_period.unit_pi_validation_start_date == today :
next_sp = SP_Period.objects.filter(period=next_period).exclude(scientific_program__in=auto_validated_sp).filter(status=SP_Period.STATUSES_SUBMITTED)
self.change_sp_status(next_sp,SP_Period.STATUSES_EVALUATED)
next_sp = SP_Period.objects.filter(period=next_period).exclude(scientific_program__in=auto_validated_sp).filter(status=SP_Period.STATUSES_EVALUATED)
SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.VALIDATION)
if not SP_PeriodWorkflow.objects.filter(action=SP_PeriodWorkflow.NOTIFICATION, period=self.period).exists():
print("routine automatic period workflow NOTIFICATION")
if next_period in Period.objects.notification_periods():
next_sp_accepted = SP_Period.objects.filter(period=next_period).filter(is_valid=SP_Period.IS_VALID_ACCEPTED)
self.change_sp_status(next_sp_accepted,SP_Period.STATUSES_ACCEPTED)
next_sp_rejected = SP_Period.objects.filter(period=next_period).filter(is_valid=SP_Period.IS_VALID_REJECTED)
self.change_sp_status(next_sp_rejected,SP_Period.STATUSES_REJECTED)
next_sp_to_be_notified = next_sp.filter(status=SP_Period.STATUSES_ACCEPTED,is_valid = True)
self.send_mail_to_observers_for_notification(next_sp_to_be_notified)
SP_PeriodWorkflow.objects.create(period=self.period,action=SP_PeriodWorkflow.NOTIFICATION)
def routine_process_body(self):
print("routine automatic period workflow")
print(SP_PeriodWorkflow.objects.all())
print(PyrosUser.objects.all())
for sp_period_workflow in SP_PeriodWorkflow.objects.all():
print(sp_period_workflow.period)
print(sp_period_workflow.action)
self.automatic_period_workflow()
if __name__ == "__main__":
# with thread
RUN_IN_THREAD=True
# with process
#RUN_IN_THREAD=False
print("ARGV OF AGENT SP :",sys.argv)
if len(sys.argv) > 1 and sys.argv[1] == "test":
print("i'm in test")
agentSP = AgentSP(use_db_test=True)
agentSP.run()
#agent = build_agent(agentSP, RUN_IN_THREAD=True)
else:
agent = build_agent(AgentSP)
'''
TEST_MODE, configfile = extract_parameters()
agent = AgentM("AgentM", configfile, RUN_IN_THREAD)
agent.setSimulatorMode(TEST_MODE)
'''
print(agent)
agent.run()