commit 1ae97c8361d555007891ec6e7aaf045d1249e28a
Author: Sofia Papagiannaki <papagian@gmail.com>
Date:   Sat Feb 25 21:57:54 2012 +0200

    change cloudbar to contain dynamic links

diff --git a/docs/source/devguide.rst b/docs/source/devguide.rst
index 77177cc..ec96ded 100644
--- a/docs/source/devguide.rst
+++ b/docs/source/devguide.rst
@@ -12,7 +12,7 @@ Users in astakos can be authenticated via several identity providers:
 * Twitter
 * Shibboleth
 
-It provides also an administrative interface for managing user accounts.
+It provides also a command line tool for managing user accounts.
 
 It is build over django and extends its authentication mechanism.
 
@@ -102,7 +102,7 @@ Logged on users can perform a number of actions:
 * send feedback for grnet services via: ``/im/send_feedback``
 * logout (and delete cookie) via: ``/im/logout``
 
-User entries can also be modified/added via the administrative interface available at ``/im/admin``.
+User entries can also be modified/added via the ``snf-manage activateuser`` command.
 
 A superuser account can be created the first time you run the ``manage.py syncdb`` django command and then loading the extra user data from the ``admin_user`` fixture. At a later date, the ``manage.py createsuperuser`` command line utility can be used (as long as the extra user data for Astakos is added with a fixture or by hand).
 
