Commit 7ad374bd authored by Kostas Papadimitriou's avatar Kostas Papadimitriou
Browse files

Merge branch 'latest-quota' into feature-astakos-tables

Conflicts:
	snf-astakos-app/astakos/im/templates/im/projects/project_list.html
	snf-astakos-app/astakos/im/views.py
parents 385b7248 8bd1b76d
...@@ -86,58 +86,6 @@ def api_method(http_method=None): ...@@ -86,58 +86,6 @@ def api_method(http_method=None):
return decorator return decorator
def _get_user_by_username(user_id):
try:
user = AstakosUser.objects.get(username=user_id)
except AstakosUser.DoesNotExist:
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
def _get_user_by_email(email):
if not email:
raise BadRequest('Email missing')
try:
user = AstakosUser.objects.get(email__iexact=email)
except AstakosUser.DoesNotExist:
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()]}
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') @api_method(http_method='GET')
def get_services(request): def get_services(request):
callback = request.GET.get('callback', None) callback = request.GET.get('callback', None)
...@@ -170,10 +118,6 @@ def get_menu(request, with_extra_links=False, with_signout=True): ...@@ -170,10 +118,6 @@ def get_menu(request, with_extra_links=False, with_signout=True):
append(item(url=absolute(request, reverse('edit_profile')), append(item(url=absolute(request, reverse('edit_profile')),
name="My account")) name="My account"))
if with_extra_links: if with_extra_links:
# if user.has_usable_password() and user.provider in ('local', ''):
# append(item(
# url=absolute(request, reverse('password_change')),
# name="Change password"))
if EMAILCHANGE_ENABLED: if EMAILCHANGE_ENABLED:
append(item( append(item(
url=absolute(request, reverse('email_change')), url=absolute(request, reverse('email_change')),
...@@ -184,24 +128,6 @@ def get_menu(request, with_extra_links=False, with_signout=True): ...@@ -184,24 +128,6 @@ def get_menu(request, with_extra_links=False, with_signout=True):
name="Invitations")) name="Invitations"))
if QUOTAHOLDER_URL: if QUOTAHOLDER_URL:
# append(item(
# url=absolute(request, reverse('group_list')),
# name="Projects",
# # submenu=(item(
# # url=absolute(request,
# # reverse('group_list')),
# # name="Overview"),
# # item(
# # url=absolute(request,
# # reverse('group_create_list')),
# # name="Create"),
# # item(
# # url=absolute(request,
# # reverse('group_search')),
# # name="Join"),
# # )
# )
# )
append(item( append(item(
url=absolute(request, reverse('project_list')), url=absolute(request, reverse('project_list')),
name="Projects")) name="Projects"))
...@@ -211,12 +137,6 @@ def get_menu(request, with_extra_links=False, with_signout=True): ...@@ -211,12 +137,6 @@ def get_menu(request, with_extra_links=False, with_signout=True):
append(item( append(item(
url=absolute(request, reverse('feedback')), url=absolute(request, reverse('feedback')),
name="Contact")) name="Contact"))
# append(item(
# url=absolute(request, reverse('billing')),
# name="Billing"))
# append(item(
# url=absolute(request, reverse('timeline')),
# name="Timeline"))
if with_signout: if with_signout:
append(item( append(item(
url=absolute(request, reverse('logout')), url=absolute(request, reverse('logout')),
......
...@@ -41,7 +41,7 @@ from smtplib import SMTPException ...@@ -41,7 +41,7 @@ from smtplib import SMTPException
from astakos.im.models import ( from astakos.im.models import (
AstakosUser, AstakosUser,
Resource, Service, RESOURCE_SEPARATOR, Resource, Service, RESOURCE_SEPARATOR,
Project, ProjectApplication, ProjectMembership, filter_queryset_by_property) Project, ProjectApplication, ProjectMembership)
from astakos.im.api.backends.base import ( from astakos.im.api.backends.base import (
BaseBackend, SuccessResult, FailureResult) BaseBackend, SuccessResult, FailureResult)
from astakos.im.api.backends.errors import ( from astakos.im.api.backends.errors import (
......
...@@ -38,9 +38,11 @@ from time import time, mktime ...@@ -38,9 +38,11 @@ from time import time, mktime
from django.http import HttpResponse from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.utils import simplejson as json
from astakos.im.api.faults import Fault, Unauthorized, InternalServerError, BadRequest from . import render_fault
from astakos.im.api import render_fault, _get_user_by_email, _get_user_by_username from .faults import (
Fault, Unauthorized, InternalServerError, BadRequest, ItemNotFound)
from astakos.im.models import AstakosUser, Service from astakos.im.models import AstakosUser, Service
from astakos.im.forms import FeedbackForm from astakos.im.forms import FeedbackForm
from astakos.im.functions import send_feedback as send_feedback_func from astakos.im.functions import send_feedback as send_feedback_func
...@@ -64,8 +66,9 @@ def api_method(http_method=None, token_required=False): ...@@ -64,8 +66,9 @@ def api_method(http_method=None, token_required=False):
service = Service.objects.get(auth_token=x_auth_token) service = Service.objects.get(auth_token=x_auth_token)
# Check if the token has expired. # Check if the token has expired.
if (time() - mktime(service.auth_token_expires.timetuple())) > 0: if service.auth_token_expires:
raise Unauthorized('Authentication expired') if (time() - mktime(service.auth_token_expires.timetuple())) > 0:
raise Unauthorized('Authentication expired')
except Service.DoesNotExist, e: except Service.DoesNotExist, e:
raise Unauthorized('Invalid X-Auth-Token') raise Unauthorized('Invalid X-Auth-Token')
response = func(request, *args, **kwargs) response = func(request, *args, **kwargs)
...@@ -81,26 +84,40 @@ def api_method(http_method=None, token_required=False): ...@@ -81,26 +84,40 @@ def api_method(http_method=None, token_required=False):
@api_method(http_method='GET', token_required=True) @api_method(http_method='GET', token_required=True)
def get_user_by_email(request, user=None): def get_user_info(request):
# Normal Response Codes: 200 # Normal Response Codes: 200
# Error Response Codes: internalServerError (500) # Error Response Codes: internalServerError (500)
# badRequest (400) # badRequest (400)
# unauthorised (401) # unauthorised (401)
# forbidden (403)
# itemNotFound (404) # itemNotFound (404)
email = request.GET.get('name') username = request.META.get('HTTP_X_USER_USERNAME')
return _get_user_by_email(email) uuid = request.META.get('HTTP_X_USER_UUID')
if not username and not uuid:
raise BadRequest('Either username or uuid is required.')
@api_method(http_method='GET', token_required=True)
def get_user_by_username(request, user_id, user=None): query = AstakosUser.objects.all()
# Normal Response Codes: 200 user_info = None
# Error Response Codes: internalServerError (500) if username:
# badRequest (400) try:
# unauthorised (401) user = query.get(username__iexact=username)
# forbidden (403) except AstakosUser.DoesNotExist:
# itemNotFound (404) raise ItemNotFound('Invalid username: %s' % username)
return _get_user_by_username(user_id) else:
user_info = {'uuid': user.uuid}
else:
try:
user = query.get(uuid=uuid)
except AstakosUser.DoesNotExist:
raise ItemNotFound('Invalid uuid: %s' % uuid)
else:
user_info = {'username': user.username}
response = HttpResponse()
response.status = 200
response.content = json.dumps(user_info)
response['Content-Type'] = 'application/json; charset=UTF-8'
response['Content-Length'] = len(response.content)
return response
@csrf_exempt @csrf_exempt
......
...@@ -40,11 +40,6 @@ class Boolean(Integer): ...@@ -40,11 +40,6 @@ class Boolean(Integer):
Boolean = Boolean() Boolean = Boolean()
# class GroupKind(Integer):
# def init(self):
# self.opts.update({'minimum': 1, 'maximum': 5})
# GroupKind = GroupKind()
Timepoint = Text(classname='Timepoint', maxlen=24) Timepoint = Text(classname='Timepoint', maxlen=24)
......
...@@ -39,10 +39,9 @@ from time import time, mktime ...@@ -39,10 +39,9 @@ from time import time, mktime
from django.http import HttpResponse from django.http import HttpResponse
from django.utils import simplejson as json from django.utils import simplejson as json
from astakos.im.api.faults import ( from .faults import (
Fault, Unauthorized, InternalServerError, BadRequest, Fault, Unauthorized, InternalServerError, BadRequest, Forbidden)
Forbidden) from . import render_fault
from astakos.im.api import render_fault, _get_user_by_email, _get_user_by_username
from astakos.im.models import AstakosUser from astakos.im.models import AstakosUser
from astakos.im.util import epoch from astakos.im.util import epoch
...@@ -84,45 +83,6 @@ def api_method(http_method=None, token_required=False, perms=None): ...@@ -84,45 +83,6 @@ def api_method(http_method=None, token_required=False, perms=None):
return decorator 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)
if not user:
raise BadRequest('No user')
# Check if the is active.
if not user.is_active:
raise 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 = {
'id': user.id,
'username': user.username,
'uuid': user.uuid,
'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,
'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', token_required=True) @api_method(http_method='GET', token_required=True)
def authenticate(request, user=None): def authenticate(request, user=None):
# Normal Response Codes: 204 # Normal Response Codes: 204
...@@ -147,40 +107,14 @@ def authenticate(request, user=None): ...@@ -147,40 +107,14 @@ def authenticate(request, user=None):
response.status = 204 response.status = 204
user_info = { user_info = {
'id': user.id, 'id': user.id,
'userid': user.username, 'username': user.username,
'uuid': user.uuid, 'uuid': user.uuid,
'email': [user.email], 'email': [user.email],
'name': user.realname, 'name': user.realname,
'auth_token': user.auth_token,
'auth_token_created': epoch(user.auth_token_created), 'auth_token_created': epoch(user.auth_token_created),
'auth_token_expires': epoch(user.auth_token_expires), 'auth_token_expires': epoch(user.auth_token_expires),
'has_credits': user.has_credits, '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 = json.dumps(user_info)
response['Content-Type'] = 'application/json; charset=UTF-8' response['Content-Type'] = 'application/json; charset=UTF-8'
response['Content-Length'] = len(response.content) response['Content-Length'] = len(response.content)
return response return response
@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')
return _get_user_by_email(email)
@api_method(http_method='GET', token_required=True, perms=['im.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)
return _get_user_by_username(user_id)
...@@ -65,60 +65,102 @@ def get_client(): ...@@ -65,60 +65,102 @@ def get_client():
_client = QuotaholderClient(QUOTAHOLDER_URL, token=QUOTAHOLDER_TOKEN) _client = QuotaholderClient(QUOTAHOLDER_URL, token=QUOTAHOLDER_TOKEN)
return _client return _client
def call(func_name): def set_quota(payload):
"""Decorator function for Quotaholder client calls.""" c = get_client()
def decorator(payload_func): if not c:
@wraps(payload_func) return
def wrapper(entities=(), **kwargs): result = c.set_quota(context={}, clientkey=clientkey, set_quota=payload)
if not entities: logger.info('set_quota: %s rejected: %s' % (payload, result))
return () return result
if not QUOTAHOLDER_URL: def get_quota(user):
return () c = get_client()
if not c:
c = get_client() return
func = c.__dict__.get(func_name) payload = []
if not func: append = payload.append
return () for r in user.quota.keys():
append((user.uuid, r, ENTITY_KEY),)
data = payload_func(entities, **kwargs) result = c.get_quota(context={}, clientkey=clientkey, get_quota=payload)
if not data: logger.info('get_quota: %s rejected: %s' % (payload, result))
return data return result
funcname = func.__name__
kwargs = {'context': {}, funcname: data}
rejected = func(**kwargs)
msg = _('%s: %s - Rejected: %s' % (funcname, data, rejected,))
logger.log(LOGGING_LEVEL, msg)
return rejected
return wrapper
return decorator
@call('set_quota')
def send_quota(users):
data = []
append = data.append
for user in users:
for resource, uplimit in user.quota.iteritems():
key = ENTITY_KEY
quantity = None
capacity = uplimit if uplimit != inf else None
import_limit = None
export_limit = None
flags = 0
args = (
user.uuid, resource, key, quantity, capacity, import_limit,
export_limit, flags)
append(args)
return data
def create_entity(payload):
c = get_client()
if not c:
return
result = c.create_entity(context={}, clientkey=clientkey, create_entity=payload)
logger.info('create_entity: %s rejected: %s' % (payload, result))
return result
SetQuotaPayload = namedtuple('SetQuotaPayload', ('holder',
'resource',
'key',
'quantity',
'capacity',
'import_limit',
'export_limit',
'flags'))
GetQuotaPayload = namedtuple('GetQuotaPayload', ('holder',
'resource',
'key'))
CreateEntityPayload = namedtuple('CreateEntityPayload', ('entity',
'owner',
'key',
'ownerkey'))
QuotaLimits = namedtuple('QuotaLimits', ('holder', QuotaLimits = namedtuple('QuotaLimits', ('holder',
'resource', 'resource',
'capacity', 'capacity',
'import_limit', 'import_limit',
'export_limit')) 'export_limit'))
def register_users(users):
payload = list(CreateEntityPayload(
entity=u.uuid,
owner='system',
key=ENTITY_KEY,
ownerkey='') for u in users)
rejected = create_entity(payload)
if not rejected:
payload = []
append = payload.append
for u in users:
for resource, uplimit in u.quota.iteritems():
append( SetQuotaPayload(
holder=u.uuid,
resource=resource,
key=ENTITY_KEY,
quantity=0,
capacity=uplimit if uplimit != inf else None,
import_limit=0,
export_limit=0,
flags=0))
return set_quota(payload)
def register_resources(resources):
rdata = ((r.service, r) for r in resources)
services = set(r.service for r in resources)
payload = list(CreateEntityPayload(
entity=service,
owner='system',
key=ENTITY_KEY,
ownerkey='') for service in set(services))
rejected = create_entity(payload)
if not rejected:
payload = list(SetQuotaPayload(
holder=resource.service,
resource=resource,
key=ENTITY_KEY,
quantity=None,
capacity=None,
import_limit=None,
export_limit=None,
flags=0) for resource in resources)
return set_quota(payload)
def qh_add_quota(serial, sub_list, add_list): def qh_add_quota(serial, sub_list, add_list):
if not QUOTAHOLDER_URL: if not QUOTAHOLDER_URL:
return () return ()
...@@ -171,84 +213,6 @@ def qh_ack_serials(serials): ...@@ -171,84 +213,6 @@ def qh_ack_serials(serials):
serials=serials) serials=serials)
return return
@call('set_quota')
def send_resource_quantities(resources):
data = []
append = data.append
for resource in resources:
key = ENTITY_KEY
quantity = resource.meta.filter(key='quantity') or None
capacity = None
import_limit = None
export_limit = None
flags = 0
args = (resource.service.name, str(resource), key, quantity, capacity,
import_limit, export_limit, flags)
append(args)
return data
@call('get_quota')
def get_quota(users):
data = []
append = data.append
for user in users:
try:
entity = user.uuid
except AttributeError:
continue
else:
for r in user.quota.keys():
args = entity, r, ENTITY_KEY
append(args)
return data
@call('create_entity')
def create_user_entities(entities):
data = []
append = data.append
for entity in entities:
entity = entity.uuid
owner = 'system'
key = ENTITY_KEY
ownerkey = ''
args = entity, owner, key, ownerkey
append(args)
return data
@call('create_entity')
def create_service_entities(entities):
data = []
append = data.append
l = []
for entity in entities:
entity = entity.service.name
if entity in l:
continue
l.append(entity)
owner = 'system'
key = ENTITY_K