improved request validation
authorJordan Augé <jordan.auge@lip6.fr>
Wed, 28 Aug 2013 08:41:36 +0000 (10:41 +0200)
committerJordan Augé <jordan.auge@lip6.fr>
Wed, 28 Aug 2013 08:41:36 +0000 (10:41 +0200)
manifold/manifoldapi.py
portal/actions.py [new file with mode: 0644]
portal/forms.py
portal/migrations/0003_extend_slice.py [new file with mode: 0644]
portal/models.py
portal/static/css/validate_pending.css
portal/templates/slice_request_email.txt [new file with mode: 0644]
portal/templates/user_request_email.txt [new file with mode: 0644]
portal/templates/validate_pending.html
portal/urls.py
portal/views.py

index 81a2caf..e7d6a1b 100644 (file)
@@ -74,5 +74,10 @@ def execute_query(request, query):
     print "-"*80
     result = manifold_api.forward(query.to_dict())
     if result['code'] == 2:
     print "-"*80
     result = manifold_api.forward(query.to_dict())
     if result['code'] == 2:
-        raise Exception, 'Error running query'
+        raise Exception, 'Error running query: %r' % result
+
+    # XXX Handle errors
+    #Error running query: {'origin': [0, 'XMLRPCAPI'], 'code': 2, 'description': 'No such session: No row was found for one()', 'traceback': 'Traceback (most recent call last):\n  File "/usr/local/lib/python2.7/dist-packages/manifold/core/xmlrpc_api.py", line 68, in xmlrpc_forward\n    user = Auth(auth).check()\n  File "/usr/local/lib/python2.7/dist-packages/manifold/auth/__init__.py", line 245, in check\n    return self.auth_method.check()\n  File "/usr/local/lib/python2.7/dist-packages/manifold/auth/__init__.py", line 95, in check\n    raise AuthenticationFailure, "No such session: %s" % e\nAuthenticationFailure: No such session: No row was found for one()\n', 'type': 2, 'ts': None, 'value': None}
+
+
     return result['value'] 
     return result['value'] 
