Revision 1ae97c83

b/docs/source/devguide.rst
12 12
* Twitter
13 13
* Shibboleth
14 14

  
15
It provides also an administrative interface for managing user accounts.
15
It provides also a command line tool for managing user accounts.
16 16

  
17 17
It is build over django and extends its authentication mechanism.
18 18

  
......
102 102
* send feedback for grnet services via: ``/im/send_feedback``
103 103
* logout (and delete cookie) via: ``/im/logout``
104 104

  
105
User entries can also be modified/added via the administrative interface available at ``/im/admin``.
105
User entries can also be modified/added via the ``snf-manage activateuser`` command.
106 106

  
107 107
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).
108 108

  
......
126 126
The Astakos API
127 127
---------------
128 128

  
129
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`)
130

  
131 129
.. _authenticate-api-label:
132 130

  
133 131
Authenticate
134 132
^^^^^^^^^^^^
135 133

  
134
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`)
135

  
136 136
==================== =========  ==================
137
Uri                                  Method     Description
137
Uri                  Method     Description
138 138
==================== =========  ==================
139 139
``/im/authenticate`` GET        Authenticate user using token
140 140
==================== =========  ==================
......
179 179
401 (Unauthorized)          Missing token or inactive user
180 180
500 (Internal Server Error) The request cannot be completed because of an internal error
181 181
=========================== =====================
182

  
183
Get Services
184
^^^^^^^^^^^^
185

  
186
Returns a json formatted list containing information about the supported cloud services.
187

  
188
==================== =========  ==================
189
Uri                  Method     Description
190
==================== =========  ==================
191
``/im/get_services`` GET        Get cloud services
192
==================== =========  ==================
193

  
194
Example reply:
195

  
196
::
197

  
198
[{"url": "/", "icon": "home-icon.png", "name": "grnet cloud", "id": "cloud"},
199
 {"url": "/okeanos.html", "name": "~okeanos", "id": "okeanos"},
200
 {"url": "/ui/", "name": "pithos+", "id": "pithos"}]
201
 
202
Get Menu
203
^^^^^^^^
204

  
205
Returns a json formatted list containing the cloud bar links. 
206

  
207
==================== =========  ==================
208
Uri                  Method     Description
209
==================== =========  ==================
210
``/im/get_menu``     GET        Get cloud bar menu
211
==================== =========  ==================
212

  
213
Example reply if request user is not authenticated:
214

  
215
::
216

  
217
[{"url": "/im/login?next=", "name": "login..."}]
218

  
219
Example reply if request user is authenticated:
220

  
221
[{"url": "/im/profile", "name": "spapagian@grnet.gr"},
222
 {"url": "/im/profile", "name": "view your profile..."},
223
 {"url": "/im/password", "name": "change your password..."},
224
 {"url": "/im/feedback", "name": "feedback..."},
225
 {"url": "/im/logout", "name": "logout..."}]
226

  
227

  
228

  
229

  
b/snf-astakos-app/astakos/im/api.py
33 33

  
34 34
from traceback import format_exc
35 35
from time import time, mktime
36
from urllib import quote
37
from urlparse import urlparse
38

  
36 39
from django.conf import settings
37 40
from django.http import HttpResponse
38 41
from django.utils import simplejson as json
42
from django.core.urlresolvers import reverse
39 43

  
40 44
from astakos.im.faults import BadRequest, Unauthorized, InternalServerError
41 45
from astakos.im.models import AstakosUser
46
from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED
42 47

  
43 48
def render_fault(request, fault):
44 49
    if isinstance(fault, InternalServerError) and settings.DEBUG:
......
91 96
    except BaseException, e:
92 97
        fault = InternalServerError('Unexpected error')
93 98
        return render_fault(request, fault)
99

  
100
def get_services(request):
101
    if request.method != 'GET':
102
        raise BadRequest('Method not allowed.')
103
    data = json.dumps(CLOUD_SERVICES)