@@ -126,15 +126,15 @@ Finally, backend systems having acquired a token can use the :ref:`authenticate-
 The Astakos API
 ---------------
 
-All API requests require a token. An application that wishes to connect to Astakos, but does not have a token, should redirect the user to ``/login``. (see :ref:`authentication-label`)
-
 .. _authenticate-api-label:
 
 Authenticate
 ^^^^^^^^^^^^
 
+Authenticate API requests require a token. An application that wishes to connect to Astakos, but does not have a token, should redirect the user to ``/login``. (see :ref:`authentication-label`)
+
 ==================== =========  ==================
-Uri                                  Method     Description
+Uri                  Method     Description
 ==================== =========  ==================
 ``/im/authenticate`` GET        Authenticate user using token
 ==================== =========  ==================
@@ -179,3 +179,51 @@ Return Code                 Description
 401 (Unauthorized)          Missing token or inactive user
 500 (Internal Server Error) The request cannot be completed because of an internal error
 =========================== =====================
+
+Get Services
+^^^^^^^^^^^^
+
+Returns a json formatted list containing information about the supported cloud services.
+
+==================== =========  ==================
+Uri                  Method     Description
+==================== =========  ==================
+``/im/get_services`` GET        Get cloud services
+==================== =========  ==================
+
+Example reply:
+
+::
+
+[{"url": "/", "icon": "home-icon.png", "name": "grnet cloud", "id": "cloud"},
+ {"url": "/okeanos.html", "name": "~okeanos", "id": "okeanos"},
+ {"url": "/ui/", "name": "pithos+", "id": "pithos"}]
+ 
+Get Menu
+^^^^^^^^
+
+Returns a json formatted list containing the cloud bar links. 
+
+==================== =========  ==================
+Uri                  Method     Description
+==================== =========  ==================
+``/im/get_menu``     GET        Get cloud bar menu
+==================== =========  ==================
+
+Example reply if request user is not authenticated:
+
+::
+
+[{"url": "/im/login?next=", "name": "login..."}]
+
+Example reply if request user is authenticated:
+
+[{"url": "/im/profile", "name": "spapagian@grnet.gr"},
+ {"url": "/im/profile", "name": "view your profile..."},
+ {"url": "/im/password", "name": "change your password..."},
+ {"url": "/im/feedback", "name": "feedback..."},
+ {"url": "/im/logout", "name": "logout..."}]
+
+
+
+
diff --git a/snf-astakos-app/astakos/im/api.py b/snf-astakos-app/astakos/im/api.py
index e6ad5f4..f570b28 100644
--- a/snf-astakos-app/astakos/im/api.py
+++ b/snf-astakos-app/astakos/im/api.py
@@ -33,12 +33,17 @@
 
 from traceback import format_exc
 from time import time, mktime
+from urllib import quote
+from urlparse import urlparse
+
 from django.conf import settings
 from django.http import HttpResponse
 from django.utils import simplejson as json
+from django.core.urlresolvers import reverse
 
 from astakos.im.faults import BadRequest, Unauthorized, InternalServerError
 from astakos.im.models import AstakosUser
+from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED
 
 def render_fault(request, fault):
     if isinstance(fault, InternalServerError) and settings.DEBUG:
@@ -91,3 +96,30 @@ def authenticate(request):
     except BaseException, e:
         fault = InternalServerError('Unexpected error')
         return render_fault(request, fault)
+
+def get_services(request):
+    if request.method != 'GET':
+        raise BadRequest('Method not allowed.')
+    data = json.dumps(CLOUD_SERVICES)
+    return HttpResponse(content=data, mimetype="application/json")
+
+def get_menu(request):
+    if request.method != 'GET':
+        raise BadRequest('Method not allowed.')
+    location = request.GET.get('location', '')
+    index_url = reverse('astakos.im.views.index')
+    if urlparse(location).query.rfind('next=') == -1:
+        index_url = '%s?next=%s' % (index_url, quote(location))
+    l = [{ 'url': index_url, 'name': "login..."}]
+    if request.user.is_authenticated():
+        l = []
+        l.append({ 'url': reverse('astakos.im.views.edit_profile'), 'name': request.user.email})
+        l.append({ 'url': reverse('astakos.im.views.edit_profile'), 'name': "view your profile..." })
+        if request.user.password:
+            l.append({ 'url': reverse('password_change'), 'name': "change your password..." })
+        if INVITATIONS_ENABLED:
+            l.append({ 'url': reverse('astakos.im.views.invite'), 'name': "invite some friends..." })
+        l.append({ 'url': reverse('astakos.im.views.send_feedback'), 'name': "feedback..." })
+        l.append({ 'url': reverse('astakos.im.views.logout'), 'name': "logout..."})
+    data = json.dumps(tuple(l))
+    return HttpResponse(content=data, mimetype="application/json")
\ No newline at end of file
diff --git a/snf-astakos-app/astakos/im/settings.py b/snf-astakos-app/astakos/im/settings.py
index 9a67892..1093a96 100644
--- a/snf-astakos-app/astakos/im/settings.py
+++ b/snf-astakos-app/astakos/im/settings.py
@@ -47,3 +47,9 @@ BASEURL = getattr(settings, 'ASTAKOS_BASEURL', 'http://pithos.dev.grnet.gr')
 
 # Set service name
 SITENAME = getattr(settings, 'ASTAKOS_SITENAME', 'GRNET Cloud')
+
+# Set cloud services appear in the horizontal bar
+CLOUD_SERVICES = getattr(settings, 'ASTAKOS_CLOUD_SERVICES', (
+        { 'url':'/', 'name':'grnet cloud', 'id':'cloud', 'icon':'home-icon.png' },
+        { 'url':'/okeanos.html', 'name':'~okeanos', 'id':'okeanos' },
+        { 'url':'/ui/', 'name':'pithos+', 'id':'pithos' }))
\ No newline at end of file
diff --git a/snf-astakos-app/astakos/im/static/im/cloudbar/cloudbar.js b/snf-astakos-app/astakos/im/static/im/cloudbar/cloudbar.js
index 64ddf25..def84d1 100644
--- a/snf-astakos-app/astakos/im/static/im/cloudbar/cloudbar.js
+++ b/snf-astakos-app/astakos/im/static/im/cloudbar/cloudbar.js
@@ -5,21 +5,6 @@ $(document).ready(function(){
     */
 
     var PROFILE_URL = "https://accounts.cloud.grnet.gr";
-    var SERVICES_LINKS = window.CLOUDBAR_SERVICES_LINKS || {
-        'cloud':   { url:'/', name:'grnet cloud', id:'cloud', icon:'home-icon.png' },
-        'okeanos': { url:'/okeanos.html', name:'~okeanos', id:'okeanos' },
-        'pithos':  { url:'/ui/', name:'pithos+', id:'pithos' }
-    };
-    
-    var PROFILE_LINKS = window.CLOUDBAR_PROFILE_LINKS || {
-        'login': { url: '/im/login?next=' + window.location.toString(), auth:false, name: "login...", visible:false },
-        'profile': { url: '/im/profile', auth:true, name: "view your profile..." },
-        'password': { url: '/im/password', auth:true, name: "change your password..." },
-        'invitations': { url: '/im/invite', auth:true, name: "invite some friends..." },
-        'feedback': { url: '/im/feedback', auth:true, name: "feedback..." },
-        'logout': { url: '/im/logout', auth:true, name: "logout..." }
-    };
-
 
     // cookie plugin https://raw.github.com/carhartl/jquery-cookie/master/jquery.cookie.js 
     //  * Copyright (c) 2010 Klaus Hartl, @carhartl
@@ -51,66 +36,47 @@ $(document).ready(function(){
     var services = $('<div class="services"></div>');
     var profile = $('<div class="profile"></div>');
     
-    
     // create services links and set the active class to the current service
-    $.each(SERVICES_LINKS, function(i, el){
-        var slink = $("<a>");
-        if (el.icon) {
-            slink.append($('<img src="'+cssloc+el.icon+'"/>'));
-        } else {
-            slink.text(el.name);
-        }
-        slink.attr('href', el.url);
-        slink.attr('title', el.name);
-        services.append(slink);
-        if (el.id == ACTIVE_MENU) {
-            slink.addClass("active");
-        }
-    });
-
-    var USERNAME, LOGGED_IN;
-    var authcookie = cookie(COOKIE_NAME);
-    var anonymous = {'user': 'Login...', 'logged_in': false};
-
-    if (authcookie && authcookie.indexOf("|") > -1) {
-        USER_DATA.logged_in = true;
-        USER_DATA.user = authcookie.split("|")[0];
-    } else {
-        USER_DATA = anonymous;
-    }
-
-    USERNAME = USER_DATA.user;
-    LOGGED_IN = USER_DATA.logged_in;
-
-    // clear username
-    USERNAME = USERNAME.replace(/\\'/g,'');
-    USERNAME = USERNAME.replace(/\"/g,'');
-
-    var user = $('<div class="user"></div>');
-    var username = $('<a href="#"></a>');
-    username.text(USERNAME);
+    $.getJSON('/im/get_services/', function(data) {
+            $.each(data, function(i, el){
+            var slink = $("<a>");
+            if (el.icon) {
+                slink.append($('<img src="'+cssloc+el.icon+'"/>'));
+            } else {
+                slink.text(el.name);
+            }
+            slink.attr('href', el.url);
+            slink.attr('title', el.name);
+            services.append(slink);
+            if (el.id == ACTIVE_MENU) {
+                slink.addClass("active");
+            }
+        });
+      });
     
     // create profile links
+    var user = $('<div class="user"></div>');    
+    var username = $('<a href="#"></a>');
     var usermenu = $("<ul>");
-    $.each(PROFILE_LINKS, function(i,el) {
-        if (!LOGGED_IN && el.auth) { return }
-        if (LOGGED_IN && !el.auth) { return }
-        var li = $("<li />");
-        var link = $("<a />");
-        link.text(el.name);
-        link.attr({href:el.url});
-        li.append(link);
-        if (el.visible == false) {
-            li.hide();
-        }
-        usermenu.append(li);
+    $.getJSON('/im/get_menu/?location='.concat(window.location.toString()), function(data) {
+        $.each(data, function(i,el) {
+            if (i == 0){
+                username.text(el.name);
+                username.attr('href', el.url);
+            }else{
+                var link = $("<a />");
+                link.text(el.name);
+                link.attr({href:el.url});
+                var li = $("<li />");
+                li.append(link);
+                usermenu.append(li);
+            }
+        });
     });
-
+    
     //profile.filter(".user a").attr("href", 
                                    //profile.find("li a").get(0).attr("href"))
     
-
-    
     user.append(username);
     user.append(usermenu);
     profile.append(user);
diff --git a/snf-astakos-app/astakos/im/urls.py b/snf-astakos-app/astakos/im/urls.py
index b2143c2..2e8c876 100644
--- a/snf-astakos-app/astakos/im/urls.py
+++ b/snf-astakos-app/astakos/im/urls.py
@@ -62,7 +62,7 @@ if 'local' in IM_MODULES:
         url(r'^local/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
          'password_reset_confirm'),
         url(r'^local/password/reset/complete/$', 'password_reset_complete'),
-        url(r'^password/?$', 'password_change', {'post_change_redirect':'profile'})
+        url(r'^password/?$', 'password_change', {'post_change_redirect':'profile'}, name='password_change')
     )
 
 if INVITATIONS_ENABLED:
@@ -82,5 +82,7 @@ if 'twitter' in IM_MODULES:
     )
 
 urlpatterns += patterns('astakos.im.api',
-    url(r'^authenticate/?$', 'authenticate')
+    url(r'^authenticate/?$', 'authenticate'),
+    url(r'^get_services/?$', 'get_services'),
+    url(r'^get_menu/?$', 'get_menu'),
 )