diff --git a/portal/actions.py b/portal/actions.py
new file mode 100644 (file)
index 0000000..16ddaa1
--- /dev/null
@@ -0,0 +1,180 @@
+from django.http                 import HttpResponse
+from manifold.core.query         import Query
+from manifold.manifoldapi        import execute_query
+from portal.models               import PendingUser, PendingSlice
+import json
+
+# Get the list of authorities
+
+def authority_get_pis(authority_hrn):
+    query = Query.get('authority').filter_by('authority_hrn', '==', authority_hrn).select('pi_users')
+    results = execute_query(query)
+    if not results:
+        raise Exception, "Authority not found: %s" % authority_hrn
+    result, = results
+    return result['pi_users']
+
+def authority_get_pi_emails(authority_hrn):
+    user_hrns = authority_get_pis(authority_hrn)
+    
+    query = Query.get('user').filter_by('user_hrn', 'included', user_hrns).select('user_email')
+    results = execute_query(query)
+    
+    return [result['user_email'] for result in results]
+
+# SFA add record (user, slice)
+
+def sfa_add_user(user_params):
+    # sfi.py add --xrn=fed4fire.upmc.timur_friedman --type=user --key=/root/.sfi/timur.pub --email=timur.friedman@lip6.fr --extra=first_name=Timur --extra=last_name=Friedman --extra=enabled=true
+    # user_params: xrn type key email + first_name last_name enabled
+    query = Query.create('user').set(user_params).select('user_hrn')
+    results = execute_query(query)
+    if not results:
+        raise Exception, "Failed creating SFA user: %s" % user_params['user_hrn']
+    result, = results
+    return result['user_hrn']
+
+def sfa_add_slice(slice_params):
+    pass
+
+# Propose hrn
+
+def manifold_add_user(user_params):
+    # user_params: email, password
+    query = Query.create('local:user').set(user_params).select('email')
+    results = execute_query(query)
+    if not results:
+        raise Exception, "Failed creating manifold user: %s" % user_params['email']
+    result, = results
+    return result['email']
+
+def manifold_add_account(account_params):
+    query = Query.create('local:account').set(account_params).select(['user', 'platform'])
+    results = execute_query(query)
+    if not results:
+        raise Exception, "Failed creating manifold account on platform %s for user: %s" % (account_params['platform'], account_params['user'])
+    result, = results
+    return (result['user'], result['platform'])
+
+def make_request_user(user):
+    request = {}
+    request['type'] = 'user'
+    request['id'] = user.id
+    request['timestamp'] = 'TODO' # XXX in DB ?
+    request['authority_hrn'] = user.authority_hrn
+    request['first_name'] = user.first_name
+    request['last_name'] = user.last_name
+    request['email'] = user.email
+    return request
+
+def make_request_slice(slice):
+    request = {}
+    request['type'] = 'slice'
+    request['id'] = slice.id
+    request['timestamp'] = 'TODO' # XXX in DB ?
+    request['authority_hrn'] = slice.authority_hrn
+    request['number_of_nodes'] = slice.number_of_nodes
+    request['type_of_nodes'] = slice.type_of_nodes
+    request['purpose'] = slice.purpose
+    return request
+
+def make_requests(pending_users, pending_slices):
+    print "pending users =", pending_users
+    print "pending slices =", pending_slices
+
+    requests = []
+    for user in pending_users:
+        requests.append(make_request_user(user))
+    for slice in pending_slices:
+        requests.append(make_request_slice(slice))
+    return requests   
+
+def get_request_by_id(ids):
+    sorted_ids = { 'user': [], 'slice': [] }
+    for type__id in ids:
+        type, id = type__id.split('__')
+        sorted_ids[type].append(id)
+        
+    if not ids:
+        pending_users  = PendingUser.objects.all()
+        pending_slices = PendingSlice.objects.all()
+    else:
+        pending_users  = PendingUser.objects.filter(id__in=sorted_ids['user']).all()
+        pending_slices = PendingSlice.objects.filter(id__in=sorted_ids['slice']).all()
+
+    return make_requests(pending_users, pending_slices)
+
+def get_request_by_authority(authority_hrns):
+    if not authority_hrns:
+        pending_users  = PendingUser.objects.all()
+        pending_slices = PendingSlice.objects.all()
+    else:
+        pending_users  = PendingUser.objects.filter(authority_hrn__in=authority_hrns).all()
+        pending_slices = PendingSlice.objects.filter(authority_hrn__in=authority_hrns).all()
+
+    return make_requests(pending_users, pending_slices)
+    
+SFA_USER_KEYS         = ['xrn', 'type', 'key', 'first_name', 'last_name', 'email']
+SFA_SLICE_KEYS        = []
+MANIFOLD_USER_KEYS    = ['email', 'password']
+MANIFOLD_ACCOUNT_KEYS = []
+
+def portal_validate_request(request_ids):
+    status = {}
+
+    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:
+                sfa_user_params = { key: request[key] for key in SFA_USER_KEYS }
+                sfa_user_params['enabled'] = True
+                # XXX # sfa_add_user(sfa_user_params)
+                request_status['SFA user'] = {'status': True }
+            except Exception, e:
+                request_status['SFA user'] = {'status': False, 'description': str(e)}
+
+            try:
+                manifold_user_params = { key: request[key] for key in MANIFOLD_USER_KEYS }
+                # XXX # manifold_add_user(manifold_user_params)
+                request_status['MySlice user'] = {'status': True }
+            except Exception, e:
+                request_status['MySlice user'] = {'status': False, 'description': str(e)}
+
+            # XXX
+            #manifold_account_params = { key: request[key] for key in MANIFOLD_ACCOUNT_KEYS }
+            #manifold_add_account(manifold_account_params)
+            request_status['MySlice testbed accounts'] = {'status': False }
+
+        elif request['type'] == 'slice':
+            try:
+                sfa_slice_params = { key: request[key] for key in SFA_SLICE_KEYS }
+                # XXX # sfa_add_slice(sfa_slice_params)
+                request_status['SFA slice'] = {'status': True }
+            except Exception, e:
+                request_status['SFA slice'] = {'status': False, 'description': str(e)}
+
+        status['%s__%s' % (request['type'], request['id'])] = request_status
+
+    # XXX remove from database succeeded actions
+
+    return status
+
+
+def validate_action(*args, **kwargs):
+    ids = filter(None, kwargs['id'].split('/'))
+    status = portal_validate_request(ids)
+    json_answer = json.dumps(status)
+    return HttpResponse (json_answer, mimetype="application/json")
+
+# Django and ajax
+# http://djangosnippets.org/snippets/942/
index 46a60bd..7abc0e4 100644 (file)
@@ -105,12 +105,12 @@ from django.utils.translation import ugettext_lazy as _
 # DEPRECATED # 
 # DEPRECATED #    class Meta:
 # DEPRECATED #        model = PendingUser
 # DEPRECATED # 
 # DEPRECATED #    class Meta:
 # DEPRECATED #        model = PendingUser
