# or implied, of GRNET S.A.
import logging
+import urllib
+from functools import wraps
from traceback import format_exc
from time import time, mktime
from urllib import quote
from django.utils import simplejson as json
from django.core.urlresolvers import reverse
-from astakos.im.faults import BadRequest, Unauthorized, InternalServerError
+from astakos.im.faults import BadRequest, Unauthorized, InternalServerError, \
+Fault, ItemNotFound, Forbidden
from astakos.im.models import AstakosUser
-from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED
+from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED, COOKIE_NAME, \
+EMAILCHANGE_ENABLED
+from astakos.im.util import epoch
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:
response['Content-Length'] = len(response.content)
return response
-def authenticate(request):
+def api_method(http_method=None, token_required=False, perms=None):
+ """Decorator function for views that implement an API method."""
+ if not perms:
+ perms = []
+
+ def decorator(func):
+ @wraps(func)
+ def wrapper(request, *args, **kwargs):
+ try:
+ if http_method and request.method != http_method:
+ raise BadRequest('Method not allowed.')
+ x_auth_token = request.META.get('HTTP_X_AUTH_TOKEN')
+ if token_required:
+ if not x_auth_token:
+ raise Unauthorized('Access denied')
+ try:
+ user = AstakosUser.objects.get(auth_token=x_auth_token)
+ if not user.has_perms(perms):
+ raise Forbidden('Unauthorized request')
+ except AstakosUser.DoesNotExist, e:
+ raise Unauthorized('Invalid X-Auth-Token')
+ kwargs['user'] = user
+ 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
+
+@api_method(http_method='GET', token_required=True)
+def authenticate_old(request, user=None):
# Normal Response Codes: 204
# Error Response Codes: internalServerError (500)
# badRequest (400)
# unauthorised (401)
- try:
- if request.method != 'GET':
- raise BadRequest('Method not allowed.')
- x_auth_token = request.META.get('HTTP_X_AUTH_TOKEN')
- if not x_auth_token:
- return render_fault(request, BadRequest('Missing X-Auth-Token'))
-
- try:
- user = AstakosUser.objects.get(auth_token=x_auth_token)
- except AstakosUser.DoesNotExist, e:
- return render_fault(request, Unauthorized('Invalid X-Auth-Token'))
+ if not user:
+ raise BadRequest('No user')
+
+ # Check if the is active.
+ if not user.is_active:
+ raise Unauthorized('User inactive')
- # Check if the is active.
- if not user.is_active:
- return render_fault(request, Unauthorized('User inactive'))
+ # Check if the token has expired.
+ if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
+ raise Unauthorized('Authentication expired')
+
+ if not user.signed_terms():
+ raise Unauthorized('Pending approval terms')
+
+ response = HttpResponse()
+ response.status=204
+ user_info = {'username':user.username,
+ 'uniq':user.email,
+ 'auth_token':user.auth_token,
+ 'auth_token_created':user.auth_token_created.isoformat(),
+ 'auth_token_expires':user.auth_token_expires.isoformat(),
+ 'has_credits':user.has_credits,
+ 'has_signed_terms':user.signed_terms()}
+ response.content = json.dumps(user_info)
+ response['Content-Type'] = 'application/json; charset=UTF-8'
+ response['Content-Length'] = len(response.content)
+ return response
- # Check if the token has expired.
- if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
- return render_fault(request, Unauthorized('Authentication expired'))
+@api_method(http_method='GET', token_required=True)
+def authenticate(request, user=None):
+ # Normal Response Codes: 204
+ # Error Response Codes: internalServerError (500)
+ # badRequest (400)
+ # unauthorised (401)
+ if not user:
+ raise BadRequest('No user')
+
+ # Check if the is active.
+ if not user.is_active:
+ raise Unauthorized('User inactive')
- response = HttpResponse()
- response.status=204
- user_info = {'username':user.username,
- 'uniq':user.email,
- 'auth_token':user.auth_token,
- 'auth_token_created':user.auth_token_created.isoformat(),
- 'auth_token_expires':user.auth_token_expires.isoformat(),
- 'has_credits':user.has_credits}
- response.content = json.dumps(user_info)
- response['Content-Type'] = 'application/json; charset=UTF-8'
- response['Content-Length'] = len(response.content)
- return response
- except BaseException, e:
- logger.exception(e)
- fault = InternalServerError('Unexpected error')
- return render_fault(request, fault)
+ # Check if the token has expired.
+ if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
+ raise Unauthorized('Authentication expired')
+
+ if not user.signed_terms():
+ raise Unauthorized('Pending approval terms')
+
+ response = HttpResponse()
+ response.status=204
+ user_info = {'userid':user.username,
+ 'email':[user.email],
+ 'name':user.realname,
+ 'auth_token':user.auth_token,
+ 'auth_token_created':epoch(user.auth_token_created),
+ 'auth_token_expires':epoch(user.auth_token_expires),
+ 'has_credits':user.has_credits,
+ 'is_active':user.is_active,
+ 'groups':[g.name for g in user.groups.all()]}
+ response.content = json.dumps(user_info)
+ response['Content-Type'] = 'application/json; charset=UTF-8'
+ response['Content-Length'] = len(response.content)
+ return response
+@api_method(http_method='GET')
def get_services(request):
- if request.method != 'GET':
- raise BadRequest('Method not allowed.')
-
callback = request.GET.get('callback', None)
data = json.dumps(CLOUD_SERVICES)
mimetype = 'application/json'
return HttpResponse(content=data, mimetype=mimetype)
+@api_method()
def get_menu(request, with_extra_links=False, with_signout=True):
- location = request.GET.get('location', '')
- exclude = []
index_url = reverse('index')
- login_url = reverse('login')
- logout_url = reverse('astakos.im.views.logout')
absolute = lambda (url): request.build_absolute_uri(url)
- l = index_url, login_url, logout_url
- forbidden = []
- for url in l:
- url = url.rstrip('/')
- forbidden.extend([url, url + '/', absolute(url), absolute(url + '/')])
- if location not in forbidden:
- index_url = '%s?next=%s' % (index_url, quote(location))
l = [{ 'url': absolute(index_url), 'name': "Sign in"}]
- if request.user.is_authenticated():
+ cookie = urllib.unquote(request.COOKIES.get(COOKIE_NAME, ''))
+ email = cookie.partition('|')[0]
+ try:
+ user = AstakosUser.objects.get(email=email, is_active=True)
+ except AstakosUser.DoesNotExist:
+ pass
+ else:
l = []
l.append({ 'url': absolute(reverse('astakos.im.views.index')),
- 'name': request.user.email})
+ 'name': user.email})
l.append({ 'url': absolute(reverse('astakos.im.views.edit_profile')),
'name': "My account" })
if with_extra_links:
- if request.user.password:
+ if user.has_usable_password():
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.send_feedback')),
+ l.append({ 'url': absolute(reverse('astakos.im.views.feedback')),
'name': "Feedback" })
if with_signout:
l.append({ 'url': absolute(reverse('astakos.im.views.logout')),
data = '%s(%s)' % (callback, data)
return HttpResponse(content=data, mimetype=mimetype)
+
+@api_method(http_method='GET', token_required=True, perms=['im.can_access_userinfo'])
+def get_user_by_email(request, user=None):
+ # Normal Response Codes: 200
+ # Error Response Codes: internalServerError (500)
+ # badRequest (400)
+ # unauthorised (401)
+ # forbidden (403)
+ # itemNotFound (404)
+ email = request.GET.get('name')
+ if not email:
+ raise BadRequest('Email missing')
+ try:
+ user = AstakosUser.objects.get(email = email)
+ except AstakosUser.DoesNotExist, e:
+ raise ItemNotFound('Invalid email')
+
+ if not user.is_active:
+ raise ItemNotFound('Inactive user')
+ else:
+ response = HttpResponse()
+ response.status=200
+ user_info = {'id':user.id,
+ 'username':user.username,
+ 'email':[user.email],
+ 'enabled':user.is_active,
+ 'name':user.realname,
+ 'auth_token_created':user.auth_token_created.strftime(format),
+ 'auth_token_expires':user.auth_token_expires.strftime(format),
+ 'has_credits':user.has_credits,
+ 'groups':[g.name for g in user.groups.all()],
+ 'user_permissions':[p.codename for p in user.user_permissions.all()],
+ 'group_permissions': list(user.get_group_permissions())}
+ response.content = json.dumps(user_info)
+ response['Content-Type'] = 'application/json; charset=UTF-8'
+ response['Content-Length'] = len(response.content)
+ return response
+
+@api_method(http_method='GET', token_required=True, perms=['can_access_userinfo'])
+def get_user_by_username(request, user_id, user=None):
+ # Normal Response Codes: 200
+ # Error Response Codes: internalServerError (500)
+ # badRequest (400)
+ # unauthorised (401)
+ # forbidden (403)
+ # itemNotFound (404)
+ try:
+ user = AstakosUser.objects.get(username = user_id)
+ except AstakosUser.DoesNotExist, e:
+ raise ItemNotFound('Invalid userid')
+ else:
+ response = HttpResponse()
+ response.status=200
+ user_info = {'id':user.id,
+ 'username':user.username,
+ 'email':[user.email],
+ 'name':user.realname,
+ 'auth_token_created':user.auth_token_created.strftime(format),
+ 'auth_token_expires':user.auth_token_expires.strftime(format),
+ 'has_credits':user.has_credits,
+ 'enabled':user.is_active,
+ 'groups':[g.name for g in user.groups.all()]}
+ 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