Slice req is always validated because it's under user's project on which he is a PI
[myslice.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                 if (post['authority_hrn'] is None or post['authority_hrn'] == ''):
114                     errors.append('Organization is mandatory')
115     
116                 if (post['purpose'] is None or post['purpose'] == ''):
117                     errors.append('Project purpose is mandatory')
118
119                 if (re.search(r'^[A-Za-z0-9_]*$', post['project_name']) == None):
120                     errors.append('Project name may contain only letters, numbers, and underscore.')
121
122             # What kind of project name is valid?
123             if (post['project_name'] is None or post['project_name'] == ''):
124                 errors.append('Project name is mandatory')
125
126             # max project_name length is 10
127             if (len(post['project_name']) >10):
128                 errors.append('Project name can be maximum 10 characters long')
129
130             
131             if not errors:
132                 logger.info("is_pi on auth_hrn = {}".format(user_authority))
133                 if is_pi(wsgi_request, user_hrn, user_authority):
134                     # PIs can directly create/join project in their own authority...
135                     if 'join' in wsgi_request.POST:
136                         authority_add_pis(wsgi_request, post['project_name'], user_hrn)
137                     else:
138                         hrn = post['authority_hrn'] + '.' + post['project_name']
139                         sfa_add_authority(wsgi_request, {'authority_hrn':hrn})
140                         authority_add_pis(wsgi_request, hrn, user_hrn)
141                     self.template_name = 'project-request-done-view.html'
142                 else:
143                     # Otherwise a wsgi_request is sent to the PI
144                     if 'join' in wsgi_request.POST:
145                         create_pending_join(wsgi_request, post)
146                     else:
147                         create_pending_project(wsgi_request, post)
148                     self.template_name = 'project-request-ack-view.html'
149
150         # retrieves the pending projects creation list
151         pending_projects = PendingProject.objects.all().filter(user_hrn=user_hrn)
152         # retrieves the pending join a project list
153         pending_join_projects = PendingJoin.objects.all().filter(user_hrn=user_hrn)
154
155         root_authority = user_authority.split('.', 1)[0]                  
156         env = {
157                'errors':        errors,
158                'username':      wsgi_request.user,
159                'theme':         self.theme,
160                'authorities':   authorities,
161                'authority_hrn': user_authority,
162                'root_authority_hrn': root_authority,
163                'pending_projects': pending_projects,
164                'pending_join_projects': pending_join_projects,
165         }
166         return render(wsgi_request, self.template, env)
167     
168         
169     
170         """
171         """
172         errors = []
173         slice_name =''
174         purpose=''
175         url=''
176         authority_hrn = None
177         authority_name = None
178         # Retrieve the list of authorities
179         authorities_query = Query.get('authority').select('name', 'authority_hrn')
180         authorities = execute_admin_query(wsgi_request, authorities_query)
181         if authorities is not None:
182             authorities = sorted(authorities, key=lambda k: k['authority_hrn'])
183             authorities = sorted(authorities, key=lambda k: k['name'])
184
185         # Get user_email (XXX Would deserve to be simplified)
186         user_query  = Query().get('local:user').select('email','config')
187         user_details = execute_query(wsgi_request, user_query)
188         user_email = user_details[0].get('email')
189         # getting user_hrn
190         for user_detail in user_details:
191             user_config = json.loads(user_detail['config'])
192             user_authority = user_config.get('authority','N/A')              
193         # getting the org from authority        
194         for authority in authorities:
195             if authority['authority_hrn'] == user_authority:
196                 authority_name = authority['name']
197
198         # Handle the case when we use only hrn and not name
199         if authority_name is None:
200             authority_name = user_authority
201         #
202         account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
203         account_details = execute_query(wsgi_request, account_query)
204         #
205         platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
206         platform_details = execute_query(wsgi_request, platform_query)
207         
208         user_hrn = None
209         # getting user_hrn from local:account
210         for account_detail in account_details:
211             for platform_detail in platform_details:
212                 if platform_detail['platform_id'] == account_detail['platform_id']:
213                     # taking user_hrn only from myslice account
214                     # NOTE: we should later handle accounts filter_by auth_type= managed OR user
215                     if 'myslice' in platform_detail['platform']:
216                         account_config = json.loads(account_detail['config'])
217                         user_hrn = account_config.get('user_hrn','N/A')
218                         acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
219
220
221         # checking if pi or not
222         if acc_auth_cred == {} or acc_auth_cred == 'N/A':
223             pi = "is_not_pi"
224         else:
225             pi = "is_pi"
226
227
228         # Page rendering
229 #         page = Page(wsgi_request)
230 #         page.add_js_files  ( [ "js/jquery.validate.js", "js/jquery-ui.js" ] )
231 #         page.add_css_files ( [ "https://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" ] )
232 #         page.expose_js_metadata()
233
234         if method == 'POST':
235             # The form has been submitted
236
237             # get the domain url
238 #             current_site = Site.objects.get_current()
239 #             current_site = current_site.domain
240             
241             # getting the authority_hrn from the selected organization
242             for authority in authorities:
243                 if authority['name'] == wsgi_request.POST.get('org_name', ''):
244                     authority_hrn = authority['authority_hrn']
245
246             # Handle the case when we use only hrn and not name
247             if authority_hrn is None:
248                 authority_hrn = wsgi_request.POST.get('org_name', '')
249
250             slice_request = {
251                 'type'              : 'slice',
252                 'id'                : None,
253                 'user_hrn'          : user_hrn,
254                 'email'             : user_email,
255                 'timestamp'         : time.time(),
256                 'authority_hrn'     : authority_hrn,
257                 'organization'      : wsgi_request.POST.get('org_name', ''),
258                 'slice_name'        : wsgi_request.POST.get('slice_name', ''),
259                 'url'               : wsgi_request.POST.get('url', ''),
260                 'purpose'           : wsgi_request.POST.get('purpose', ''),
261                 'current_site'      : current_site
262             }
263             
264             # create slice_hrn based on authority_hrn and slice_name
265 #             slice_name = slice_request['slice_name']
266             req_slice_hrn = authority_hrn + '.' + slice_name
267             # comparing requested slice_hrn with the existing slice_hrn 
268             slice_query  = Query().get('myslice:slice').select('slice_hrn','parent_authority').filter_by('parent_authority','==',authority_hrn)
269             slice_details_sfa = execute_admin_query(wsgi_request, slice_query)
270             for _slice in slice_details_sfa:
271                 if _slice['slice_hrn'] == req_slice_hrn:
272                     errors.append('Slice already exists. Please use a different slice name.')
273             
274
275             # What kind of slice name is valid?
276             if (slice_name is None or slice_name == ''):
277                 errors.append('Slice name is mandatory')
278             
279             if (re.search(r'^[A-Za-z0-9_]*$', slice_name) == None):
280                 errors.append('Slice name may contain only letters, numbers, and underscore.')
281             
282             organization = slice_request['organization']    
283             if (organization is None or organization == ''):
284                 errors.append('Organization is mandatory')
285
286
287     
288             purpose = slice_request['purpose']
289             if (purpose is None or purpose == ''):
290                 errors.append('Experiment purpose is mandatory')
291
292             url = slice_request['url']
293
294             if not errors:
295                 if is_pi(wsgi_request, user_hrn, authority_hrn):
296                     # PIs can directly create slices in their own authority...
297                     create_slice(wsgi_request, slice_request)
298                     clear_user_creds(wsgi_request, user_email)
299                     self.template_name = 'slice-request-done-view.html'
300                 else:
301                     # Otherwise a wsgi_request is sent to the PI
302                     create_pending_slice(wsgi_request, slice_request, user_email)
303                     self.template_name = 'slice-request-ack-view.html'
304                 
305                 # log user activity
306                 activity.user.slice(wsgi_request)
307                 
308                 return render(wsgi_request, self.template, {'theme': self.theme}) # Redirect after POST
309         else:
310             slice_request = {}
311
312         template_env = {
313             'username': wsgi_request.user.email,
314             'errors': errors,
315             'slice_name': slice_name,
316             'purpose': purpose,
317             'email': user_email,
318             'user_hrn': user_hrn,
319             'url': url,
320             'pi': pi,
321             'authority_name': authority_name,        
322             'authority_hrn': user_authority,        
323             'cc_myself': True,
324             'authorities': authorities,
325             'theme': self.theme,
326             'section': "Slice request"
327         }
328         template_env.update(slice_request)
329         template_env.update(page.prelude_env())
330         return render(wsgi_request, self.template, template_env)