merge
authorCiro Scognamiglio <ciro.scognamiglio@cslash.net>
Mon, 15 Sep 2014 14:43:00 +0000 (16:43 +0200)
committerCiro Scognamiglio <ciro.scognamiglio@cslash.net>
Mon, 15 Sep 2014 14:43:00 +0000 (16:43 +0200)
29 files changed:
portal/accountview.py
portal/actions.py
portal/joinview.py
portal/managementtababout.py
portal/templates/authority_request_denied.html [new file with mode: 0644]
portal/templates/authority_request_denied.txt [new file with mode: 0644]
portal/templates/authority_request_email.html
portal/templates/authority_request_email.txt
portal/templates/management-tab-requests.html
portal/templates/onelab/onelab_account-view.html
portal/templates/onelab/onelab_home-view.html
portal/templates/onelab/onelab_institution.html
portal/templates/onelab/onelab_management-tab-about.html
portal/templates/onelab/onelab_management-tab-requests.html
portal/templates/onelab/onelab_registration_view.html
portal/templates/onelab/onelab_slicerequest_view.html
portal/templates/onelab/onelab_user_request_email.html
portal/templates/slice-request-done-view.html
portal/templates/slice_request_denied.html [new file with mode: 0644]
portal/templates/slice_request_denied.txt [new file with mode: 0644]
portal/templates/slice_request_email.html
portal/templates/slice_request_email.txt
portal/templates/slice_request_validated.html [new file with mode: 0644]
portal/templates/slice_request_validated.txt [new file with mode: 0644]
portal/templates/user_request_denied.html [new file with mode: 0644]
portal/templates/user_request_denied.txt [new file with mode: 0644]
portal/templates/user_request_validated.html [new file with mode: 0644]
portal/templates/user_request_validated.txt [new file with mode: 0644]
portal/urls.py

index bf033e6..5048383 100644 (file)
@@ -189,29 +189,36 @@ class AccountView(LoginRequiredAutoLogoutView, ThemeView):
 
 
         ## check user is pi or not
-        platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
-        account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
-        platform_details = execute_query(self.request, platform_query)
-        account_details = execute_query(self.request, account_query)
-        for platform_detail in platform_details:
-            for account_detail in account_details:
-                if platform_detail['platform_id'] == account_detail['platform_id']:
-                    if 'config' in account_detail and account_detail['config'] is not '':
-                        account_config = json.loads(account_detail['config'])
-                        if 'myslice' in platform_detail['platform']:
-                            acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+      #  platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+      #  account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+      #  platform_details = execute_query(self.request, platform_query)
+      #  account_details = execute_query(self.request, account_query)
+      #  for platform_detail in platform_details:
+      #      for account_detail in account_details:
+      #          if platform_detail['platform_id'] == account_detail['platform_id']:
+      #              if 'config' in account_detail and account_detail['config'] is not '':
+      #                  account_config = json.loads(account_detail['config'])
+      #                  if 'myslice' in platform_detail['platform']:
+      #                      acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
         # assigning values
         if acc_auth_cred == {} or acc_auth_cred == 'N/A':
             pi = "is_not_pi"
         else:
             pi = "is_pi"
 
+        # check if the user has creds or not
+        if acc_user_cred == {} or acc_user_cred == 'N/A':
+            user_cred = 'no_creds'
+        else:
+            user_cred = 'has_creds'
+
         context = super(AccountView, self).get_context_data(**kwargs)
         context['principal_acc'] = principal_acc_list
         context['ref_acc'] = ref_acc_list
         context['platform_list'] = platform_list
         context['my_users'] = my_users
         context['pi'] = pi
+        context['user_cred'] = user_cred
         context['my_slices'] = my_slices
         context['my_auths'] = my_auths
         context['user_status'] = user_status
index 38af28c..b272e2d 100644 (file)
@@ -4,7 +4,9 @@ from manifoldapi.manifoldapi    import execute_query,execute_admin_query
 from portal.models              import PendingUser, PendingSlice, PendingAuthority
 import json
 
-from django.contrib.auth.models import User
+from django.contrib.auth.models  import User
+from django.contrib.sites.models import Site
+from django.contrib.auth        import get_user_model
 from django.template.loader     import render_to_string
 from django.core.mail           import EmailMultiAlternatives, send_mail
 
@@ -201,6 +203,11 @@ def manifold_delete_account(request, platform_id, user_id, account_params):
     results = execute_admin_query(request,query)
     return results
 
+def manifold_delete_user(request, user_id, user_params):
+    query = Query.delete('local:user').filter_by('user_id', '==', user_id).set(user_params).select('user_id')
+    results = execute_admin_query(request,query)
+    return results
+
 
 #not tested
 def manifold_add_platform(request, platform_params):
@@ -383,13 +390,177 @@ def portal_validate_request(wsgi_request, request_ids):
 
     return status
 
-
 def validate_action(request, **kwargs):
     ids = filter(None, kwargs['id'].split('/'))
     status = portal_validate_request(request, ids)
     json_answer = json.dumps(status)
     return HttpResponse (json_answer, mimetype="application/json")
 