-
-class SliceRequestForm(forms.ModelForm):
-    slice_name = forms.CharField( widget=forms.TextInput )
-    class Meta:
-        model = PendingSlice
-
+# DEPRECATED #
+# DEPRECATED #class SliceRequestForm(forms.ModelForm):
+# DEPRECATED #    slice_name = forms.CharField( widget=forms.TextInput )
+# DEPRECATED #    class Meta:
+# DEPRECATED #        model = PendingSlice
+# DEPRECATED #
 # DEPRECATED #class RegisterUserStep2Form(forms.ModelForm):
 # DEPRECATED #    class Meta:
 # DEPRECATED #        model = PendingUser
 # DEPRECATED #class RegisterUserStep2Form(forms.ModelForm):
 # DEPRECATED #    class Meta:
 # DEPRECATED #        model = PendingUser
@@ -126,10 +126,29 @@ class ContactForm(forms.Form):
 
 class SliceRequestForm(forms.Form):
     slice_name = forms.CharField()
 
 class SliceRequestForm(forms.Form):
     slice_name = forms.CharField()
+    authority_hrn = forms.ChoiceField(choices=[(1, 'un')])
     number_of_nodes  = forms.DecimalField()
     type_of_nodes = forms.CharField()
     purpose = forms.CharField(widget=forms.Textarea)
     email = forms.EmailField()
     cc_myself = forms.BooleanField(required=False)
 
     number_of_nodes  = forms.DecimalField()
     type_of_nodes = forms.CharField()
     purpose = forms.CharField(widget=forms.Textarea)
     email = forms.EmailField()
     cc_myself = forms.BooleanField(required=False)
 