104
    return HttpResponse(content=data, mimetype="application/json")
105

  
106
def get_menu(request):
107
    if request.method != 'GET':
108
        raise BadRequest('Method not allowed.')
109
    location = request.GET.get('location', '')
110
    index_url = reverse('astakos.im.views.index')
111
    if urlparse(location).query.rfind('next=') == -1:
112
        index_url = '%s?next=%s' % (index_url, quote(location))
113
    l = [{ 'url': index_url, 'name': "login..."}]
114
    if request.user.is_authenticated():
115
        l = []
116
        l.append({ 'url': reverse('astakos.im.views.edit_profile'), 'name': request.user.email})
117
        l.append({ 'url': reverse('astakos.im.views.edit_profile'), 'name': "view your profile..." })
118
        if request.user.password:
119
            l.append({ 'url': reverse('password_change'), 'name': "change your password..." })
120
        if INVITATIONS_ENABLED:
121
            l.append({ 'url': reverse('astakos.im.views.invite'), 'name': "invite some friends..." })
122
        l.append({ 'url': reverse('astakos.im.views.send_feedback'), 'name': "feedback..." })
123
        l.append({ 'url': reverse('astakos.im.views.logout'), 'name': "logout..."})
124
    data = json.dumps(tuple(l))
125
    return HttpResponse(content=data, mimetype="application/json")
b/snf-astakos-app/astakos/im/settings.py
47 47

  
48 48
# Set service name
49 49
SITENAME = getattr(settings, 'ASTAKOS_SITENAME', 'GRNET Cloud')
50

  
51
# Set cloud services appear in the horizontal bar
52
CLOUD_SERVICES = getattr(settings, 'ASTAKOS_CLOUD_SERVICES', (
53
        { 'url':'/', 'name':'grnet cloud', 'id':'cloud', 'icon':'home-icon.png' },
54
        { 'url':'/okeanos.html', 'name':'~okeanos', 'id':'okeanos' },
55
        { 'url':'/ui/', 'name':'pithos+', 'id':'pithos' }))
b/snf-astakos-app/astakos/im/static/im/cloudbar/cloudbar.js
5 5
    */
6 6

  
7 7
    var PROFILE_URL = "https://accounts.cloud.grnet.gr";
8
    var SERVICES_LINKS = window.CLOUDBAR_SERVICES_LINKS || {
9
        'cloud':   { url:'/', name:'grnet cloud', id:'cloud', icon:'home-icon.png' },
10
        'okeanos': { url:'/okeanos.html', name:'~okeanos', id:'okeanos' },
11
        'pithos':  { url:'/ui/', name:'pithos+', id:'pithos' }
12
    };
13
    
14
    var PROFILE_LINKS = window.CLOUDBAR_PROFILE_LINKS || {
15
        'login': { url: '/im/login?next=' + window.location.toString(), auth:false, name: "login...", visible:false },
16
        'profile': { url: '/im/profile', auth:true, name: "view your profile..." },
17
        'password': { url: '/im/password', auth:true, name: "change your password..." },
18
        'invitations': { url: '/im/invite', auth:true, name: "invite some friends..." },
19
        'feedback': { url: '/im/feedback', auth:true, name: "feedback..." },
20
        'logout': { url: '/im/logout', auth:true, name: "logout..." }
21
    };
22

  
23 8

  
24 9
    // cookie plugin https://raw.github.com/carhartl/jquery-cookie/master/jquery.cookie.js 
25 10
    //  * Copyright (c) 2010 Klaus Hartl, @carhartl
......
51 36
    var services = $('<div class="services"></div>');
52 37
    var profile = $('<div class="profile"></div>');
53 38
    
54
    
55 39
    // create services links and set the active class to the current service
56
    $.each(SERVICES_LINKS, function(i, el){
57
        var slink = $("<a>");
58
        if (el.icon) {
59
            slink.append($('<img src="'+cssloc+el.icon+'"/>'));
60
        } else {
61
            slink.text(el.name);
62
        }
63
        slink.attr('href', el.url);
64
        slink.attr('title', el.name);
65
        services.append(slink);
66
        if (el.id == ACTIVE_MENU) {
67
            slink.addClass("active");
68
        }
69
    });
