Projects: added view and template (fed4fire)
authorLoic Baron <loic.baron@lip6.fr>
Wed, 21 Jan 2015 16:15:13 +0000 (17:15 +0100)
committerLoic Baron <loic.baron@lip6.fr>
Wed, 21 Jan 2015 16:15:13 +0000 (17:15 +0100)
portal/projectrequestview.py [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_projectrequest_view.html [new file with mode: 0644]

diff --git a/portal/projectrequestview.py b/portal/projectrequestview.py
new file mode 100644 (file)
index 0000000..d2f11a6
--- /dev/null
@@ -0,0 +1,193 @@
+from django.shortcuts           import render
+from django.contrib.sites.models import Site
+
+
+from unfold.page                import Page
+
+from manifold.core.query        import Query
+from manifoldapi.manifoldapi    import execute_admin_query, execute_query
+
+from portal.actions             import is_pi, create_slice, create_pending_slice, clear_user_creds
+#from portal.forms               import SliceRequestForm
+from unfold.loginrequired       import LoginRequiredAutoLogoutView
+from ui.topmenu                 import topmenu_items_live, the_user
+
+from myslice.theme import ThemeView
+
+import json, time, re
+
+import activity.user
+
+class ProjectRequestView (LoginRequiredAutoLogoutView, ThemeView):
+    template_name = 'projectrequest_view.html'
+    
+    # because we inherit LoginRequiredAutoLogoutView that is implemented by redefining 'dispatch'
+    # we cannot redefine dispatch here, or we'd lose LoginRequired and AutoLogout behaviours
+    def post (self, request):
+        return self.get_or_post (request, 'POST')
+
+    def get (self, request):
+        return self.get_or_post (request, 'GET')
+
+    def get_or_post  (self, wsgi_request, method):
+        """
+        """
+        errors = []
+        slice_name =''
+        purpose=''
+        url=''
+        authority_hrn = None
+        authority_name = None
+        # Retrieve the list of authorities
+        authorities_query = Query.get('authority').select('name', 'authority_hrn')
+        authorities = execute_admin_query(wsgi_request, authorities_query)
+        if authorities is not None:
+            authorities = sorted(authorities, key=lambda k: k['authority_hrn'])
+            authorities = sorted(authorities, key=lambda k: k['name'])
+
+        # Get user_email (XXX Would deserve to be simplified)
+        user_query  = Query().get('local:user').select('email','config')
+        user_details = execute_query(wsgi_request, user_query)
+        user_email = user_details[0].get('email')
+        # getting user_hrn
+        for user_detail in user_details:
+            user_config = json.loads(user_detail['config'])
+            user_authority = user_config.get('authority','N/A')              
+        # getting the org from authority        
+        for authority in authorities:
+            if authority['authority_hrn'] == user_authority:
+                authority_name = authority['name']
+
+        # Handle the case when we use only hrn and not name
+        if authority_name is None:
+            authority_name = user_authority
+        #
+        account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+        account_details = execute_query(wsgi_request, account_query)
+        #
+        platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+        platform_details = execute_query(wsgi_request, platform_query)
+        user_hrn = None
+        # getting user_hrn from local:account
+        for account_detail in account_details:
+            for platform_detail in platform_details:
+                if platform_detail['platform_id'] == account_detail['platform_id']:
+                    # taking user_hrn only from myslice account
+                    # NOTE: we should later handle accounts filter_by auth_type= managed OR user
+                    if 'myslice' in platform_detail['platform']:
+                        account_config = json.loads(account_detail['config'])
+                        user_hrn = account_config.get('user_hrn','N/A')
+                        acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+
+
+        # checking if pi or not
+        if acc_auth_cred == {} or acc_auth_cred == 'N/A':
+            pi = "is_not_pi"
+        else:
+            pi = "is_pi"
+
+
+        # Page rendering
+        page = Page(wsgi_request)
+        page.add_js_files  ( [ "js/jquery.validate.js", "js/jquery-ui.js" ] )
+        page.add_css_files ( [ "https://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" ] )
+        page.expose_js_metadata()
+
+        if method == 'POST':
+            # The form has been submitted
+
+            # get the domain url
+            current_site = Site.objects.get_current()
+            current_site = current_site.domain
+            
+            # getting the authority_hrn from the selected organization
+            for authority in authorities:
+                if authority['name'] == wsgi_request.POST.get('org_name', ''):
+                    authority_hrn = authority['authority_hrn']
+
+            # Handle the case when we use only hrn and not name
+            if authority_hrn is None:
+                authority_hrn = wsgi_request.POST.get('org_name', '')
+
+            slice_request = {
+                'type'              : 'slice',
+                'id'                : None,
+                'user_hrn'          : user_hrn,
+                'email'             : user_email,
+                'timestamp'         : time.time(),
+                'authority_hrn'     : authority_hrn,
+                'organization'      : wsgi_request.POST.get('org_name', ''),
+                'slice_name'        : wsgi_request.POST.get('slice_name', ''),
+                'url'               : wsgi_request.POST.get('url', ''),
+                'purpose'           : wsgi_request.POST.get('purpose', ''),
+                'current_site'      : current_site
+            }
+            
+            # create slice_hrn based on authority_hrn and slice_name
+            slice_name = slice_request['slice_name']
+            req_slice_hrn = authority_hrn + '.' + slice_name
+            # comparing requested slice_hrn with the existing slice_hrn 
+            slice_query  = Query().get('myslice:slice').select('slice_hrn','parent_authority').filter_by('parent_authority','==',authority_hrn)
+            slice_details_sfa = execute_admin_query(wsgi_request, slice_query)
+            for _slice in slice_details_sfa:
+                if _slice['slice_hrn'] == req_slice_hrn:
+                    errors.append('Slice already exists. Please use a different slice name.')
+            
+
+            # What kind of slice name is valid?
+            if (slice_name is None or slice_name == ''):
+                errors.append('Slice name is mandatory')
+            
+            if (re.search(r'^[A-Za-z0-9_]*$', slice_name) == None):
+                errors.append('Slice name may contain only letters, numbers, and underscore.')
+            
+            organization = slice_request['organization']    
+            if (organization is None or organization == ''):
+                errors.append('Organization is mandatory')
+
+
+    
+            purpose = slice_request['purpose']
+            if (purpose is None or purpose == ''):
+                errors.append('Experiment purpose is mandatory')
+
+            url = slice_request['url']
+
+            if not errors:
+                if is_pi(wsgi_request, user_hrn, authority_hrn):
+                    # PIs can directly create slices in their own authority...
+                    create_slice(wsgi_request, slice_request)
+                    clear_user_creds(wsgi_request, user_email)
+                    self.template_name = 'slice-request-done-view.html'
+                else:
+                    # Otherwise a wsgi_request is sent to the PI
+                    create_pending_slice(wsgi_request, slice_request, user_email)
+                    self.template_name = 'slice-request-ack-view.html'
+                
+                # log user activity
+                activity.user.slice(wsgi_request)
+                
+                return render(wsgi_request, self.template, {'theme': self.theme}) # Redirect after POST
+        else:
+            slice_request = {}
+
+        template_env = {
+            'username': wsgi_request.user.email,
+            'topmenu_items': topmenu_items_live('Request a slice', page),
+            'errors': errors,
+            'slice_name': slice_name,
+            'purpose': purpose,
+            'email': user_email,
+            'user_hrn': user_hrn,
+            'url': url,
+            'pi': pi,
+            'authority_name': authority_name,        
+            'authority_hrn': user_authority,        
+            'cc_myself': True,
+            'authorities': authorities,
+            'theme': self.theme,
+            'section': "Slice request"
+        }
+        template_env.update(slice_request)
+        template_env.update(page.prelude_env())
+        return render(wsgi_request, self.template, template_env)
diff --git a/portal/templates/fed4fire/fed4fire_projectrequest_view.html b/portal/templates/fed4fire/fed4fire_projectrequest_view.html
new file mode 100644 (file)
index 0000000..962976f
--- /dev/null
@@ -0,0 +1,114 @@
+{% extends "layout.html" %}
+{% load i18n %}
+
+{% block content %}
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Experiment &nbsp;>&nbsp; Request a new Project or Join an existing one
+                        </div>
+               </div>
+       </div>
+
+       {% if errors %}
+       <div class="row">
+               <div class="col-md-12">
+               <ul class="error">
+                 {% for error in errors %}
+                 <li>{{ error }}</li>
+                 {% endfor %}
+               </ul>
+               </div>
+       </div>
+       {% endif %}
+       
+       <div class="row">
+               <div class="col-md-8 el">
+                       <form role="form" method="post">
+                       {% csrf_token %}
+                         <div class="form-group" style="display:none">
+                           <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
+                         </div>
+                         <div class="form-group">
+                               <select id="org_name" name="org_name" class="form-control" style="width:590px" value="{{ organization }}" required> 
+                {% if authorities %}
+                    {% for authority in authorities %}
+                        {% if authority.name %}
+                            <option value="{{ authority.authority_hrn }}">{{authority.name}}</option>
+                        {% else %}
+                            <option value="{{ authority.authority_hrn }}">{{authority.authority_hrn}}</option>
+                        {% endif %}
+                    {% endfor %} 
+                {% endif %}
+                </select>
+                         </div>
+                         <div class="form-group">
+                <input type="text">New Project</input>
+                         </div>
+                         <div class="form-group">
+                <input type="text">Existing Project</input>
+                         </div>
+                         <div class="form-group">
+                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Project purpose" style="width:300px" 
+                               title="Purpose of your project (informative)" required="required">{{ purpose }}</textarea>
+                         </div>
+                         {%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>
+       </div>
+               
+<script>
+jQuery(document).ready(function(){
+/*
+       
+       $("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
+               var jsonData = JSON.parse(data);
+        $(this).attr("value", jsonData[0]['parent_authority']);
+    });
+       $("#authority_hrn").val("{{authority_name}}");
+       var availableTags = [
+    {% if authorities %}
+        {% for authority in authorities %}
+            {% if authority.name %}
+                {value:"{{ authority.name }}",label:"{{authority.name}}"},
+                       // to show only full name
+            {% else %}
+                {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+            {% endif %}
+        {% endfor %}    
+    {% else %}
+        {value:"",label:"No authority found !!!"}
+    {% endif %}
+    ];
+       // sorting the list
+       availableTags.sort(function(a,b){
+               var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+               if (nameA < nameB) {
+               return -1;
+               }
+               if (nameA > nameB) {
+               return 1;
+               }
+       return 0;
+       }); 
+    $( "#authority_hrn" ).autocomplete({
+      source: availableTags,
+      minLength: 0,
+      select: function( event, ui ) {console.log(jQuery(this));}
+    });
+*/
+       $("#submit_pi").click(function() {
+               localStorage.clear();
+       });
+       // auto-complete the form
+    jQuery("#org_name").combobox();
+
+});
+</script>
+{% endblock %}
+