+    def __init__(self, *args, **kwargs):
+        initial =  kwargs.get('initial', {})
+        authority_hrn = initial.get('authority_hrn', None)
+
+        # set just the initial value
+        # in the real form needs something like this {'authority_hrn':'a'}
+        # but in this case you want {'authority_hrn':('a', 'letter_a')}
+        if authority_hrn:
+            kwargs['initial']['authority_hrn'] = authority_hrn[0]
+
+        # create the form
+        super(SliceRequestForm, self).__init__(*args, **kwargs)
+
+        # self.fields only exist after, so a double validation is needed
+        if authority_hrn:# and authority_hrn[0] not in (c[0] for c in authority_hrn):
+            # XXX This does not work, the choicefield is not updated...
+            #self.fields['authority_hrn'].choices.extend(authority_hrn)
+            self.fields['authority_hrn'] = forms.ChoiceField( choices=authority_hrn)
     
     
diff --git a/portal/migrations/0003_extend_slice.py b/portal/migrations/0003_extend_slice.py
new file mode 100644 (file)
index 0000000..2437098
--- /dev/null
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'PendingSlice.number_of_nodes'
+        db.add_column(u'portal_pendingslice', 'number_of_nodes',
+                      self.gf('django.db.models.fields.TextField')(default=0),
+                      keep_default=False)
+
+        # Adding field 'PendingSlice.type_of_nodes'
+        db.add_column(u'portal_pendingslice', 'type_of_nodes',
+                      self.gf('django.db.models.fields.TextField')(default='NA'),
+                      keep_default=False)
+
+        # Adding field 'PendingSlice.purpose'
+        db.add_column(u'portal_pendingslice', 'purpose',
+                      self.gf('django.db.models.fields.TextField')(default='NA'),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'PendingSlice.number_of_nodes'
+        db.delete_column(u'portal_pendingslice', 'number_of_nodes')
+
+        # Deleting field 'PendingSlice.type_of_nodes'
+        db.delete_column(u'portal_pendingslice', 'type_of_nodes')
+
+        # Deleting field 'PendingSlice.purpose'
+        db.delete_column(u'portal_pendingslice', 'purpose')
+
+
+    models = {
+        u'portal.institution': {
+            'Meta': {'object_name': 'Institution'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.TextField', [], {})
+        },
+        u'portal.pendingslice': {
+            'Meta': {'object_name': 'PendingSlice'},
+            'authority_hrn': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'number_of_nodes': ('django.db.models.fields.TextField', [], {'default': '0'}),
+            'purpose': ('django.db.models.fields.TextField', [], {'default': "'NA'"}),
+            'slice_name': ('django.db.models.fields.TextField', [], {}),
+            'type_of_nodes': ('django.db.models.fields.TextField', [], {'default': "'NA'"})
+        },
+        u'portal.pendinguser': {
+            'Meta': {'object_name': 'PendingUser'},
+            'affiliation': ('django.db.models.fields.TextField', [], {}),
+            'authority_hrn': ('django.db.models.fields.TextField', [], {}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'first_name': ('django.db.models.fields.TextField', [], {}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'keypair': ('django.db.models.fields.TextField', [], {}),
+            'last_name': ('django.db.models.fields.TextField', [], {}),
+            'password': ('django.db.models.fields.TextField', [], {})
+        }
+    }
+
+    complete_apps = ['portal']
\ No newline at end of file
index a16e330..9a414ba 100644 (file)
@@ -309,5 +309,8 @@ class PendingUser(models.Model):
 
 
 class PendingSlice(models.Model):
 
 
 class PendingSlice(models.Model):
-    slice_name  = models.TextField()
-    authority_hrn = models.TextField(null=True)
+    slice_name      = models.TextField()
+    authority_hrn   = models.TextField(null=True)
+    number_of_nodes = models.TextField(default=0)
+    type_of_nodes   = models.TextField(default='NA')
+    purpose         = models.TextField(default='NA')
index 4ed27e1..d0a7a56 100644 (file)
@@ -5,7 +5,7 @@
        position:relative;
 }
 
        position:relative;
 }
 
-.portal_validate_request .slice {
+.portal_validate_request.slice {
        background-image: url(../img/slice-icon.png);
 }
 
        background-image: url(../img/slice-icon.png);
 }
 
@@ -13,7 +13,7 @@
        background-image: url(../img/user-icon.png);
 }
 
        background-image: url(../img/user-icon.png);
 }
 
-.portal_validate_request .authority {
+.portal_validate_request.authority {
        background-image: url(../img/authority-icon.png);
 }
 
        background-image: url(../img/authority-icon.png);
 }
 
 }
 
 .portal_validate_request .id {
 }
 
 .portal_validate_request .id {
-       position: relative;
+       position: absolute;
        left: 5%;
 }
        left: 5%;
 }
-.portal_validate_request .timestamp {
-       position: relative;
-       left: 10%;
+
+.portal_validate_request .authority {
+       position: absolute;
+       left: 7%;
 }
 }
