commit 14c5be5a5280412a0810fe3376ccc7e0c5a0127a
Author: Sofia Papagiannaki <papagian@gmail.com>
Date:   Fri Aug 3 11:25:29 2012 +0300

    move get_menu and get_service out of api/admin

diff --git a/snf-astakos-app/astakos/im/api/__init__.py b/snf-astakos-app/astakos/im/api/__init__.py
index 6bb6daf..9f3b750 100644
--- a/snf-astakos-app/astakos/im/api/__init__.py
+++ b/snf-astakos-app/astakos/im/api/__init__.py
@@ -31,14 +31,56 @@
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
+from functools import wraps
+from traceback import format_exc
+from urllib import quote, unquote
+
 from django.http import HttpResponse
 from django.utils import simplejson as json
+from django.conf import settings
+from django.core.urlresolvers import reverse
+
+from astakos.im.models import AstakosUser, GroupKind, Service, Resource
+from astakos.im.encoder import ModelJSONEncoder
+from astakos.im.api.faults import Fault, ItemNotFound, InternalServerError
+from astakos.im.settings import INVITATIONS_ENABLED, COOKIE_NAME, EMAILCHANGE_ENABLED
 
-from astakos.im.models import AstakosUser
-from astakos.im.api.faults import ItemNotFound
+import logging
+logger = logging.getLogger(__name__)
 
 format = ('%a, %d %b %Y %H:%M:%S GMT')
 
+def render_fault(request, fault):
+    if isinstance(fault, InternalServerError) and settings.DEBUG:
+        fault.details = format_exc(fault)
+
+    request.serialization = 'text'
+    data = fault.message + '\n'
+    if fault.details:
+        data += '\n' + fault.details
+    response = HttpResponse(data, status=fault.code)
+    response['Content-Length'] = len(response.content)
+    return response
+
+def api_method(http_method=None):
+    """Decorator function for views that implement an API method."""
+    def decorator(func):
+        @wraps(func)
+        def wrapper(request, *args, **kwargs):
+            try:
+                if http_method and request.method != http_method:
+                    raise BadRequest('Method not allowed.')
+                response = func(request, *args, **kwargs)
+                return response
+            except Fault, fault:
+                return render_fault(request, fault)
+            except BaseException, e:
+                logger.exception('Unexpected error: %s' % e)
+                fault = InternalServerError('Unexpected error')
+                return render_fault(request, fault)
+        return wrapper
+    return decorator
+
 def _get_user_by_username(user_id):
     try:
         user = AstakosUser.objects.get(username = user_id)
@@ -87,4 +129,67 @@ def _get_user_by_email(email):
         response.content = json.dumps(user_info)
         response['Content-Type'] = 'application/json; charset=UTF-8'
         response['Content-Length'] = len(response.content)
-        return response
\ No newline at end of file
+        return response
+
+@api_method(http_method='GET')
+def get_services(request):
+    callback = request.GET.get('callback', None)
+    services = Service.objects.all()
+    data = tuple({'id':s.pk, 'name':s.name, 'url':s.url, 'icon':s.icon} for s in services)
+    data = json.dumps(data)
+    mimetype = 'application/json'
+
+    if callback:
+        mimetype = 'application/javascript'
+        data = '%s(%s)' % (callback, data)
+
+    return HttpResponse(content=data, mimetype=mimetype)
+
+@api_method()
+def get_menu(request, with_extra_links=False, with_signout=True):
+    index_url = reverse('index')
+    absolute = lambda (url): request.build_absolute_uri(url)
+    l = [{ 'url': absolute(index_url), 'name': "Sign in"}]
+    cookie = unquote(request.COOKIES.get(COOKIE_NAME, ''))
+    email = cookie.partition('|')[0]
+    try:
+        if not email:
+            raise ValueError
+        user = AstakosUser.objects.get(email=email, is_active=True)
+    except AstakosUser.DoesNotExist:
+        pass
+    except ValueError:
+        pass
+    else:
+        l = []
+        l.append({ 'url': absolute(reverse('astakos.im.views.index')),
+                  'name': user.email})
+        l.append({ 'url': absolute(reverse('astakos.im.views.edit_profile')),
+                  'name': "My account" })
+        if with_extra_links:
+            if user.has_usable_password() and user.provider == 'local':
+                l.append({ 'url': absolute(reverse('password_change')),
+                          'name': "Change password" })
+            if EMAILCHANGE_ENABLED:
+                l.append({'url':absolute(reverse('email_change')),
+                          'name': "Change email"})
+            if INVITATIONS_ENABLED:
+                l.append({ 'url': absolute(reverse('astakos.im.views.invite')),
+                          'name': "Invitations" })
+            l.append({ 'url': absolute(reverse('astakos.im.views.feedback')),
+                      'name': "Feedback" })
+            l.append({ 'url': absolute(reverse('group_add')),
+                      'name': "Add group" })
+        if with_signout:
+            l.append({ 'url': absolute(reverse('astakos.im.views.logout')),
+                      'name': "Sign out"})
+
+    callback = request.GET.get('callback', None)
+    data = json.dumps(tuple(l))
+    mimetype = 'application/json'
+
+    if callback:
+        mimetype = 'application/javascript'
+        data = '%s(%s)' % (callback, data)
+
+    return HttpResponse(content=data, mimetype=mimetype)
\ No newline at end of file