70

  
71
    var USERNAME, LOGGED_IN;
72
    var authcookie = cookie(COOKIE_NAME);
73
    var anonymous = {'user': 'Login...', 'logged_in': false};
74

  
75
    if (authcookie && authcookie.indexOf("|") > -1) {
76
        USER_DATA.logged_in = true;
77
        USER_DATA.user = authcookie.split("|")[0];
78
    } else {
79
        USER_DATA = anonymous;
80
    }
81

  
82
    USERNAME = USER_DATA.user;
83
    LOGGED_IN = USER_DATA.logged_in;
84

  
85
    // clear username
86
    USERNAME = USERNAME.replace(/\\'/g,'');
87
    USERNAME = USERNAME.replace(/\"/g,'');
88

  
89
    var user = $('<div class="user"></div>');
90
    var username = $('<a href="#"></a>');
91
    username.text(USERNAME);
40
    $.getJSON('/im/get_services/', function(data) {
41
            $.each(data, function(i, el){
42
            var slink = $("<a>");
43
            if (el.icon) {
44
                slink.append($('<img src="'+cssloc+el.icon+'"/>'));
45
            } else {
46
                slink.text(el.name);
47
            }
48
            slink.attr('href', el.url);
49
            slink.attr('title', el.name);
50
            services.append(slink);
51
            if (el.id == ACTIVE_MENU) {
52
                slink.addClass("active");
53
            }
54
        });
55
      });
92 56
    
93 57
    // create profile links
58
    var user = $('<div class="user"></div>');    
59
    var username = $('<a href="#"></a>');
94 60
    var usermenu = $("<ul>");
95
    $.each(PROFILE_LINKS, function(i,el) {
96
        if (!LOGGED_IN && el.auth) { return }
97
        if (LOGGED_IN && !el.auth) { return }
98
        var li = $("<li />");
99
        var link = $("<a />");
100
        link.text(el.name);
101
        link.attr({href:el.url});
102
        li.append(link);
103
        if (el.visible == false) {
104
            li.hide();
105
        }
106
        usermenu.append(li);
61
    $.getJSON('/im/get_menu/?location='.concat(window.location.toString()), function(data) {
62
        $.each(data, function(i,el) {
63
            if (i == 0){
64
                username.text(el.name);
65
                username.attr('href', el.url);
66
            }else{
67
                var link = $("<a />");
68
                link.text(el.name);
69
                link.attr({href:el.url});
70
                var li = $("<li />");
71
                li.append(link);
72
                usermenu.append(li);
73
            }
74
        });
107 75
    });
108

  
76
    
109 77
    //profile.filter(".user a").attr("href", 
110 78
                                   //profile.find("li a").get(0).attr("href"))
111 79
    
112

  
113
    
114 80
    user.append(username);
115 81
    user.append(usermenu);
116 82
    profile.append(user);
b/snf-astakos-app/astakos/im/urls.py
62 62
        url(r'^local/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
63 63
         'password_reset_confirm'),
64 64
        url(r'^local/password/reset/complete/$', 'password_reset_complete'),
65
        url(r'^password/?$', 'password_change', {'post_change_redirect':'profile'})
65
        url(r'^password/?$', 'password_change', {'post_change_redirect':'profile'}, name='password_change')
66 66
    )
67 67

  
68 68
if INVITATIONS_ENABLED:
......
82 82
    )
83 83

  
84 84
urlpatterns += patterns('astakos.im.api',
85
    url(r'^authenticate/?$', 'authenticate')
85
    url(r'^authenticate/?$', 'authenticate'),
86
    url(r'^get_services/?$', 'get_services'),
87
    url(r'^get_menu/?$', 'get_menu'),
86 88
)

Also available in: Unified diff