+
 .portal_validate_request .details {
 .portal_validate_request .details {
-       position: relative;
-       left: 20%;
+       position: absolute;
+       left: 15%;
+}
+
+.portal_validate_request .timestamp {
+       position: absolute;
+       left: 50%;
+}
+
+.portal_validate_request .status {
+       position: absolute;
+       left: 65%;
 }
 
 .portal_validate_request input {
 }
 
 .portal_validate_request input {
-       position: relative;
-       left: 40%;
+       position: absolute;
+       left: 60%;
 }
 
 .portal_validate_request.even {
 }
 
 .portal_validate_request.even {
diff --git a/portal/templates/slice_request_email.txt b/portal/templates/slice_request_email.txt
new file mode 100644 (file)
index 0000000..ef46a04
--- /dev/null
@@ -0,0 +1,9 @@
+NEW SLICE REQUEST
+
+slice name      : {{slice_name}}
+number of nodes : {{number_of_nodes}}
+type of nodes   : {{type_of_nodes}}
+purpose         : {{purpose}}
+email           : {{email}}
+cc myself       : {{cc_myself}}
+
diff --git a/portal/templates/user_request_email.txt b/portal/templates/user_request_email.txt
new file mode 100644 (file)
index 0000000..3e18d0e
--- /dev/null
@@ -0,0 +1,9 @@
+NEW USER REQUEST
+
+first_name   : {{first_name}}
+last_name    : {{last_name}} 
+authority_hrn: {{authority_hrn}}
+keypair      : {{keypair}}
+email        : {{email}}
+cc myself    : {{cc_myself}}
+
index dd7d5c2..74176ea 100644 (file)
@@ -2,6 +2,47 @@
 
 {% block head %}
 <link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/validate_pending.css" />
 
 {% block head %}
 <link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/validate_pending.css" />
+<script type="text/javascript">
+       function on_click_event() {
+               var ids = []; 
+               $('.portal__validate__checkbox').each(function(i, el) {
+                       if ($(el).attr('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/validate_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">' + name + '</font>';
+                                                               $('#portal__validate__checkbox__' + request_type__id).hide();
+                                                       } else {
+                                                               status_str += '<font color="red">' + name + ' (' + result.description + ')</font>';
+                                                       }
+                                               });
+                                               $('#portal__status__' + request_type__id).html(status_str)
+
+
+                                       });
+                               }
+                       );
+               }
+       }
+</script>
 {% endblock %}
 
 {% block unfold1_main %}
 {% endblock %}
 
 {% block unfold1_main %}
                <span class='type'>{{ request.type }}</span>
                <span class='id'>{{ request.id }}</span>
                <span class='timestamp'>{{ request.timestamp }}</span>
                <span class='type'>{{ request.type }}</span>
                <span class='id'>{{ request.id }}</span>
                <span class='timestamp'>{{ request.timestamp }}</span>