+
+def reject_action(request, **kwargs):
+    ids = filter(None, kwargs['id'].split('/'))
+    status = portal_reject_request(request, ids)
+    json_answer = json.dumps(status)
+    return HttpResponse (json_answer, mimetype="application/json")
+
+
+def portal_reject_request(wsgi_request, request_ids):
+    status = {}
+    # get the domain url    
+    current_site = Site.objects.get_current()
+    current_site = current_site.domain
+
+
+    if not isinstance(request_ids, list):
+        request_ids = [request_ids]
+
+    requests = get_request_by_id(request_ids)
+    for request in requests:
+        # type, id, timestamp, details, allowed -- MISSING: authority_hrn
+        # CAREFUL about details
+        # user  : first name, last name, email, password, keypair
+        # slice : number of nodes, type of nodes, purpose
+        
+        request_status = {}
+
+        if request['type'] == 'user':
+            try:
+                request_status['SFA user'] = {'status': True }
+                # getting user email based on id 
+                ## RAW SQL queries on Django DB- https://docs.djangoproject.com/en/dev/topics/db/sql/
+                for user in PendingUser.objects.raw('SELECT * FROM portal_pendinguser WHERE id = %s', [request['id']]):
+                    user_email= user.email
+                    first_name = user.first_name
+                    last_name = user.last_name
+
+                ctx = {
+                    'first_name'    : first_name, 
+                    'last_name'     : last_name, 
+                    'portal_url'    : current_site,
+                    }
+                try:
+                    theme.template_name = 'user_request_denied.txt'
+                    text_content = render_to_string(theme.template, ctx)
+                    theme.template_name = 'user_request_denied.html'
+                    html_content = render_to_string(theme.template, ctx)
+                    theme.template_name = 'email_default_sender.txt'
+                    sender =  render_to_string(theme.template, ctx)
+                    sender = sender.replace('\n', '')
+                               
+                    subject = 'User request denied.'
+
+                    msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+                    msg.attach_alternative(html_content, "text/html")
+                    msg.send()
+                except Exception, e:
+                    print "Failed to send email, please check the mail templates and the SMTP configuration of your server"   
+            
+                # removing from Django auth_user
+                UserModel = get_user_model()
+                UserModel._default_manager.filter(email__iexact = user_email).delete()
+                # removing from Django portal_pendinguser
+                PendingUser.objects.get(id=request['id']).delete()
+                # removing from manifold
+                # removing manifold account
+                user_query = Query().get('local:user') \
+                    .filter_by('email', '==', user_email)           \
+                    .select('user_id')
+                user = execute_admin_query(wsgi_request, user_query)
+                user_id = user[0]['user_id']
+        
+                platform_query = Query().get('local:platform') \
+                    .filter_by('platform', '==', 'myslice')           \
+                    .select('platform_id')
+                platform = execute_admin_query(wsgi_request, platform_query)
+                platform_id = platform[0]['platform_id']
+                account_params = {'user_id':user_id}
+                manifold_delete_account(request, platform_id, user_id, account_params)           
+             
+                # removing manifold user
+                user_params = {'user_id':user_id}
+                manifold_delete_user(request, user_id, user_params)
+            except Exception, e:
+                request_status['SFA authority'] = {'status': False, 'description': str(e)}
+                      
+        elif request['type'] == 'slice':
+            request_status['SFA slice'] = {'status': True } 
+
+            # getting user email based on id 
+            ## RAW SQL queries on Django DB- https://docs.djangoproject.com/en/dev/topics/db/sql/
+            for user in PendingSlice.objects.raw('SELECT * FROM portal_pendingslice WHERE id = %s', [request['id']]):
+                user_email= user.type_of_nodes # XXX type_of_nodes field contains the email [shd be renamed in DB]
+                slice_name = user.slice_name
+                purpose = user.purpose
+                url = user.number_of_nodes
+
+            ctx = {
+                'slice_name': slice_name,
+                'purpose': purpose,
+                'url': url,
+                'portal_url': current_site,
+                }
+            try:
+                theme.template_name = 'slice_request_denied.txt'
+                text_content = render_to_string(theme.template, ctx)
+                theme.template_name = 'slice_request_denied.html'
+                html_content = render_to_string(theme.template, ctx)
+                theme.template_name = 'email_default_sender.txt'
+                sender =  render_to_string(theme.template, ctx)
+                sender = sender.replace('\n', '')
+                               
+                subject = 'Slice request denied.'
+
+                msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+                msg.attach_alternative(html_content, "text/html")
+                msg.send()
+            except Exception, e:
+                print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+                      
+            PendingSlice.objects.get(id=request['id']).delete()
+
+        elif request['type'] == 'authority':
+            request_status['SFA authority'] = {'status': True }
+            
+            # getting user email based on id 
+            ## RAW SQL queries on Django DB- https://docs.djangoproject.com/en/dev/topics/db/sql/
+            for user in PendingAuthority.objects.raw('SELECT * FROM portal_pendingauthority WHERE id = %s', [request['id']]):
+                user_email= user.address_line1 # XXX address_line1 field contains the email [shd be renamed in DB]
+                site_name = user.site_name
+                city = user.address_city
+                country = user.address_country
+                short_name = user.site_abbreviated_name
+                url = user.site_url
+
+            ctx = { 
+                'site_name': site_name,
+                'short_name': short_name,
+                'url': url,
+                'city': city,
+                'country': country,                          
+                'portal_url'    : current_site,
+                }
+                
+            try:
+                theme.template_name = 'authority_request_denied.txt'
+                text_content = render_to_string(theme.template, ctx)
+                theme.template_name = 'authority_request_denied.html'
+                html_content = render_to_string(theme.template, ctx)
+                theme.template_name = 'email_default_sender.txt'
+                sender =  render_to_string(theme.template, ctx)
+                sender = sender.replace('\n', '')
+                subject = 'Authority request denied.'
+                msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+                msg.attach_alternative(html_content, "text/html")
+                msg.send()
+            except Exception, e:
+                print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+
+            PendingAuthority.objects.get(id=request['id']).delete()
+
+        status['%s__%s' % (request['type'], request['id'])] = request_status
+
+    return status
+
 # Django and ajax
 # http://djangosnippets.org/snippets/942/
 
@@ -445,9 +616,24 @@ def create_slice(wsgi_request, request):
         raise Exception, "Could not create %s. Already exists ?" % slice_params['hrn']
     else:
         clear_user_creds(wsgi_request,user_email)
