Scheduler: adding/removing resources enforce warnings and recount number of unconfigu...
[unfold.git] / portal / projectrequestview.py
1 import json
2 import time
3 import re
4
5 from django.shortcuts           import render
6 from django.contrib.sites.models import Site
7
8 from manifold.core.query        import Query
9 from manifoldapi.manifoldapi    import execute_admin_query, execute_query
10
11 from unfold.loginrequired       import LoginRequiredAutoLogoutView
12
13 from portal.actions import create_pending_project, create_pending_join, sfa_add_authority, authority_add_pis, is_pi
14 from portal.models import PendingProject, PendingJoin
15
16 from myslice.theme import ThemeView
17 from myslice.settings import logger
18
19 class ProjectRequestView(LoginRequiredAutoLogoutView, ThemeView):
20     template_name = 'projectrequest_view.html'
21     
22     def getAuthorities(self, request):
23         authorities_query = Query.get('authority').select('name', 'authority_hrn')
24         authorities = execute_admin_query(request, authorities_query)
25         if authorities is not None:
26             # Remove the root authority from the list
27             matching = [s for s in authorities if "." in s['authority_hrn']]
28             authorities = sorted(matching, key=lambda k: k['authority_hrn'])
29             authorities = sorted(matching, key=lambda k: k['name'])
30         return authorities
31     
32     def getUserAuthority(self, request):
33         # Get user_email (XXX Would deserve to be simplified)
34         user_query  = Query().get('local:user').select('email','config')
35         user_details = execute_query(request, user_query)
36         for user_detail in user_details:
37             user_config = json.loads(user_detail['config'])
38             user_authority = user_config.get('authority','N/A')
39         return user_authority
40     
41     def getUserHrn(self, request):
42         user_hrn = None
43         
44         account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
45         account_details = execute_query(request, account_query)
46
47         platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
48         platform_details = execute_query(request, platform_query)
49         
50         # getting user_hrn from local:account
51         for account_detail in account_details:
52             for platform_detail in platform_details:
53                 if platform_detail['platform_id'] == account_detail['platform_id']:
54                     # taking user_hrn only from myslice account
55                     # NOTE: we should later handle accounts filter_by auth_type= managed OR user
56                     if 'myslice' in platform_detail['platform']:
57                         account_config = json.loads(account_detail['config'])
58                         user_hrn = account_config.get('user_hrn','N/A')
59         return user_hrn        
60
61     def getUserEmail(self, request):
62         # Get user_email (XXX Would deserve to be simplified)
63         user_query  = Query().get('local:user').select('email','config')
64         user_details = execute_query(request, user_query)
65         user_email = user_details[0].get('email')
66         return user_email
67                    
68     def post(self, request):
69         return self.handle_request(request, 'POST')
70
71     def get(self, request):
72         return self.handle_request(request, 'GET')
73
74     def handle_request(self, wsgi_request, method):
75         errors = []
76         authority_hrn = None
77         authority_name = None
78         
79         #errors.append(wsgi_request.POST)
80
81         user_hrn = self.getUserHrn(wsgi_request)
82
83         user_email = self.getUserEmail(wsgi_request)
84         
85         authorities = self.getAuthorities(wsgi_request)
86         
87         user_authority = self.getUserAuthority(wsgi_request)
88         
89         # getting the org from authority
90         for authority in authorities:
91             if authority['authority_hrn'] == user_authority:
92                 authority_name = authority['name']
93         
94         if method == 'POST' :
95         
96             if 'join' in wsgi_request.POST:
97                 post = {
98                     'user_hrn'          : user_hrn,
99                     'email'             : user_email,
100                     'project_name'      : wsgi_request.POST.get('project_name', ''),
101                     'authority_hrn'     : wsgi_request.POST.get('project_name', ''),
102                 }
103
104             else:
105                 post = {
106                     'user_hrn'          : user_hrn,
107                     'email'             : user_email,
108                     'authority_hrn'     : wsgi_request.POST.get('authority_name', ''),
109                     'project_name'      : wsgi_request.POST.get('project_name', ''),
110                     'purpose'           : wsgi_request.POST.get('purpose', ''),
111                 }
112                 
113                 # for new projects max project_name length is 10
114                 if (len(post['project_name']) >10):
115                     errors.append('Project name can be maximum 10 characters long')
116
117                 #if (post['authority_hrn'] is None or post['authority_hrn'] == ''):
118                 #    errors.append('Organization is mandatory')
119     
120                 if (post['purpose'] is None or post['purpose'] == ''):
121                     errors.append('Project purpose is mandatory')
122
123                 if (re.search(r'^[A-Za-z0-9_]*$', post['project_name']) == None):
124                     errors.append('Project name may contain only letters, numbers, and underscore.')
125
126             # What kind of project name is valid?
127             if (post['project_name'] is None or post['project_name'] == ''):
128                 errors.append('Project name is mandatory')   
129             
130             if not errors:
131                 logger.info("is_pi on auth_hrn = {}".format(user_authority))
132                 if is_pi(wsgi_request, user_hrn, user_authority):
133                     # PIs can directly create/join project in their own authority...
134                     if 'join' in wsgi_request.POST:
135                         authority_add_pis(wsgi_request, post['project_name'], user_hrn)
136                     else:
137                         hrn = post['authority_hrn'] + '.' + post['project_name']
138                         sfa_add_authority(wsgi_request, {'authority_hrn':hrn})
139                         authority_add_pis(wsgi_request, hrn, user_hrn)
140                     self.template_name = 'project-request-done-view.html'
141                 else:
142                     # Otherwise a wsgi_request is sent to the PI
143                     if 'join' in wsgi_request.POST:
144                         create_pending_join(wsgi_request, post)
145                     else:
146                         create_pending_project(wsgi_request, post)
147                     self.template_name = 'project-request-ack-view.html'
148
149         # retrieves the pending projects creation list
150         pending_projects = PendingProject.objects.all().filter(user_hrn=user_hrn)
151         # retrieves the pending join a project list
152         pending_join_projects = PendingJoin.objects.all().filter(user_hrn=user_hrn)
153
154         root_authority = user_authority.split('.', 1)[0]                  
155         env = {
156                'errors':        errors,
157                'username':      wsgi_request.user,
158                'theme':         self.theme,
159                'authorities':   authorities,
160                'authority_hrn': user_authority,
161                'root_authority_hrn': root_authority,
162                'pending_projects': pending_projects,
163                'pending_join_projects': pending_join_projects,
164         }
165         return render(wsgi_request, self.template, env)
166     
167         
168     
169         """
170         """
171         errors = []
172         slice_name =''
173         purpose=''
174         url=''
175         authority_hrn = None
176         authority_name = None
177         # Retrieve the list of authorities
178         authorities_query = Query.get('authority').select('name', 'authority_hrn')
179         authorities = execute_admin_query(wsgi_request, authorities_query)
180         if authorities is not None:
181             authorities = sorted(authorities, key=lambda k: k['authority_hrn'])
182             authorities = sorted(authorities, key=lambda k: k['name'])
183
184         # Get user_email (XXX Would deserve to be simplified)
185         user_query  = Query().get('local:user').select('email','config')
186         user_details = execute_query(wsgi_request, user_query)
187         user_email = user_details[0].get('email')
188         # getting user_hrn
189         for user_detail in user_details:
190             user_config = json.loads(user_detail['config'])
191             user_authority = user_config.get('authority','N/A')              
192         # getting the org from authority        
193         for authority in authorities:
194             if authority['authority_hrn'] == user_authority:
195                 authority_name = authority['name']
196
197         # Handle the case when we use only hrn and not name
198         if authority_name is None:
199             authority_name = user_authority
200         #
201         account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
202         account_details = execute_query(wsgi_request, account_query)
203         #
204         platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
205         platform_details = execute_query(wsgi_request, platform_query)
206         
207         user_hrn = None
208         # getting user_hrn from local:account
209         for account_detail in account_details:
210             for platform_detail in platform_details:
211                 if platform_detail['platform_id'] == account_detail['platform_id']:
212                     # taking user_hrn only from myslice account
213                     # NOTE: we should later handle accounts filter_by auth_type= managed OR user
214                     if 'myslice' in platform_detail['platform']:
215                         account_config = json.loads(account_detail['config'])
216                         user_hrn = account_config.get('user_hrn','N/A')
217                         acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
218
219
220         # checking if pi or not
221         if acc_auth_cred == {} or acc_auth_cred == 'N/A':
222             pi = "is_not_pi"
223         else:
224             pi = "is_pi"
225
226
227         # Page rendering
228 #         page = Page(wsgi_request)
229 #         page.add_js_files  ( [ "js/jquery.validate.js", "js/jquery-ui.js" ] )
230 #         page.add_css_files ( [ "https://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" ] )
231 #         page.expose_js_metadata()
232
233         if method == 'POST':
234             # The form has been submitted
235
236             # get the domain url
237 #             current_site = Site.objects.get_current()
238 #             current_site = current_site.domain
239             
240             # getting the authority_hrn from the selected organization
241             for authority in authorities:
242                 if authority['name'] == wsgi_request.POST.get('org_name', ''):
243                     authority_hrn = authority['authority_hrn']
244
245             # Handle the case when we use only hrn and not name
246             if authority_hrn is None:
247                 authority_hrn = wsgi_request.POST.get('org_name', '')
248
249             slice_request = {
250                 'type'              : 'slice',
251                 'id'                : None,
252                 'user_hrn'          : user_hrn,
253                 'email'             : user_email,
254                 'timestamp'         : time.time(),
255                 'authority_hrn'     : authority_hrn,
256                 'organization'      : wsgi_request.POST.get('org_name', ''),
257                 'slice_name'        : wsgi_request.POST.get('slice_name', ''),
258                 'url'               : wsgi_request.POST.get('url', ''),
259                 'purpose'           : wsgi_request.POST.get('purpose', ''),
260                 'current_site'      : current_site
261             }
262             
263             # create slice_hrn based on authority_hrn and slice_name
264 #             slice_name = slice_request['slice_name']
265             req_slice_hrn = authority_hrn + '.' + slice_name
266             # comparing requested slice_hrn with the existing slice_hrn 
267             slice_query  = Query().get('myslice:slice').select('slice_hrn','parent_authority').filter_by('parent_authority','==',authority_hrn)
268             slice_details_sfa = execute_admin_query(wsgi_request, slice_query)
269             for _slice in slice_details_sfa:
270                 if _slice['slice_hrn'] == req_slice_hrn:
271                     errors.append('Slice already exists. Please use a different slice name.')
272             
273
274             # What kind of slice name is valid?
275             if (slice_name is None or slice_name == ''):
276                 errors.append('Slice name is mandatory')
277             
278             if (re.search(r'^[A-Za-z0-9_]*$', slice_name) == None):
279                 errors.append('Slice name may contain only letters, numbers, and underscore.')
280             
281             organization = slice_request['organization']    
282             if (organization is None or organization == ''):
283                 errors.append('Organization is mandatory')
284
285
286     
287             purpose = slice_request['purpose']
288             if (purpose is None or purpose == ''):
289                 errors.append('Experiment purpose is mandatory')
290
291             url = slice_request['url']
292
293             if not errors:
294                 if is_pi(wsgi_request, user_hrn, authority_hrn):
295                     # PIs can directly create slices in their own authority...
296                     create_slice(wsgi_request, slice_request)
297                     clear_user_creds(wsgi_request, user_email)
298                     self.template_name = 'slice-request-done-view.html'
299                 else:
300                     # Otherwise a wsgi_request is sent to the PI
301                     create_pending_slice(wsgi_request, slice_request, user_email)
302                     self.template_name = 'slice-request-ack-view.html'
303                 
304                 # log user activity
305                 activity.user.slice(wsgi_request)
306                 
307                 return render(wsgi_request, self.template, {'theme': self.theme}) # Redirect after POST
308         else:
309             slice_request = {}
310
311         template_env = {
312             'username': wsgi_request.user.email,
313             'errors': errors,
314             'slice_name': slice_name,
315             'purpose': purpose,
316             'email': user_email,
317             'user_hrn': user_hrn,
318             'url': url,
319             'pi': pi,
320             'authority_name': authority_name,        
321             'authority_hrn': user_authority,        
322             'cc_myself': True,
323             'authorities': authorities,
324             'theme': self.theme,
325             'section': "Slice request"
326         }
327         template_env.update(slice_request)
328         template_env.update(page.prelude_env())
329         return render(wsgi_request, self.template, template_env)