de2a9971816d9469520a8106be47913b6ab3ca90
[myslice.git] / portal / views.py
1 # -*- coding: utf-8 -*-
2 #
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
5 #
6 # Authors:
7 #   Jordan AugĂ© <jordan.auge@lip6.fr>
8 #   Mohammed Yasin Rahman <mohammed-yasin.rahman@lip6.fr>
9 # Copyright 2013, UPMC Sorbonne UniversitĂ©s / LIP6
10 #
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.
14
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
18 # details.
19
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.
23
24 import os.path, re
25 import json
26
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
33
34 from plugins.lists.simplelist    import SimpleList
35 from plugins.hazelnut            import Hazelnut
36 from plugins.pres_view           import PresView
37 from portal.event import Event
38
39 from portal                      import signals
40 from portal.forms                import SliceRequestForm
41 from portal.util                 import RegistrationView, ActivationView
42 from portal.models               import PendingUser, PendingSlice
43 from portal.actions              import authority_get_pi_emails, get_request_by_authority, manifold_add_user, manifold_update_user
44 from manifold.manifoldapi        import execute_query
45 from manifold.core.query         import Query
46 from unfold.page                 import Page
47 from myslice.viewutils           import topmenu_items, the_user
48 from django.http                 import HttpResponseRedirect, HttpResponse
49
50 #class for my_account
51 @login_required
52 #my_acc form value processing
53 def account_process(request):
54     user_query  = Query().get('local:user').select('password','config')
55     user_details = execute_query(request, user_query)
56
57     if 'submit_name' in request.POST:
58         edited_first_name =  request.POST['fname']
59         edited_last_name =  request.POST['lname']
60         
61         config={}
62         for user_config in user_details:
63         #email = user_detail['email']
64             if user_config['config']:
65                 config = json.loads(user_config['config'])
66                 config['firstname'] = edited_first_name
67                 config['lastname'] = edited_last_name
68                 config['authority'] = config.get('authority','Unknown Authority')
69                 updated_config = json.dumps(config)
70         
71         # updating config local:user in manifold       
72         user_params = { 'config': updated_config}
73         manifold_update_user(request,user_params)
74         # this will be depricated, we will show the success msg in same page
75         return HttpResponse('Sucess: First Name and Last Name Updated!')       
76     elif 'submit_pass' in request.POST:
77         edited_password = request.POST['password']
78         
79         for user_pass in user_details:
80             user_pass['password'] = edited_password
81         #updating password in local:user
82         user_params = { 'password': user_pass['password']}
83         manifold_update_user(request,user_params)
84
85         return HttpResponse('Success: Password Changed!!')
86     elif 'generate' in request.POST:
87         # Generate public and private keys using SFA Library
88         from sfa.trust.certificate  import Keypair
89         k = Keypair(create=True)
90         public_key = k.get_pubkey_string()
91         private_key = k.as_pem()
92         private_key = ''.join(private_key.split())
93         public_key = "ssh-rsa " + public_key
94         # Saving to DB
95         keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
96 #        keypair = re.sub("\r", "", keypair)
97 #        keypair = re.sub("\n", "\\n", keypair)
98 #        #keypair = keypair.rstrip('\r\n')
99 #        keypair = ''.join(keypair.split())
100         get_user.keypair = keypair
101         get_user.save()
102         return HttpResponse('Success: New Keypair Generated! %s' % keypair)
103
104     elif 'upload_key' in request.POST:
105         up_file = request.FILES['pubkey']
106         file_content =  up_file.read()
107         file_name = up_file.name
108         file_extension = os.path.splitext(file_name)[1] 
109         allowed_extension =  ['.pub','.txt']
110         if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
111             file_content = '{"user_public_key":"'+ file_content +'"}'
112             file_content = re.sub("\r", "", file_content)
113             file_content = re.sub("\n", "\\n",file_content)
114             file_content = ''.join(file_content.split())
115             get_user.keypair = file_content
116             get_user.save()
117             return HttpResponse('Success: Publickey uploaded! Old records overwritten')
118         else:
119             return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')    
120         
121     else:
122         message = 'You submitted an empty form.'
123         return HttpResponse(message)
124
125 def register_4m_f4f(request):
126     errors = []
127
128     authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
129     #authorities_query = Query.get('authority').select('authority_hrn')
130     authorities = execute_query(request, authorities_query)
131
132     if request.method == 'POST':
133         # We shall use a form here
134
135         #get_email = PendingUser.objects.get(email)
136         reg_fname = request.POST.get('firstname', '')
137         reg_lname = request.POST.get('lastname', '')
138         #reg_aff = request.POST.get('affiliation','')
139         reg_auth = request.POST.get('authority_hrn', '')
140         reg_email = request.POST.get('email','').lower()
141         
142         #POST value validation  
143         if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
144             errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
145             #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
146             #return render(request, 'register_4m_f4f.html')
147         if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
148             errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
149             #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
150             #return render(request, 'register_4m_f4f.html')
151 #        if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
152 #            errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
153             #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
154             #return render(request, 'register_4m_f4f.html')
155         # XXX validate authority hrn !!
156         if PendingUser.objects.filter(email__iexact=reg_email):
157             errors.append('Email already registered.Please provide a new email address.')
158             #return HttpResponse("Email Already exists")
159             #return render(request, 'register_4m_f4f.html')
160         if 'generate' in request.POST['question']:
161             # Generate public and private keys using SFA Library
162             from sfa.trust.certificate  import Keypair
163             k = Keypair(create=True)
164             public_key = k.get_pubkey_string()
165             private_key = k.as_pem()
166             private_key = ''.join(private_key.split())
167             public_key = "ssh-rsa " + public_key
168             # Saving to DB
169             keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
170 #            keypair = re.sub("\r", "", keypair)
171 #            keypair = re.sub("\n", "\\n", keypair)
172 #            #keypair = keypair.rstrip('\r\n')
173 #            keypair = ''.join(keypair.split())
174         else:
175             up_file = request.FILES['user_public_key']
176             file_content =  up_file.read()
177             file_name = up_file.name
178             file_extension = os.path.splitext(file_name)[1]
179             allowed_extension =  ['.pub','.txt']
180             if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
181                 keypair = '{"user_public_key":"'+ file_content +'"}'
182                 keypair = re.sub("\r", "", keypair)
183                 keypair = re.sub("\n", "\\n",keypair)
184                 keypair = ''.join(keypair.split())
185             else:
186                 errors.append('Please upload a valid RSA public key [.txt or .pub].')
187
188         #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff, 
189         #                email=reg_email, password=request.POST['password'], keypair=keypair)
190         #b.save()
191         if not errors:
192             b = PendingUser(
193                 first_name=reg_fname, 
194                 last_name=reg_lname, 
195                 #affiliation=reg_aff,
196                 authority_hrn=reg_auth,
197                 email=reg_email, 
198                 password=request.POST['password'],
199                 keypair=keypair
200             )
201             b.save()
202
203             # Send email
204             ctx = {
205                 first_name   : reg_fname, 
206                 last_name    : reg_lname, 
207                 #affiliation  : reg_aff,
208                 authority_hrn: reg_auth,
209                 email        : reg_email, 
210                 keypair      : keypair,
211                 cc_myself    : True # form.cleaned_data['cc_myself']
212             }
213
214             recipients = authority_get_pi_emails(authority_hrn)
215             if ctx['cc_myself']:
216                 recipients.append(ctx['email'])
217
218             msg = render_to_string('user_request_email.txt', ctx)
219             send_mail("Onelab New User request submitted", msg, email, recipients)
220
221             return render(request, 'user_register_complete.html')
222
223     return render(request, 'register_4m_f4f.html',{
224         'topmenu_items': topmenu_items('Register', request),
225         'errors': errors,
226         'firstname': request.POST.get('firstname', ''),
227         'lastname': request.POST.get('lastname', ''),
228         #'affiliation': request.POST.get('affiliation', ''),
229         'authority_hrn': request.POST.get('authority_hrn', ''),
230         'email': request.POST.get('email', ''),
231         'password': request.POST.get('password', ''),           
232         'authorities': authorities
233     })        
234     
235
236 @login_required
237 def slice_request(request):
238     errors = []
239
240     authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
241     #authorities_query = Query.get('authority').select('authority_hrn')
242     authorities = execute_query(request, authorities_query)
243
244     authority_hrn_tuple = []
245     for authority in authorities:
246         authority_hrn_tuple.append((authority['authority_hrn'], authority['name']))
247     authority_hrn_initial = {'authority_hrn': authority_hrn_tuple}
248         
249     # request.POST or None ?
250     if request.method == 'POST':
251         # The form has been submitted
252         form = SliceRequestForm(request.POST, initial=authority_hrn_initial) 
253
254         if form.is_valid():
255             slice_name      = form.cleaned_data['slice_name']
256             authority_hrn   = form.cleaned_data['authority_hrn']
257             number_of_nodes = form.cleaned_data['number_of_nodes']
258             type_of_nodes   = form.cleaned_data['type_of_nodes']
259             purpose         = form.cleaned_data['purpose']
260             
261             s = PendingSlice(
262                 slice_name      = slice_name,
263                 authority_hrn   = authority_hrn,
264                 number_of_nodes = number_of_nodes,
265                 type_of_nodes   = type_of_nodes,
266                 purpose         = purpose
267             )
268             s.save()
269
270             # All validation rules pass; process data in form.cleaned_data
271             # slice_name, number_of_nodes, type_of_nodes, purpose
272             email = form.cleaned_data['email'] # email of the sender
273             cc_myself = form.cleaned_data['cc_myself']
274
275             # The recipients are the PI of the authority
276             recipients = authority_get_pi_emails(authority_hrn)
277             #recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
278             if cc_myself:
279                 recipients.append(email)
280             msg = render_to_string('slice_request_email.txt', form.cleaned_data)
281             send_mail("Onelab New Slice request form submitted", msg, email, recipients)
282
283             return render(request,'slicereq_recvd.html') # Redirect after POST
284     else:
285         form = SliceRequestForm(initial=authority_hrn_initial)
286
287 #    template_env = {}
288 #    template_env['form'] = form
289 #    template_env['topmenu_items'] = topmenu_items('Request a slice', request) 
290 #    template_env['unfold1_main'] = render(request, 'slice_request_.html', {
291 #        'form': form,
292 #    })
293 #    from django.shortcuts                import render_to_response
294 #    from django.template                 import RequestContext
295 #    return render_to_response ('view-unfold1.html',template_env,
296 #                               context_instance=RequestContext(request))
297
298     return render(request, 'slice_request.html', {
299         'form': form,
300         'topmenu_items': topmenu_items('Request a slice', request),
301         'username': the_user (request) 
302     })
303
304
305 class PresViewView(TemplateView):
306     template_name = "view-unfold1.html"
307
308     def get_context_data(self, **kwargs):
309
310         page = Page(self.request)
311
312         pres_view = PresView(page = page)
313
314         context = super(PresViewView, self).get_context_data(**kwargs)
315
316         #context['ALL_STATIC'] = "all_static"
317         context['unfold1_main'] = pres_view.render(self.request)
318
319         # XXX This is repeated in all pages
320         # more general variables expected in the template
321         context['title'] = 'Test view that combines various plugins'
322         # the menu items on the top
323         context['topmenu_items'] = topmenu_items('PresView', self.request)
324         # so we can sho who is logged
325         context['username'] = the_user(self.request)
326
327         prelude_env = page.prelude_env()
328         context.update(prelude_env)
329
330         return context
331
332 def json_me(config_file,type):
333     json_answer = ''
334     for ligne in config_file:
335         if not ligne.startswith('#'):
336             args = ligne.split(';')
337             json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1]  + '" ,"descriptif":"' + args[2]+'"')
338             if type!="dynamic":
339                 json_answer += str(',"contraints":')
340                 if args[3]=="":
341                     json_answer += str('""')
342                 else:
343                     json_answer += str(args[3])
344             json_answer += str('},')
345     return json_answer[:-1]
346
347
348 DIR = '/var/myslice/'
349 STATIC = '%s/config_method_static' % DIR
350 DYNAMIC = '%s/config_method_dynamic' % DIR
351 ANIMATION = '%s/config_method_animation' % DIR
352
353 def pres_view_methods(request, type):
354
355     if type ==None:
356         return 0
357     elif type =="static":
358         config = open(STATIC, "r")
359         json_answer = str('{ "options": [')
360         json_answer += str(json_me(config,"static"))
361         json_answer += str('] }')
362         config.close()
363     elif type =="dynamic":
364         config = open(DYNAMIC, "r")
365         json_answer = str('{ "options": [')
366         json_answer += str(json_me(config,"dynamic"))
367         json_answer += str('] }')
368         config.close()
369     elif type =="animation":
370         config = open(ANIMATION, "r")
371         json_answer = str('{ "options": [')
372         json_answer += str(json_me(config,"animation"))
373         json_answer += str('] }')
374         config.close()
375     elif type =="all":
376         config = open(STATIC, "r")
377         json_answer = str('{ "static": [')
378         json_answer += str(json_me(config,"static"))
379         json_answer += str('],')
380         json_answer += str('"dynamic": [')
381         config.close()
382         config = open(DYNAMIC, "r")
383         json_answer += str(json_me(config,"dynamic"))
384         json_answer += str('],')
385         json_answer += str('"animation": [')
386         config.close()
387         config = open(ANIMATION, "r")
388         json_answer += str(json_me(config,"animation"))
389         json_answer += str('] }')
390         config.close()
391     else:
392         return 0
393     return HttpResponse (json_answer, mimetype="application/json")
394
395 def pres_view_animation(request, constraints, id):
396
397 # sites crees depuis 2008
398 # static.py?contraints=']date_created':1262325600&id='name_id"'
399
400     # method = request.getvalue('method') #ex : GetSites
401     #constraints = "']date_created':1262325600"
402     #id = "2"
403
404     if id == None:
405         return 0
406
407     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
408     # constraints = {}#request.getvalue('constraints') // nul = {}
409     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
410
411     config_file = open(ANIMATION, "r")
412     for ligne in config_file:
413         if not ligne.startswith('#'):
414             ligne = ligne.split('\n')
415             first = ligne[0].split(';')
416             if (str(first[1]) == str(id)):
417                 save = first
418     config_file.close()
419
420     #Les print_method, print_option sont definis par le client (js)
421     #Les animations acceptent que les connexions anonymous
422     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
423     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
424
425
426     #Creation d'un objet event
427     event = Event(args)
428     cmd = [{"params": {
429             "data": {
430                 "print_options": event.print_options,
431                 "print_method": event.print_method,
432                 "message": event.data
433             }
434         }
435     }]
436
437     json_answer = json.dumps(cmd)
438     return HttpResponse (json_answer, mimetype="application/json")
439
440 def pres_view_static(request, constraints, id):
441     #constraints = "']date_created':1262325600"
442     #id = "2"
443
444     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
445     # constraints = {}#request.getvalue('constraints') // nul = {}
446     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
447
448     config_file = open(STATIC, "r")
449     for ligne in config_file:
450         if not ligne.startswith('#'):
451             ligne = ligne.split('\n')
452             first = ligne[0].split(';')
453             if (str(first[1]) == str(id)):
454                 save = first
455     config_file.close()
456
457     #Les print_method, print_option sont definis par le client (js)
458     #Les animations acceptent que les connexions anonymous
459     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
460     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
461
462
463     #Creation d'un objet event
464     event = Event(args)
465     cmd = [{"params": {
466             "data": {
467                 "print_options": event.print_options,
468                 "print_method": event.print_method,
469                 "message": event.data
470             }
471         }
472     }]
473
474     json_answer = json.dumps(cmd)
475     return HttpResponse (json_answer, mimetype="application/json")
476
477 class ValidatePendingView(TemplateView):
478     template_name = "validate_pending.html"
479
480     def get_context_data(self, **kwargs):
481         # We might have slices on different registries with different user accounts 
482         # 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
483         # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
484
485         #messages.info(self.request, 'You have logged in')
486         page = Page(self.request)
487
488         ctx_my_authorities = {}
489         ctx_delegation_authorities = {}
490
491
492         # The user need to be logged in
493         if the_user(self.request):
494             # Who can a PI validate:
495             # His own authorities + those he has credentials for.
496             # In MySlice we need to look at credentials also.
497             
498
499             # XXX This will have to be asynchroneous. Need to implement barriers,
500             # for now it will be sufficient to have it working statically
501
502             # get user_id to later on query accounts
503             # XXX Having real query plan on local tables would simplify all this
504             # XXX $user_email is still not available for local tables
505             #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
506             user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
507             user, = execute_query(self.request, user_query)
508             user_id = user['user_id']
509
510             # Query manifold to learn about available SFA platforms for more information
511             # In general we will at least have the portal
512             # For now we are considering all registries
513             all_authorities = []
514             platform_ids = []
515             sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
516             sfa_platforms = execute_query(self.request, sfa_platforms_query)
517             for sfa_platform in sfa_platforms:
518                 print "SFA PLATFORM > ", sfa_platform['platform']
519                 if not 'auth_type' in sfa_platform:
520                     continue
521                 auth = sfa_platform['auth_type']
522                 if not auth in all_authorities:
523                     all_authorities.append(auth)
524                 platform_ids.append(sfa_platform['platform_id'])
525
526             # We can check on which the user has authoritity credentials = PI rights
527             credential_authorities = set()
528             credential_authorities_expired = set()
529
530             # User account on these registries
531             user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
532             user_accounts = execute_query(self.request, user_accounts_query)
533             #print "=" * 80
534             #print user_accounts
535             #print "=" * 80
536             for user_account in user_accounts:
537                 config = json.loads(user_account['config'])
538                 creds = []
539                 if 'authority_credentials' in config:
540                     for authority_hrn, credential in config['authority_credentials'].items():
541                         #if credential is not expired:
542                         credential_authorities.add(authority_hrn)
543                         #else
544                         #    credential_authorities_expired.add(authority_hrn)
545                 if 'delegated_authority_credentials' in config:
546                     for authority_hrn, credential in config['delegated_authority_credentials'].items():
547                         #if credential is not expired:
548                         credential_authorities.add(authority_hrn)
549                         #else
550                         #    credential_authorities_expired.add(authority_hrn)
551
552             print 'credential_authorities =', credential_authorities
553             print 'credential_authorities_expired =', credential_authorities_expired
554
555             # ** Where am I a PI **
556             # For this we need to ask SFA (of all authorities) = PI function
557             pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
558             pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
559             pi_authorities = set()
560             for pa in pi_authorities_tmp:
561                 pi_authorities |= set(pa['pi_authorities'])
562
563             print "pi_authorities =", pi_authorities
564             
565             # My authorities + I have a credential
566             pi_credential_authorities = pi_authorities & credential_authorities
567             pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
568             pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
569             # Authorities I've been delegated PI rights
570             pi_delegation_credential_authorities = credential_authorities - pi_authorities
571             pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
572
573             print "pi_credential_authorities =", pi_credential_authorities
574             print "pi_no_credential_authorities =", pi_no_credential_authorities
575             print "pi_expired_credential_authorities =", pi_expired_credential_authorities
576             print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
577             print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
578
579             # Summary intermediary
580             pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
581             pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
582
583             print "--"
584             print "pi_my_authorities = ", pi_my_authorities
585             print "pi_delegation_authorities = ", pi_delegation_authorities
586
587             # Summary all
588             queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
589             print "----"
590             print "queried_pending_authorities = ", queried_pending_authorities
591
592             requests = get_request_by_authority(queried_pending_authorities)
593             for request in requests:
594                 auth_hrn = request['authority_hrn']
595
596                 if auth_hrn in pi_my_authorities:
597                     dest = ctx_my_authorities
598
599                     # define the css class
600                     if auth_hrn in pi_credential_authorities:
601                         request['allowed'] = 'allowed'
602                     elif auth_hrn in pi_expired_credential_authorities:
603                         request['allowed'] = 'expired'
604                     else: # pi_no_credential_authorities
605                         request['allowed'] = 'denied'
606
607                 elif auth_hrn in pi_delegation_authorities:
608                     dest = ctx_delegation_authorities
609
610                     if auth_hrn in pi_delegation_credential_authorities:
611                         request['allowed'] = 'allowed'
612                     else: # pi_delegation_expired_authorities
613                         request['allowed'] = 'expired'
614
615                 else:
616                     continue
617
618                 if not auth_hrn in dest:
619                     dest[auth_hrn] = []
620                 dest[auth_hrn].append(request) 
621         
622         context = super(ValidatePendingView, self).get_context_data(**kwargs)
623         context['my_authorities']   = ctx_my_authorities
624         context['delegation_authorities'] = ctx_delegation_authorities
625
626         # XXX This is repeated in all pages
627         # more general variables expected in the template
628         context['title'] = 'Test view that combines various plugins'
629         # the menu items on the top
630         context['topmenu_items'] = topmenu_items('Dashboard', self.request) 
631         # so we can sho who is logged
632         context['username'] = the_user(self.request) 
633
634         # XXX We need to prepare the page for queries
635         #context.update(page.prelude_env())
636
637         return context