-        subject = 'Slice created'
-        msg = 'A manager of your institution has validated your slice request. You can now add resources to the slice and start experimenting.'
-        send_mail(subject, msg, 'support@onelab.eu',[user_email], fail_silently=False)
+
+        try:
+            theme.template_name = 'slice_request_validated.txt'
+            text_content = render_to_string(theme.template, request)
+            theme.template_name = 'slice_request_validated.html'
+            html_content = render_to_string(theme.template, request)
+        
+            theme.template_name = 'email_default_sender.txt'
+            sender =  render_to_string(theme.template, request)
+            sender = sender.replace('\n', '')
+
+            subject = 'Slice request validated'
+
+            msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+            msg.attach_alternative(html_content, "text/html")
+            msg.send()
+        except Exception, e:
+            print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
        
     return results
 
@@ -460,8 +646,9 @@ def create_pending_slice(wsgi_request, request, email):
         slice_name      = request['slice_name'],
         user_hrn        = request['user_hrn'],
         authority_hrn   = request['authority_hrn'],
-        number_of_nodes = request['url'],
+        number_of_nodes = request['url'], # field needs to be renamed
         purpose         = request['purpose'],
+        type_of_nodes   = request['email'] # field needs to be renamed 
     )
     s.save()
 
@@ -572,9 +759,25 @@ def sfa_create_user(wsgi_request, request, namespace = None, as_admin = False):
     if not results:
         raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
     else:
-        subject = 'User validated'
-        msg = 'A manager of your institution has validated your account. You have now full user access to the portal.'
-        send_mail(subject, msg, 'support@onelab.eu',[request['email']], fail_silently=False)       
+        try:
+            theme.template_name = 'user_request_validated.txt'
+            text_content = render_to_string(theme.template, request)
+            theme.template_name = 'user_request_validated.html'
+            html_content = render_to_string(theme.template, request)
+        
+            theme.template_name = 'email_default_sender.txt'
+            sender =  render_to_string(theme.template, request)
+            sender = sender.replace('\n', '')
+
+
+            subject = 'User validated'
+
+            msg = EmailMultiAlternatives(subject, text_content, sender, [request['email']])
+            msg.attach_alternative(html_content, "text/html")
+            msg.send()
+        except Exception, e:
+            print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+
     return results
 
 def create_user(wsgi_request, request, namespace = None, as_admin = False):
index 832055b..0282e96 100644 (file)
@@ -141,7 +141,7 @@ class JoinView (FreeAccessView, ThemeView):
                     site_url              = reg_site_url,
                     site_latitude         = reg_site_latitude, 
                     site_longitude        = reg_site_longitude,
-                    address_line1         = reg_address_line1,
+                    address_line1         = reg_email, # XXX field name must be renamed. Email needed 4 rejection email.
                     address_line2         = reg_address_line2,
                     address_line3         = reg_address_line3,
                     address_city          = reg_address_city,
@@ -197,14 +197,7 @@ class JoinView (FreeAccessView, ThemeView):
                         'authority_hrn'         : reg_root_authority_hrn + '.' + reg_site_authority,
                         'site_abbreviated_name' : reg_site_abbreviated_name, 
                         'site_url'              : reg_site_url,
-                        'site_latitude'         : reg_site_latitude, 
-                        'site_longitude'        : reg_site_longitude,
-                        'address_line1'         : reg_address_line1,
-                        'address_line2'         : reg_address_line2,
-                        'address_line3'         : reg_address_line3,
                         'address_city'          : reg_address_city,
-                        'address_postalcode'    : reg_address_postalcode,
-                        'address_state'         : reg_address_state,
                         'address_country'       : reg_address_country,
                         'first_name'            : reg_fname, 
                         'last_name'             : reg_lname, 
@@ -213,33 +206,33 @@ class JoinView (FreeAccessView, ThemeView):
                         'user_hrn'              : user_hrn,
                         'public_key'            : public_key,
                         }
-                    recipients = authority_get_pi_emails(request,reg_auth)
+
+                    #recipients = authority_get_pi_emails(request,reg_auth)
                     
-                    # We don't need to send this email to user.
-                    # it's for the PI only
-                    #if ctx['cc_myself']:
-                    #    recipients.append(ctx['email'])
-                    theme.template_name = 'authority_request_email.html'
-                    html_content = render_to_string(theme.template, ctx)
+                    self.template_name = 'authority_request_email.html'
+                    html_content = render_to_string(self.template, ctx)
             
-                    theme.template_name = 'authority_request_email.txt'
-                    text_content = render_to_string(theme.template, ctx)
+                    self.template_name = 'authority_request_email.txt'
+                    text_content = render_to_string(self.template, ctx)
             
-                    theme.template_name = 'authority_request_email_subject.txt'
-                    subject = render_to_string(theme.template, ctx)
+                    self.template_name = 'authority_request_email_subject.txt'
+                    subject = render_to_string(self.template, ctx)
                     subject = subject.replace('\n', '')
             
-                    theme.template_name = 'email_default_sender.txt'
-                    sender =  render_to_string(theme.template, ctx)
-                    sender = sender.replace('\n', '')
-            
-                    msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+                    #theme.template_name = 'email_default_sender.txt'
+                    #sender =  render_to_string(theme.template, ctx)
+                    #sender = sender.replace('\n', '')
+                    sender = reg_email
+                    
+                    msg = EmailMultiAlternatives(subject, text_content, sender, ['support@onelab.eu'])
                     msg.attach_alternative(html_content, "text/html")
                     msg.send()
     
                 except Exception, e:
                     print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
-                
+                    import traceback
+                    traceback.print_exc()
+
                 self.template_name = 'join_complete.html'
                 # log institution activity
                 activity.institution.joined(self.request)
index cee9311..8bd1cdc 100644 (file)
@@ -28,8 +28,9 @@ class ManagementAboutView (FreeAccessView, ThemeView):
             user_local_query  = Query().get('local:user').select('config').filter_by('email','==',str(self.request.user))
             user_local_details = execute_query(self.request, user_local_query)
             user_authority = json.loads(user_local_details[0]['config']).get('authority')