-               <span class='details'>{{ request.details }}</span>
+               <span class='authority'>{{ request.authority_hrn }}</span>
+        
+        {% if request.type == 'user' %}
+        <span class='details'>First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}</span>
+        {% else %}
+            {% if request.type == 'slice' %}
+        <span class='details'>Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}</span>
+            {% else %} {# authority #}
+        <span class='details'>TODO</span>
+            {% endif %}
+        {% endif %}
+
                {% if request.allowed == 'allowed' %}
                {% if request.allowed == 'allowed' %}
-               <input type='checkbox'/>
+               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
                {% else %}
                        {% if request.allowed == 'expired' %}
                                expired
                {% else %}
                        {% if request.allowed == 'expired' %}
                                expired
@@ -29,6 +81,7 @@
                                denied
                        {% endif %}
                {% endif %}
                                denied
                        {% endif %}
                {% endif %}
+               <span class='status' id='portal__status__{{request.type}}__{{request.id}}'></span>
        </div>
     {% endfor %}
 {% endfor %}
        </div>
     {% endfor %}
 {% endfor %}
                <span class='timestamp'>{{ request.timestamp }}</span>
                <span class='details'>{{ request.details }}</span>
                {% if request.allowed == 'allowed' %}
                <span class='timestamp'>{{ request.timestamp }}</span>
                <span class='details'>{{ request.details }}</span>
                {% if request.allowed == 'allowed' %}
-               <input type='checkbox'/>
+               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
                {% else %}
                        {% if request.allowed == 'expired' %}
                                expired
                {% else %}
                        {% if request.allowed == 'expired' %}
                                expired
                                denied
                        {% endif %}
                {% endif %}
                                denied
                        {% endif %}
                {% endif %}
+               <span class='status' id='portal__status__{{request.type}}__{{request.id}}'></span>
        </div>
     {% endfor %}
 {% endfor %}
 
 {% endif %}
 
        </div>
     {% endfor %}
 {% endfor %}
 
 {% endif %}
 
+<input type='button' id='portal__validate' value='Validate' onclick='on_click_event();'/>
+
 {% endblock %}
 {% endblock %}
index 2887388..31c8908 100644 (file)
@@ -55,6 +55,9 @@ urlpatterns = patterns('',
     url(r'^slice_request/?$', views.slice_request),
     # Validate pending requests
     url(r'^validate/?$', ValidatePendingView.as_view()),
     url(r'^slice_request/?$', views.slice_request),
     # Validate pending requests
     url(r'^validate/?$', ValidatePendingView.as_view()),
+    # 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'),
+     (r'^validate_action(?P<id>(?:/\w+)+)/?$', 'portal.actions.validate_action'),
 
     url(r'^pres_view/?$', PresViewView.as_view(), name='pres_view'),
     (r'^methods/(?P<type>\w+)/?$', 'portal.views.pres_view_methods'),
 
     url(r'^pres_view/?$', PresViewView.as_view(), name='pres_view'),
     (r'^methods/(?P<type>\w+)/?$', 'portal.views.pres_view_methods'),
index ac4e7b8..87f6cb6 100644 (file)
@@ -27,6 +27,8 @@ from django.contrib              import messages
 from django.views.generic        import View
 from django.views.generic.base   import TemplateView
 from django.shortcuts            import render
 from django.views.generic        import View
 from django.views.generic.base   import TemplateView
 from django.shortcuts            import render
+from django.template.loader      import render_to_string
+from django.core.mail            import send_mail
 
 from plugins.lists.simplelist    import SimpleList
 from plugins.hazelnut            import Hazelnut
 
 from plugins.lists.simplelist    import SimpleList
 from plugins.hazelnut            import Hazelnut
@@ -38,6 +40,7 @@ from portal                      import signals
 from portal.forms                import SliceRequestForm, ContactForm
 from portal.util                 import RegistrationView, ActivationView
 from portal.models               import PendingUser, PendingSlice
 from portal.forms                import SliceRequestForm, ContactForm
 from portal.util                 import RegistrationView, ActivationView
 from portal.models               import PendingUser, PendingSlice
+from portal.actions              import authority_get_pi_emails, get_request_by_authority
 from manifold.core.query         import Query
 from manifold.manifoldapi        import execute_query
 from unfold.page                 import Page
 from manifold.core.query         import Query
 from manifold.manifoldapi        import execute_query
 from unfold.page                 import Page
@@ -690,6 +693,8 @@ def register_4m_f4f(request):
     authorities = execute_query(request, authorities_query)
 
     if request.method == 'POST':
     authorities = execute_query(request, authorities_query)
 
     if request.method == 'POST':
+        # We shall use a form here
+
         #get_email = PendingUser.objects.get(email)
         reg_fname = request.POST.get('firstname', '')
         reg_lname = request.POST.get('lastname', '')
         #get_email = PendingUser.objects.get(email)
         reg_fname = request.POST.get('firstname', '')
         reg_lname = request.POST.get('lastname', '')
@@ -763,10 +768,35 @@ def register_4m_f4f(request):
         #                email=reg_email, password=request.POST['password'], keypair=keypair)
         #b.save()
         if not errors:
         #                email=reg_email, password=request.POST['password'], keypair=keypair)
         #b.save()
         if not errors:
-            b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
-                            authority_hrn=reg_auth,
-                            email=reg_email, password=request.POST['password'], keypair=keypair)
+            b = PendingUser(
+                first_name=reg_fname, 
+                last_name=reg_lname, 
+                affiliation=reg_aff,
+                authority_hrn=reg_auth,
+                email=reg_email, 
+                password=request.POST['password'],
+                keypair=keypair
+            )
             b.save()
             b.save()
+
+            # Send email
+            ctx = {
+                first_name   : reg_fname, 
+                last_name    : reg_lname, 
+                affiliation  : reg_aff,
+                authority_hrn: reg_auth,
+                email        : reg_email, 
+                keypair      : keypair,
+                cc_myself    : True # form.cleaned_data['cc_myself']
+            }
+
+            recipients = authority_get_pi_emails(authority_hrn)
+            if ctx['cc_myself']:
+                recipients.append(ctx['email'])
+
+            msg = render_to_string('user_request_email.txt', ctx)
+            send_mail("Onelab New User request submitted", msg, email, recipients)
+
             return render(request, 'user_register_complete.html')
 
     return render(request, 'register_4m_f4f.html',{
             return render(request, 'user_register_complete.html')
 
     return render(request, 'register_4m_f4f.html',{
@@ -796,6 +826,7 @@ def contact(request):
             email = form.cleaned_data['email'] # email of the sender
             cc_myself = form.cleaned_data['cc_myself']
 
             email = form.cleaned_data['email'] # email of the sender
             cc_myself = form.cleaned_data['cc_myself']
 
+            #recipients = authority_get_pi_emails(authority_hrn)
             recipients = ['yasin.upmc@gmail.com']
             if cc_myself:
                 recipients.append(email)
             recipients = ['yasin.upmc@gmail.com']
             if cc_myself:
                 recipients.append(email)
@@ -815,26 +846,54 @@ def contact(request):
 
 
 def slice_request(request):
 
 
 def slice_request(request):
-    if request.method == 'POST': # If the form has been submitted...
-        form = SliceRequestForm(request.POST) # A form bound to the POST data
-        if form.is_valid(): # All validation rules pass
-            # Process the data in form.cleaned_data
-            slice_name = form.cleaned_data['slice_name']
+    errors = []
+
+    authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
+    #authorities_query = Query.get('authority').select('authority_hrn')
+    authorities = execute_query(request, authorities_query)
+
+    authority_hrn_tuple = []
+    for authority in authorities:
+        authority_hrn_tuple.append((authority['authority_hrn'], authority['name']))
+    authority_hrn_initial = {'authority_hrn': authority_hrn_tuple}
+        
+    # request.POST or None ?
+    if request.method == 'POST':
+        # The form has been submitted
+        form = SliceRequestForm(request.POST, initial=authority_hrn_initial) 
+
+        if form.is_valid():
+            slice_name      = form.cleaned_data['slice_name']
+            authority_hrn   = form.cleaned_data['authority_hrn']
             number_of_nodes = form.cleaned_data['number_of_nodes']
             number_of_nodes = form.cleaned_data['number_of_nodes']
-            type_of_nodes = form.cleaned_data['type_of_nodes']
-            purpose = form.cleaned_data['purpose']
+            type_of_nodes   = form.cleaned_data['type_of_nodes']
+            purpose         = form.cleaned_data['purpose']
+            
+            s = PendingSlice(
+                slice_name      = slice_name,
+                authority_hrn   = authority_hrn,
+                number_of_nodes = number_of_nodes,
+                type_of_nodes   = type_of_nodes,
+                purpose         = purpose
+            )
+            s.save()
+
+            # All validation rules pass; process data in form.cleaned_data
+            # slice_name, number_of_nodes, type_of_nodes, purpose
             email = form.cleaned_data['email'] # email of the sender
             cc_myself = form.cleaned_data['cc_myself']
 
             email = form.cleaned_data['email'] # email of the sender
             cc_myself = form.cleaned_data['cc_myself']
 
-            recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
+            # The recipients are the PI of the authority
+            recipients = authority_get_pi_emails(authority_hrn)
+            #recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
             if cc_myself:
                 recipients.append(email)
             if cc_myself:
                 recipients.append(email)
+            msg = render_to_string('slice_request_email.txt', form.cleaned_data)
+            send_mail("Onelab New Slice request form submitted", msg, email, recipients)
 
 
-            from django.core.mail import send_mail
-            send_mail("Onelab New Slice request form submitted", [slice_name,number_of_nodes,type_of_nodes,purpose], email, recipients)
             return render(request,'slicereq_recvd.html') # Redirect after POST
     else:
             return render(request,'slicereq_recvd.html') # Redirect after POST
     else:
-        form = SliceRequestForm() # An unbound form
+        form = SliceRequestForm(initial=authority_hrn_initial)
 
 #    template_env = {}
 #    template_env['form'] = form
 
 #    template_env = {}
 #    template_env['form'] = form
@@ -1140,26 +1199,10 @@ class ValidatePendingView(TemplateView):
             queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
             print "----"
             print "queried_pending_authorities = ", queried_pending_authorities
             queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
             print "----"
             print "queried_pending_authorities = ", queried_pending_authorities
-            
-            # Pending requests + authorities
-            #pending_users = PendingUser.objects.filter(authority_hrn__in = queried_pending_authorities).all() 
-            #pending_slices = PendingSlice.objects.filter(authority_hrn__in = queried_pending_authorities).all() 
-            pending_users = PendingUser.objects.all()
-            pending_slices = PendingSlice.objects.all()
-
-            # Dispatch requests and build the proper structure for the template:
-
-            print "pending users =", pending_users
-            print "pending slices =", pending_slices
-
-            for user in pending_users:
-                auth_hrn = user.authority_hrn
 
 
-                request = {}
-                request['type'] = 'user'
-                request['id'] = 'TODO' # XXX in DB ?
-                request['timestamp'] = 'TODO' # XXX in DB ?
-                request['details'] = "%s %s <%s>" % (user.first_name, user.last_name, user.email)
+            requests = get_request_by_authority(queried_pending_authorities)
+            for request in requests:
+                auth_hrn = request['authority_hrn']
 
                 if auth_hrn in pi_my_authorities:
                     dest = ctx_my_authorities
 
                 if auth_hrn in pi_my_authorities:
                     dest = ctx_my_authorities
@@ -1182,45 +1225,11 @@ class ValidatePendingView(TemplateView):
 
                 else:
                     continue
 
                 else:
                     continue
-                    
-                if not auth_hrn in dest:
-                    dest[auth_hrn] = []
-                print "auth_hrn [%s] was added %r" % (auth_hrn, request)
-                dest[auth_hrn].append(request) 
-
-            for slice in pending_slices:
-                auth_hrn = slice.authority_hrn
-                if not auth_hrn:
-                    auth_hrn = "ple.upmc" # XXX HARDCODED
-
-                request = {}
-                request['type'] = 'slice'
-                request['id'] = 'TODO' # XXX in DB ?
-                request['timestamp'] = 'TODO' # XXX in DB ?
-                request['details'] = "Number of nodes: %d -- Type of nodes: %s<br/>%s" % ('TODO', 'TODO', 'TODO') # XXX 
-                if auth_hrn in pi_my_authorities:
-                    dest = ctx_my_authorities
-
-                    # define the css class
-                    if auth_hrn in pi_credential_authorities:
-                        request['allowed'] = 'allowed'
-                    elif auth_hrn in pi_expired_credential_authorities:
-                        request['allowed'] = 'expired'
-                    else: # pi_no_credential_authorities
-                        request['allowed'] = 'denied'
-
-                elif auth_hrn in pi_delegation_authorities:
-                    dest = ctx_delegation_authorities
 
 
-                    if auth_hrn in pi_delegation_credential_authorities:
-                        request['allowed'] = 'allowed'
-                    else: # pi_delegation_expired_authorities
-                        request['allowed'] = 'expired'
-                    
                 if not auth_hrn in dest:
                     dest[auth_hrn] = []
                 dest[auth_hrn].append(request) 
                 if not auth_hrn in dest:
                     dest[auth_hrn] = []
                 dest[auth_hrn].append(request) 
-
+        
         context = super(ValidatePendingView, self).get_context_data(**kwargs)
         context['my_authorities']   = ctx_my_authorities
         context['delegation_authorities'] = ctx_delegation_authorities
         context = super(ValidatePendingView, self).get_context_data(**kwargs)
         context['my_authorities']   = ctx_my_authorities
         context['delegation_authorities'] = ctx_delegation_authorities