1 # -*- coding: utf-8 -*-
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
7 # Jordan Augé <jordan.auge@lip6.fr>
8 # Mohammed Yasin Rahman <mohammed-yasin.rahman@lip6.fr>
9 # Copyright 2013, UPMC Sorbonne Universités / LIP6
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 3, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful, but WITHOUT
16 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 # You should have received a copy of the GNU General Public License along with
21 # this program; see the file COPYING. If not, write to the Free Software
22 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 from django.http import HttpResponseRedirect, HttpResponse
27 from django.views.generic.base import TemplateView
28 from django.shortcuts import render
29 from django.template.loader import render_to_string
30 from django.core.mail import send_mail
31 from django.utils.decorators import method_decorator
32 from django.contrib.auth.decorators import login_required
34 from myslice.viewutils import topmenu_items, the_user
36 from plugins.lists.simplelist import SimpleList
37 from plugins.hazelnut import Hazelnut
38 from plugins.pres_view import PresView
39 from portal.event import Event
41 from portal import signals
42 from portal.forms import SliceRequestForm
43 from portal.util import RegistrationView, ActivationView
44 from portal.models import PendingUser, PendingSlice
45 from portal.actions import authority_get_pi_emails, get_request_by_authority, manifold_add_user, manifold_update_user
46 from manifold.manifoldapi import execute_query
47 from manifold.core.query import Query
48 from unfold.page import Page
51 # initially all the portal views were defined in this single file
52 # all the other ones have now migrated into separate classes/files for more convenience
53 # I'm leaving these ones here for now as I could not exactly figure what the purpose was
54 # (i.e. what the correct name should be, as presviewview was a bit cryptic)
55 class PresViewView(TemplateView):
56 template_name = "view-unfold1.html"
58 def get_context_data(self, **kwargs):
60 page = Page(self.request)
62 pres_view = PresView(page = page)
64 context = super(PresViewView, self).get_context_data(**kwargs)
66 #context['ALL_STATIC'] = "all_static"
67 context['unfold1_main'] = pres_view.render(self.request)
69 # XXX This is repeated in all pages
70 # more general variables expected in the template
71 context['title'] = 'Test view that combines various plugins'
72 # the menu items on the top
73 context['topmenu_items'] = topmenu_items('PresView', self.request)
74 # so we can sho who is logged
75 context['username'] = the_user(self.request)
77 prelude_env = page.prelude_env()
78 context.update(prelude_env)
82 def json_me(config_file,type):
84 for ligne in config_file:
85 if not ligne.startswith('#'):
86 args = ligne.split(';')
87 json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1] + '" ,"descriptif":"' + args[2]+'"')
89 json_answer += str(',"contraints":')
91 json_answer += str('""')
93 json_answer += str(args[3])
94 json_answer += str('},')
95 return json_answer[:-1]
99 STATIC = '%s/config_method_static' % DIR
100 DYNAMIC = '%s/config_method_dynamic' % DIR
101 ANIMATION = '%s/config_method_animation' % DIR
103 def pres_view_methods(request, type):
107 elif type =="static":
108 config = open(STATIC, "r")
109 json_answer = str('{ "options": [')
110 json_answer += str(json_me(config,"static"))
111 json_answer += str('] }')
113 elif type =="dynamic":
114 config = open(DYNAMIC, "r")
115 json_answer = str('{ "options": [')
116 json_answer += str(json_me(config,"dynamic"))
117 json_answer += str('] }')
119 elif type =="animation":
120 config = open(ANIMATION, "r")
121 json_answer = str('{ "options": [')
122 json_answer += str(json_me(config,"animation"))
123 json_answer += str('] }')
126 config = open(STATIC, "r")
127 json_answer = str('{ "static": [')
128 json_answer += str(json_me(config,"static"))
129 json_answer += str('],')
130 json_answer += str('"dynamic": [')
132 config = open(DYNAMIC, "r")
133 json_answer += str(json_me(config,"dynamic"))
134 json_answer += str('],')
135 json_answer += str('"animation": [')
137 config = open(ANIMATION, "r")
138 json_answer += str(json_me(config,"animation"))
139 json_answer += str('] }')
143 return HttpResponse (json_answer, mimetype="application/json")
145 def pres_view_animation(request, constraints, id):
147 # sites crees depuis 2008
148 # static.py?contraints=']date_created':1262325600&id='name_id"'
150 # method = request.getvalue('method') #ex : GetSites
151 #constraints = "']date_created':1262325600"
157 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
158 # constraints = {}#request.getvalue('constraints') // nul = {}
159 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
161 config_file = open(ANIMATION, "r")
162 for ligne in config_file:
163 if not ligne.startswith('#'):
164 ligne = ligne.split('\n')
165 first = ligne[0].split(';')
166 if (str(first[1]) == str(id)):
170 #Les print_method, print_option sont definis par le client (js)
171 #Les animations acceptent que les connexions anonymous
172 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
173 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
176 #Creation d'un objet event
180 "print_options": event.print_options,
181 "print_method": event.print_method,
182 "message": event.data
187 json_answer = json.dumps(cmd)
188 return HttpResponse (json_answer, mimetype="application/json")
190 def pres_view_static(request, constraints, id):
191 #constraints = "']date_created':1262325600"
194 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
195 # constraints = {}#request.getvalue('constraints') // nul = {}
196 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
198 config_file = open(STATIC, "r")
199 for ligne in config_file:
200 if not ligne.startswith('#'):
201 ligne = ligne.split('\n')
202 first = ligne[0].split(';')
203 if (str(first[1]) == str(id)):
207 #Les print_method, print_option sont definis par le client (js)
208 #Les animations acceptent que les connexions anonymous
209 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
210 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
213 #Creation d'un objet event
217 "print_options": event.print_options,
218 "print_method": event.print_method,
219 "message": event.data
224 json_answer = json.dumps(cmd)
225 return HttpResponse (json_answer, mimetype="application/json")
227 class ValidatePendingView(TemplateView):
228 template_name = "validate_pending.html"
230 def get_context_data(self, **kwargs):
231 # We might have slices on different registries with different user accounts
232 # We note that this portal could be specific to a given registry, to which we register users, but i'm not sure that simplifies things
233 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
235 #messages.info(self.request, 'You have logged in')
236 page = Page(self.request)
238 ctx_my_authorities = {}
239 ctx_delegation_authorities = {}
242 # The user need to be logged in
243 if the_user(self.request):
244 # Who can a PI validate:
245 # His own authorities + those he has credentials for.
246 # In MySlice we need to look at credentials also.
249 # XXX This will have to be asynchroneous. Need to implement barriers,
250 # for now it will be sufficient to have it working statically
252 # get user_id to later on query accounts
253 # XXX Having real query plan on local tables would simplify all this
254 # XXX $user_email is still not available for local tables
255 #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
256 user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
257 user, = execute_query(self.request, user_query)
258 user_id = user['user_id']
260 # Query manifold to learn about available SFA platforms for more information
261 # In general we will at least have the portal
262 # For now we are considering all registries
265 sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
266 sfa_platforms = execute_query(self.request, sfa_platforms_query)
267 for sfa_platform in sfa_platforms:
268 print "SFA PLATFORM > ", sfa_platform['platform']
269 if not 'auth_type' in sfa_platform:
271 auth = sfa_platform['auth_type']
272 if not auth in all_authorities:
273 all_authorities.append(auth)
274 platform_ids.append(sfa_platform['platform_id'])
276 # We can check on which the user has authoritity credentials = PI rights
277 credential_authorities = set()
278 credential_authorities_expired = set()
280 # User account on these registries
281 user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
282 user_accounts = execute_query(self.request, user_accounts_query)
286 for user_account in user_accounts:
287 config = json.loads(user_account['config'])
289 if 'authority_credentials' in config:
290 for authority_hrn, credential in config['authority_credentials'].items():
291 #if credential is not expired:
292 credential_authorities.add(authority_hrn)
294 # credential_authorities_expired.add(authority_hrn)
295 if 'delegated_authority_credentials' in config:
296 for authority_hrn, credential in config['delegated_authority_credentials'].items():
297 #if credential is not expired:
298 credential_authorities.add(authority_hrn)
300 # credential_authorities_expired.add(authority_hrn)
302 print 'credential_authorities =', credential_authorities
303 print 'credential_authorities_expired =', credential_authorities_expired
305 # ** Where am I a PI **
306 # For this we need to ask SFA (of all authorities) = PI function
307 pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
308 pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
309 pi_authorities = set()
310 for pa in pi_authorities_tmp:
311 pi_authorities |= set(pa['pi_authorities'])
313 print "pi_authorities =", pi_authorities
315 # My authorities + I have a credential
316 pi_credential_authorities = pi_authorities & credential_authorities
317 pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
318 pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
319 # Authorities I've been delegated PI rights
320 pi_delegation_credential_authorities = credential_authorities - pi_authorities
321 pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
323 print "pi_credential_authorities =", pi_credential_authorities
324 print "pi_no_credential_authorities =", pi_no_credential_authorities
325 print "pi_expired_credential_authorities =", pi_expired_credential_authorities
326 print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
327 print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
329 # Summary intermediary
330 pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
331 pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
334 print "pi_my_authorities = ", pi_my_authorities
335 print "pi_delegation_authorities = ", pi_delegation_authorities
338 queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
340 print "queried_pending_authorities = ", queried_pending_authorities
342 requests = get_request_by_authority(queried_pending_authorities)
343 for request in requests:
344 auth_hrn = request['authority_hrn']
346 if auth_hrn in pi_my_authorities:
347 dest = ctx_my_authorities
349 # define the css class
350 if auth_hrn in pi_credential_authorities:
351 request['allowed'] = 'allowed'
352 elif auth_hrn in pi_expired_credential_authorities:
353 request['allowed'] = 'expired'
354 else: # pi_no_credential_authorities
355 request['allowed'] = 'denied'
357 elif auth_hrn in pi_delegation_authorities:
358 dest = ctx_delegation_authorities
360 if auth_hrn in pi_delegation_credential_authorities:
361 request['allowed'] = 'allowed'
362 else: # pi_delegation_expired_authorities
363 request['allowed'] = 'expired'
368 if not auth_hrn in dest:
370 dest[auth_hrn].append(request)
372 context = super(ValidatePendingView, self).get_context_data(**kwargs)
373 context['my_authorities'] = ctx_my_authorities
374 context['delegation_authorities'] = ctx_delegation_authorities
376 # XXX This is repeated in all pages
377 # more general variables expected in the template
378 context['title'] = 'Test view that combines various plugins'
379 # the menu items on the top
380 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
381 # so we can sho who is logged
382 context['username'] = the_user(self.request)
384 # XXX We need to prepare the page for queries
385 #context.update(page.prelude_env())