-            
-            authority_query = Query().get('authority').select('description', 'authority_hrn', 'legal', 'address', 'abbreviated_name', 
+            # XXX Should be done using Metadata
+            # select column.name from local:object where table=='authority'
+            authority_query = Query().get('authority').select('authority_hrn', 'name', 'address', 'enabled','description', 
                                                               'scientific', 'city', 'name', 'url', 'country', 'enabled', 'longitude', 
                                                               'tech', 'latitude', 'pi_users', 'parent_authority', 'onelab_membership', 
                                                               'postcode').filter_by('authority_hrn','==',user_authority)
@@ -37,11 +38,13 @@ class ManagementAboutView (FreeAccessView, ThemeView):
             
             if authority_details :
                 authority_contacts = {}
-                authority_contacts['scientific'] = [ x.strip()[1:-1] for x in authority_details[0]['scientific'][1:-1].split(',') ]
-                authority_contacts['technical'] = [ x.strip()[1:-1] for x in authority_details[0]['tech'][1:-1].split(',') ]
-            
-                authority_contacts['legal'] = [ x.strip().replace('"','') for x in authority_details[0]['legal'][1:-1].split(',') ]
                 authority = authority_details[0]
+                if 'scientific' in authority and authority['scientific'] is not None:
+                    authority_contacts['scientific'] = [ x.strip()[1:-1] for x in authority['scientific'][1:-1].split(',') ]
+                if 'technical' in authority and authority['technical'] is not None:
+                    authority_contacts['technical'] = [ x.strip()[1:-1] for x in authority['tech'][1:-1].split(',') ]
+                if 'legal' in authority and authority['legal'] is not None:
+                    authority_contacts['legal'] = [ x.strip().replace('"','') for x in authority['legal'][1:-1].split(',') ]
             else :
                 authority_contacts = None
                 authority = None
diff --git a/portal/templates/authority_request_denied.html b/portal/templates/authority_request_denied.html
new file mode 100644 (file)
index 0000000..a028170
--- /dev/null
@@ -0,0 +1,20 @@
+<p>Dear OneLab user,</p>
+<p></p>
+<p>You have recently requested an addition of the following authority in the OneLab portal ({{portal_url}}):</p> 
+<p></p>
+<b>Name of organization:</b> {{site_name}}<br>
+<b>Short name:</b> {{short_name}}<br>
+<b>Url:</b> {{url}}<br>
+<b>City:</b> {{city}}<br>
+<b>Country:</b> {{country}}<br>
+<p></p>
+</p>After verifying your request, we regret to inform you that, we are unable to validate your request.</p>
+<p>For any queries, contact us by replying to this email.</p>
+<br>
+<p>On behalf of the entire team, I wish you all the best.</p>
+<br>
+<p>Yours sincerely,</p>
+<br>
+<p>Timur Friedman</p>
+<p>Executive Director</p>
+
diff --git a/portal/templates/authority_request_denied.txt b/portal/templates/authority_request_denied.txt
new file mode 100644 (file)
index 0000000..7708b3f
--- /dev/null
@@ -0,0 +1,21 @@
+Dear OneLab user,
+
+You have recently requested an addition of the following authority in the OneLab portal ({{portal_url}}): 
+
+Name of organization: {{site_name}}
+Short name: {{short_name}}
+Url: {{url}}
+City: {{city}}
+Country: {{country}}
+
+
+After verifying your request, we regret to inform you that, we are unable to validate your request.
+For any queries, contact us by replying to this email.
+
+On behalf of the entire team, I wish you all the best.
+
+Yours sincerely,
+
+Timur Friedman
+Executive Director
+
index 51b7c40..bdcd065 100644 (file)
@@ -1,27 +1,24 @@
-<img src="https://onelab.eu/templates/onelab2/images/logo.png">
+<img src="{{ STATIC_URL }}img/onelab.png">
 <br>
 <h1>NEW AUTHORITY REQUEST</h1>
 <br>
+<p>This email is only for OneLab admins</p>
+<br>
 <h2>{{site_name}}</h2>             
-<b>Authority hrn    :</b> {{authority_hrn}}         
-<b>Abreviated name  :</b> {{site_abbreviated_name}} 
-<b>URL              :</b> {{site_url}}              
-<b>latitude         :</b> {{site_latitude}}         
-<b>longitude        :</b> {{site_longitude}}        
-<b>Address          :</b> {{address_line1}}<br>        
-                          {{address_line2}}<br>     
-                          {{address_line3}}<br>         
-<b>City             :</b> {{address_city}}          
-<b>Postcode         :</b> {{address_postalcode}}    
-<b>State            :</b> {{address_state}}         
-<b>Country          :</b> {{address_country}}  
+<b>Authority hrn    :</b> {{authority_hrn}}<br>         
+<b>Abreviated name  :</b> {{site_abbreviated_name}}<br>
+<b>URL              :</b> {{site_url}}<br>              
+<b>City             :</b> {{address_city}}<br>          
+<b>Postcode         :</b> {{address_postalcode}}<br>    
+<b>State            :</b> {{address_state}}<br>         
+<b>Country          :</b> {{address_country}}<br>  
 
 <br><br>
 
 <h2>PI for this Authority</h2>     
-<b>First Name   :</b> {{first_name}}
-<b>Last Name    :</b> {{last_name}}
-<b>Authority hrn:</b> {{authority_hrn}}
-<b>Public key   :</b> {{public_key}}
-<b>Email        :</b> {{email}}
-<b>User Hrn     :</b> {{user_hrn}}
+<b>First Name   :</b> {{first_name}}<br>
+<b>Last Name    :</b> {{last_name}}<br>
+<b>Authority hrn:</b> {{authority_hrn}}<br>
+<b>Public key   :</b> {{public_key}}<br>
+<b>Email        :</b> {{email}}<br>
+<b>User Hrn     :</b> {{user_hrn}}<br>
index 25eb21b..9376a65 100644 (file)
@@ -1,3 +1,5 @@
+This email is only for OneLab admins.
+
 NEW AUTHORITY REQUEST
 
 Site             : {{site_name}}             
@@ -6,15 +8,8 @@ Authority hrn    : {{authority_hrn}}
 Abreviated name  : {{site_abbreviated_name}} 
 URL              : {{site_url}}              
 
-latitude         : {{site_latitude}}         
-longitude        : {{site_longitude}}        
 
-Address          : {{address_line1}}
-                   {{address_line2}}     
-                   {{address_line3}}         
 City             : {{address_city}}          
-Postcode         : {{address_postalcode}}    
-State            : {{address_state}}         
 Country          : {{address_country}}  
 
 
index 2270a3b..346ecb0 100644 (file)
                                                $('#portal__status__' + request_type__id).html(status_str);
 
 
+                                       });
+                               }
+                       );
+               }
+       }
+       function on_click_reject() {
+               var ids = []; 
+               $('.portal__validate__checkbox').each(function(i, el) {
+                       if ($(el).prop('checked')) {
+                               // portal__validate__checkbox__slice__2
+                               var id_array = $(el).attr('id').split('__');
+                               // push(slice__2)
+                               ids.push(id_array[3] + '__' + id_array[4]);
+                       }
+               });
+               if (ids.length > 0) {
+                       var id_str = ids.join('/');
+
+                       // XXX spinner
+
+                       $.getJSON('/portal/reject_action/' + id_str,
+                               function(status) {
+                                       $.each(status, function(request_type__id, request_status) {
+                                               // request_status: NAME -> dict (status, description)
+                                               var status_str = '';
+                                               $.each(request_status, function(name, result) {
+                                                       if (status_str != '')
+                                                               status_str += ' -- ';
+
+                                                       if (result.status) {
+                                                               status_str += '<font color="green">Rejected</font>';
+                                                               $('#portal__validate__checkbox__' + request_type__id).hide();
+                                                       } else {
+                                                               status_str += '<font color="red">ERROR: ' + result.description + '</font>';
+                                                       }
+                                               });
+                                               $('#portal__status__' + request_type__id).html(status_str);
+
+
                                        });
                                }
                        );
         Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
         {% else %}
             {% if request.type == 'slice' %}
-        Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+        Slice name: {{request.slice_name}} -- Url: {{request.number_of_nodes}} -- Email: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
             {% else %} {# authority #}
         Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
             {% endif %}
 <br />
 <div class="col-md-12">
        <button class="btn btn-onelab" type="button" id="portal__validate" onclick="on_click_event();"><span class="glyphicon glyphicon-ok"></span> Validate</button>
+       <button class="btn btn-onelab" type="button" id="portal__reject" onclick="on_click_reject();"><span class="glyphicon glyphicon-remove"></span> Reject</button>
 </div>
index 585e39b..57acd89 100644 (file)
                <div class="col-md-12">
                <h3>Credentials <small>Delegated to Principal Account</small></h3>
                        <table class="table">
+                                        {%if 'no_creds'  in user_cred %}
+                                               <p><a href="#" style="color:red" data-toggle="modal" data-target="#myModal">NO CREDENTIALS</a> are delegated to the portal!</p>
+                                       {%endif%}       
                                        <caption><b>Delegated User Credential</b></caption> 
                            <tr class="odd"> 
                                <th>Expiration Date</th>
                                {%endif%}
                </div>
        </div>
+<!-- Modal- No credentials -->
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+            <div class="modal-dialog">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                            <h4 class="modal-title" id="myModalLabel">No credentials are delegated to the portal</h4>
+                    </div>
+                    <div class="modal-body">
+                                       <p>You may get this message for several reasons.</p>
+                                       <h3>Account Delegation: Automatic</h3>
+                                       <ul>
+                                               <li>If you press the "Clear Credentials" button</li>
+                                               <li>If you "Generate a new key pair"</li>
+                                               <li>If a new slice is added to your account</li>
+                                       </ul>
+                                       <p>In all the above mentioned cases, it is sufficient to refresh the page or go back to home page. The portal will regenrate your credentials.
+                                        In some cases it may take more time than usual. If nothing works, then please logout and login again to the portal.</p>
+                                       <h3>Account Delegation: Manual</h3>
+                                               <p>As you have uploaded your own public key, the portal can no longer generate your credentials automatically.</p>
+                                               <p>In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to
+                                               <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">delegate your credentials to the portal.</a>
+                                       </p>
+                                       <h5>Contact support</h5>
+                                       <p>If you don't have the above mentioned cases and still have this message, please  <a href="/contact/" target="_blank">contact us</a>.</p>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                    </div>
+                </div>
+            </div>
+</div>
+
 
        <div class="tab-pane row" id="access">
                <div class="col-md-12">
index 898a785..89716f7 100644 (file)
@@ -17,7 +17,7 @@
                                <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
                        </div>
                        <div>
-                               <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+                               <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Slice</button>
                        </div>
                        <div>
                                <p><strong>Your slices </strong>
index c8a668f..bd361de 100644 (file)
                                        <th>+/-</th>
                                        <th>Email</th>
                                        <th>User hrn</th>
+                            <!--
                                        <th>First name</th>
                                        <th>Last name</th>
                                        <th>Enabled</th>
+                            -->
                                        </tr>
                                </table>
                                
@@ -65,7 +67,7 @@
                        <th>Users</th>
                        <th>Url</th>
                        <!-- <th>nodes</th> -->
-                       <th>Expiration</th>
+                       <th>Creation</th>
                    </tr>
                </table>                        
            </div>
@@ -90,7 +92,7 @@ $(document).ready(function() {
     {% if person %}
     {% if user_details.parent_authority %}
 
-        $.post("/rest/slice/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+        $.post("/rest/slice/",{'fields':['slice_hrn','users','url','slice_date_created'],'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
             var list_slices = [];
             var table_slices = [];
             /* "slice_hrn", "slice_description", "slice_type", "parent_authority", "created", "nodes", "slice_url", "slice_last_updated", "users", "slice_urn", "slice_expires" */
@@ -108,10 +110,10 @@ $(document).ready(function() {
                     users_length=val.users.length;
                 }
 
-                if(val.slice_url=="undefined" || val.slice_url==null){
+                if(val.url=="undefined" || val.url==null){
                     slice_url="";
                 }else{
-                    slice_url="<a href='"+val.slice_url+"' target='_blank'>"+val.slice_url+"</a>";
+                    slice_url="<a href='"+val.url+"' target='_blank'>"+val.url+"</a>";
                 }
                 
                 slice_row = "<tr id='"+val.slice_hrn+"'>";
@@ -120,7 +122,7 @@ $(document).ready(function() {
                 slice_row += "<td>"+users_length+"</td>";
                 slice_row += "<td>"+slice_url+"</td>";
                 //slice_row += "<td>"+nodes_length+"</td>";
-                slice_row += "<td>"+val.slice_expires+"</td>";
+                slice_row += "<td>"+val.slice_date_created+"</td>";
                 slice_row += "</tr>";
                 table_slices.push(slice_row);
                 
@@ -133,7 +135,7 @@ $(document).ready(function() {
         });
                
                
-        $.post("/rest/user/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+        $.post("/rest/user/",{'fields':['user_hrn','user_email'],'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
             var list_users = [];
             var table_users = [];
                    /* Available fields
@@ -146,9 +148,11 @@ $(document).ready(function() {
                 user_row += "<td><input type='checkbox' class='user' id='"+val.user_hrn+"'></td>";
                 user_row += "<td>"+val.user_email+"</td>";
                 user_row += "<td>"+val.user_hrn+"</td>";
+                /*
                 user_row += "<td>"+val.user_first_name+"</td>";
                 user_row += "<td>"+val.user_last_name+"</td>";
                            user_row += "<td>"+val.user_enabled+"</td>";
+                */
                 user_row += "</tr>";
                 table_users.push(user_row);
             });
index 687b7de..bc768a6 100644 (file)
@@ -4,19 +4,36 @@
                <img src="{{ STATIC_URL|add:'img/institutions/'|add:authority.authority_hrn|add:'.gif'|file_exists }}" alt="{{authority.name}}">
        </div>
        <br />
+    {% if authority.name and authority.url %}
        <h3><a href="{{authority.url}}">{{authority.name}}</a></h3>
+    {% elif authority.name %}
+       <h3>{{authority.name}}</h3>
+    {% endif %}
        <p>
+    {% if authority.address %}
                {{authority.address}} <br />
-               {{authority.postcode}} {{authority.city}} <br />
+    {% endif %}
+    {% if authority.postcode %}
+               {{authority.postcode}} 
+    {% endif %}
+    {% if authority.address %}
+        {{authority.city}} <br />
+    {% endif %}
+    {% if authority.address %}
                {{authority.country}}
+    {% endif %}
        </p>
        <br />
+
+    {% if authority.address %}
        <h4>Onelab membership</h4> 
        <p>
                {{ authority.onelab_membership }}
        </p>
+    {% endif %}
 </div>
 <div class="col-md-6">
+    {% if authority.legal %}
        <h4>Legal Contact:</h4>
        <p>
        {% for c in authority_contacts.legal %}
@@ -24,6 +41,8 @@
        {% endfor %}
        </p>
        <br />
+    {% endif %}
+    {% if authority.scientific %}
        <h4>Scientific Contact:</h4>
        <p>
        {% for c in authority_contacts.scientific %}
        {% endfor %}
        </p>
        <br />
+    {% endif %}
+    {% if authority.technical %}
        <h4>Technical Contact:</h4>
        <p>
        {% for c in authority_contacts.technical %}
                {{ c }} <br />
        {% endfor %}
        </p>
+    {% endif %}
 </div>
 <script>$(document).ready(function() {
 {% if authority.name %}
index 87b8e8e..e255779 100644 (file)
                <td>{{ request.id }}</td>
                <td>
         {% if request.type == 'user' %}
-        Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+            <b>{{request.first_name}} {{request.last_name}}</b> <a href="mailto:{{request.email}}">{{request.email}}</a>
         {% else %}
             {% if request.type == 'slice' %}
-        Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+            <b>{{request.slice_name}}</b> -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
             {% else %} {# authority #}
-        Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+            <b>{{request.site_name}}</b> ({{request.site_authority}}) -- {{request.address_city}}, {{request.address_country}}
             {% endif %}
         {% endif %}
                </td>
index 18314d3..fddf6ab 100644 (file)
        </div>
 </div>
 {% endif %}
+                               <form action="/register" class="cmxform form-horizontal" method="post" enctype="multipart/form-data">
 <div class="row">
        <div class="col-md-12">
                        <div class="form-group">
-                               <form action="/register" class="cmxform form-horizontal" method="post" enctype="multipart/form-data">
-
                                {% csrf_token %}
                                <label for="authority_hrn" class="control-label">Organization</label>
                                <p></p>
@@ -84,7 +83,7 @@
                <br />
                        <div class="alert alert-danger" id="pkey_del_msg">
                                In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to 
-                               <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">delegate your public key to the portal.</a>
+                               <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">delegate your credentials to the portal.</a>
                        </div>
            </div>
        </div>
index aadcda9..211f35d 100644 (file)
                                <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment purpose" style="width:300px" 
                                title="Purpose of your experiment (informative)" required="required">{{ purpose }}</textarea>
                          </div>
-                         <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+                         {%if 'is_pi'  in pi %}        
+                         <button type="submit" id=submit_pi class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+                         {%else%}
+                         <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+                         {%endif%}     
                        </form>
        
                </div>
@@ -94,6 +98,10 @@ jQuery(document).ready(function(){
       minLength: 0,
       select: function( event, ui ) {console.log(jQuery(this));}
     });
+
+       $("#submit_pi").click(function() {
+               localStorage.clear();
+       });
 });
 </script>
 {% endblock %}
index 4786a5c..de11037 100644 (file)
@@ -1,4 +1,4 @@
-<img src="https://onelab.eu/templates/onelab2/images/logo.png">
+<img src="{{ STATIC_URL }}img/onelab.png">     
 <br>
 <h1>NEW USER REQUEST</h1>
 <br>
index f3293ad..9419d13 100644 (file)
@@ -1,10 +1,10 @@
-{% extends "layout-unfold1.html" %}
+{% extends "layout.html" %}
 
-{% block unfold_main %}
+{% block content %}
 
-  <h1>Slice created !</h1>
+  <h1>Slice created</h1>
 
-As you are a PI of the site, you slice has directly been created.
+As you are a manager of your institution, your slice has directly been created.
 
 {% endblock %}
 
diff --git a/portal/templates/slice_request_denied.html b/portal/templates/slice_request_denied.html
new file mode 100644 (file)
index 0000000..2405490
--- /dev/null
@@ -0,0 +1,19 @@
+<img src="{{ STATIC_URL }}img/onelab.png">
+<br>
+<p>Dear OneLab user,</p>
+<p></p>
+<p>You have recently requested the following slice in the OneLab portal({{portal_url}}):</p> 
+<br>
+<b>Slice name   :</b> {{slice_name}}<br>
+<b>URL          :</b> {{url}}<br>
+<b>Purpose      :</b> {{purpose}}<br>
+<br>
+<p>We regret to inform you that, a manager of your institution has rejected your request. Please contact the manager of your institution for further information. For any other queries, contact us by replying to this email.</p>
+<br>
+<p>On behalf of the entire team, I wish you a fruitful user experience on OneLab.</p>
+<br>
+<p>Yours sincerely,</p>
+<br>
+<p>Timur Friedman</p>
+<p>Executive Director</p>
+
diff --git a/portal/templates/slice_request_denied.txt b/portal/templates/slice_request_denied.txt
new file mode 100644 (file)
index 0000000..7dcbee3
--- /dev/null
@@ -0,0 +1,17 @@
+Dear OneLab user,
+
+You have recently requested the following slice in the OneLab portal({{portal_url}}):
+
+Slice name   : {{slice_name}}
+URL          : {{url}}
+Purpose      : {{purpose}}
+We regret to inform you that, a manager of your institution has rejected your request. Please contact the manager of your institution for further information. For any other queries, contact us by replying to this email.
+
+On behalf of the entire team, I wish you a fruitful user experience on OneLab..
+
+Yours sincerely,
+
+Timur Friedman
+Executive Director
+
index 2c4da62..3f5f68f 100644 (file)
@@ -1,11 +1,23 @@
-<img src="https://onelab.eu/templates/onelab2/images/logo.png">
+<img src="{{ STATIC_URL }}img/onelab.png">
 <br>
 <h1>NEW SLICE REQUEST</h1>
 <br>
+<p>You are receiving this request because we have you listed as a manager at an organization that uses OneLab.</p>
+<p>A user from your organization has requested the creation of a new slice, which will allow him or her to reserve testbed resources to conduct an experiment.</p>
+<br>
 <b>Slice name      :</b> {{slice_name}}</br>
 <b>URL                            :</b> {{url}}</br>
 <b>Purpose         :</b> {{purpose}}</br>
 <b>Organization           :</b> {{organization}}</br>
 <b>Email           :</b> {{email}}</br>
 <b>Portal url     :</b> {{current_site}}</br> 
+<p></p>
+<p>You can see new slice request <a href="http://{{current_site}}/portal/validate">in the portal.</a><p>
+<p>Please be sure that you know the user who is requesting this slice, as you are responsible for his or her actions, as described in the 
+<a href="http://{{current_site}}/terms">OneLab terms and conditions.</a></p>
+<p>And kindly ensure that the stated experiment purpose is clear, and, if there is a website that explains the website, that a URL is provided.</p>
+<p>OneLab and its affiliated testbeds exist purely to support useful and interesting work. To ensure the future of these environments, we need to know what work is actually being done.</p>
+<p></p>
+<p>If you believe that you have received this message in error, or if you have any questions, kindly contact support@onelab.eu.</p>
+
 
index dfe4f12..997e752 100644 (file)
@@ -1,5 +1,8 @@
 NEW SLICE REQUEST
 
+You are receiving this request because we have you listed as a manager at an organization that uses OneLab.
+A user from your organization has requested the creation of a new slice, which will allow him or her to reserve testbed resources to conduct an experiment.
+
 Slice name      : {{slice_name}}
 URL                    : {{url}}
 Purpose         : {{purpose}}
@@ -7,3 +10,12 @@ Email           : {{email}}
 Organization   : {{organization}}
 Portal url             : {{current_site}}
 
+You can see new slice request in: http://{{current_site}}/portal/validate
+Please be sure that you know the user who is requesting this slice, as you are responsible for his or her actions, as described in the OneLab terms and conditions:
+       http://{{current_site}}/terms
+And kindly ensure that the stated experiment purpose is clear, and, if there is a website that explains the website, that a URL is provided. 
+OneLab and its affiliated testbeds exist purely to support useful and interesting work. To ensure the future of these environments, we need to know what work is actually being done. 
+
+If you believe that you have received this message in error, or if you have any questions, kindly contact support@onelab.eu.
+
diff --git a/portal/templates/slice_request_validated.html b/portal/templates/slice_request_validated.html
new file mode 100644 (file)
index 0000000..9c18227
--- /dev/null
@@ -0,0 +1,20 @@
+<img src="{{ STATIC_URL }}img/onelab.png">
+<br>
+<p>Dear OneLab user,</p>
+<p></p>
+<p>You have recently requested a slice in the OneLab portal.</p>
+<br>
+<b>Slice name   :</b> {{slice_name}}<br>
+<b>URL          :</b> {{number_of_nodes}}<br>
+<b>Purpose      :</b> {{purpose}}<br>
+<p></p>
+<p>We are glad to inform you that, a manager of your institution has validated your slice request. You can now add resources to the slice and start experimenting.</p>
+<p></p>
+<p>On behalf of the entire team, I wish you a fruitful user experience on OneLab.</p>
+<p></p>
+<p>Yours sincerely,</p>
+
+<p>Timur Friedman</p>
+<p>Executive Director</p>
+
+
diff --git a/portal/templates/slice_request_validated.txt b/portal/templates/slice_request_validated.txt
new file mode 100644 (file)
index 0000000..f0cd3c5
--- /dev/null
@@ -0,0 +1,18 @@
+Dear OneLab user,
+
+You have recently requested a slice in the OneLab portal.
+
+Slice name      : {{slice_name}}
+URL             : {{number_of_nodes}}
+Purpose         : {{purpose}}
+
+We are glad to inform you that, a manager of your institution has validated your slice request. You can now add resources to the slice and start experimenting.
+
+On behalf of the entire team, I wish you a fruitful user experience on OneLab.
+
+Yours sincerely,
+
+Timur Friedman
+Executive Director
+
+
diff --git a/portal/templates/user_request_denied.html b/portal/templates/user_request_denied.html
new file mode 100644 (file)
index 0000000..9b954f7
--- /dev/null
@@ -0,0 +1,13 @@
+<img src="{{ STATIC_URL }}img/onelab.png">
+<br>
+<p>Dear {{first_name}} {{last_name}},</p>
+<p></p>
+<p>You have recently registered as a user to OneLab portal. We are sorry to inform you that, a manager of your institution has rejected your request. Please contact the manager of your institution for further information. For any other queries, contact us by replying to this email.</p>
+<p></p>
+<p>On behalf of the entire team, I wish you all the best.</p>
+<p></p>
+<p>Yours sincerely,</p>
+<p></p>
+<p>Timur Friedman</p>
+<p>Executive Director</p>
+
diff --git a/portal/templates/user_request_denied.txt b/portal/templates/user_request_denied.txt
new file mode 100644 (file)
index 0000000..9f931a2
--- /dev/null
@@ -0,0 +1,11 @@
+Dear {{first_name}} {{last_name}},
+
+You have recently registered as a user to OneLab portal. We are sorry to inform you that, a manager of your institution has rejected your request. Please contact the manager of your institution for further information. For any other queries, contact us by replying to this email.
+
+On behalf of the entire team, I wish you all the best.
+
+Yours sincerely,
+
+Timur Friedman
+Executive Director
+
diff --git a/portal/templates/user_request_validated.html b/portal/templates/user_request_validated.html
new file mode 100644 (file)
index 0000000..be97941
--- /dev/null
@@ -0,0 +1,16 @@
+<img src="{{ STATIC_URL }}img/onelab.png">
+<br>
+<p>Dear {{first_name}} {{last_name}},</p>
+<p></p>
+<p>It is my pleasure to welcome you as a fully signed up user of the OneLab experimental facility. OneLab provides you with access to world class computer networking testbeds, such as IoT-LAB, NITOS, and PlanetLab Europe. Our aim at OneLab is to promote the use of these testbeds for pre-commercial research and development by industry, for scientific research, and for university level laboratory exercises.</p>
+<p></p>
+</p>
+Your entry point for access to the testbeds is the OneLab portal, which provides a web-based interface for browsing and reserving resources on the various testbeds. To run an experiment using those resources, you may log in to the testbed and/or individual nodes on the testbed with your OneLab public/private key pair, or use an experiment control tool such as as NEPI or OMF. The OneLab operations team is standing by at support@onelab.eu to provide you with help regarding the portal and to refer your testbed- and tool-specific queries to those best able to answer them.
+</p>
+<p></p>
+</p>On behalf of the entire team, I wish you a fruitful user experience on OneLab.</p>
+<p></p>
+<p>Yours sincerely,</p>
+<p></p>
+<p>Timur Friedman</p>
+<p>Executive Director</p>
diff --git a/portal/templates/user_request_validated.txt b/portal/templates/user_request_validated.txt
new file mode 100644 (file)
index 0000000..a9f956a
--- /dev/null
@@ -0,0 +1,12 @@
+Dear {{first_name}} {{last_name}},
+
+It is my pleasure to welcome you as a fully signed up user of the OneLab experimental facility. OneLab provides you with access to world class computer networking testbeds, such as IoT-LAB, NITOS, and PlanetLab Europe. Our aim at OneLab is to promote the use of these testbeds for pre-commercial research and development by industry, for scientific research, and for university level laboratory exercises.
+
+Your entry point for access to the testbeds is the OneLab portal, which provides a web-based interface for browsing and reserving resources on the various testbeds. To run an experiment using those resources, you may log in to the testbed and/or individual nodes on the testbed with your OneLab public/private key pair, or use an experiment control tool such as as NEPI or OMF. The OneLab operations team is standing by at support@onelab.eu to provide you with help regarding the portal and to refer your testbed- and tool-specific queries to those best able to answer them.
+
+On behalf of the entire team, I wish you a fruitful user experience on OneLab.
+
+Yours sincerely,
+
+Timur Friedman
+Executive Director
index e6e63e6..8bcdaf2 100644 (file)
@@ -99,7 +99,7 @@ urlpatterns = patterns('',
     # http://stackoverflow.com/questions/2360179/django-urls-how-to-pass-a-list-of-items-via-clean-urls
     # (r'^validate_action/(?P<constraints>[^/]+)/(?P<id>\w+)/?$', 'portal.views.pres_view_static'),
     url(r'^validate_action(?P<id>(?:/\w+)+)/?$', 'portal.actions.validate_action'),
-
+    url(r'^reject_action(?P<id>(?:/\w+)+)/?$', 'portal.actions.reject_action'),
     url(r'^pres_view/?$', PresViewView.as_view(), name='pres_view'),
     (r'^methods/(?P<type>\w+)/?$', 'portal.views.pres_view_methods'),
     (r'^animation/(?P<constraints>[^/]+)/(?P<id>\w+)/?$', 'portal.views.pres_view_animation'),