Commit 746c1c81 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

Extend Plankton API with shared-images

Extend Plankton API, to support listing all non-public images that
are available to the user. This can be done by issuing a GET to
shared-images/ and shared-images/detail.
parent 15df0740
......@@ -255,27 +255,12 @@ class ImageBackend(object):
location = get_location(account, container, object)
return self._get_image(location)
def iter(self):
"""Iter over all images available to the user"""
backend = self.backend
for account in backend.list_accounts(self.user):
for container in backend.list_containers(self.user, account,
shared=True):
for path, version_id in backend.list_objects(self.user,
account, container, domain=PLANKTON_DOMAIN):
location = get_location(account, container, path)
image = self._get_image(location)
if image:
yield image
def iter_public(self, filters=None):
def _iter(self, public=False, filters=None, shared_from=None):
filters = filters or {}
backend = self.backend
# Fix keys
keys = [PLANKTON_PREFIX + 'name']
size_range = (None, None)
for key, val in filters.items():
if key == 'size_min':
size_range = (int(val), size_range[1])
......@@ -284,41 +269,50 @@ class ImageBackend(object):
else:
keys.append('%s = %s' % (PLANKTON_PREFIX + key, val))
for account in backend.list_accounts(None):
for container in backend.list_containers(None, account,
backend = self.backend
if shared_from:
# To get shared images, we connect as shared_from member and
# get the list shared by us
user = shared_from
accounts = [self.user]
else:
user = None if public else self.user
accounts = backend.list_accounts(user)
for account in accounts:
for container in backend.list_containers(user, account,
shared=True):
for path, version_id in backend.list_objects(None, account,
container, domain=PLANKTON_DOMAIN, keys=keys,
shared=True, size_range=size_range):
for path, _ in backend.list_objects(user, account, container,
domain=PLANKTON_DOMAIN,
keys=keys, shared=True,
size_range=size_range):
location = get_location(account, container, path)
image = self._get_image(location)
if image:
yield image
def iter_shared(self, member):
"""Iterate over image ids shared to this member"""
def iter(self, filters=None):
"""Iter over all images available to the user"""
return self._iter(filters=filters)
backend = self.backend
def iter_public(self, filters=None):
"""Iter over public images"""
return self._iter(public=True, filters=filters)
# To get the list we connect as member and get the list shared by us
for container in backend.list_containers(member, self.user):
for object, version_id in backend.list_objects(member, self.user,
container, domain=PLANKTON_DOMAIN):
try:
location = get_location(self.user, container, object)
meta = backend.get_object_meta(member, self.user,
container, object, PLANKTON_DOMAIN)
if PLANKTON_PREFIX + 'name' in meta:
yield meta['uuid']
except (NameError, NotAllowedError):
continue
def list(self):
"""Iter over all images available to the user"""
def iter_shared(self, filters=None, member=None):
"""Iter over images shared to member"""
return self._iter(filters=filters)
return list(self.iter())
def list(self, filters=None, params={}):
"""Return all images available to the user"""
images = list(self.iter(filters))
key = itemgetter(params.get('sort_key', 'created_at'))
reverse = params.get('sort_dir', 'desc') == 'desc'
images.sort(key=key, reverse=reverse)
return images
def list_public(self, filters, params):
def list_public(self, filters, params={}):
"""Return public images"""
images = list(self.iter_public(filters))
key = itemgetter(params.get('sort_key', 'created_at'))
reverse = params.get('sort_dir', 'desc') == 'desc'
......@@ -385,7 +379,10 @@ class ImageBackend(object):
raise BackendException("Invalid checksum")
is_public = params.pop('is_public', False)
permissions = {'read': ['*']} if is_public else {}
if is_public:
permissions = {'read': ['*']}
else:
permissions = {'read': [self.user]}
meta = {}
meta['properties'] = params.pop('properties', {})
......
......@@ -45,6 +45,7 @@ def demux(request):
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def demux_image(request, image_id):
if request.method == 'GET':
return views.get_image(request, image_id)
......@@ -55,6 +56,7 @@ def demux_image(request, image_id):
else:
return HttpResponseNotAllowed(['GET', 'HEAD', 'PUT'])
def demux_image_members(request, image_id):
if request.method == 'GET':
return views.list_image_members(request, image_id)
......@@ -63,6 +65,7 @@ def demux_image_members(request, image_id):
else:
return HttpResponseNotAllowed(['GET', 'PUT'])
def demux_members(request, image_id, member):
if request.method == 'DELETE':
return views.remove_image_member(request, image_id, member)
......@@ -77,6 +80,8 @@ urlpatterns = patterns('',
(r'^images/detail$', views.list_public_images, {'detail': True}),
(r'^images/([\w-]+)$', demux_image),
(r'^images/([\w-]+)/members$', demux_image_members),
(r'^images/([\w-]+)/members/(\w+)$', demux_members),
(r'^shared-images/(\w+)$', views.list_shared_images)
(r'^images/([\w-]+)/members/([\w@._-]+)$', demux_members),
(r'^shared-images/$', views.list_shared_images),
(r'^shared-images/detail', views.list_shared_images, {'detail': True}),
(r'^shared-images/([\w@._-]+)$', views.list_shared_images_with)
)
......@@ -35,7 +35,6 @@ import json
from logging import getLogger
from string import punctuation
from StringIO import StringIO
from urllib import unquote
from django.conf import settings
......@@ -272,7 +271,7 @@ def list_public_images(request, detail=False):
@plankton_method('GET')
def list_shared_images(request, member):
def list_shared_images_with(request, member):
"""Request shared images
Described in:
......@@ -283,10 +282,11 @@ def list_shared_images(request, member):
the users's images that are accessible by `member`.
"""
log.debug('list_shared_images %s', member)
log.debug('list_shared_images_with %s', member)
images = []
for image_id in request.backend.iter_shared(member):
for image in request.backend.iter_shared(member):
image_id = image['id']
images.append({'image_id': image_id, 'can_share': False})
data = json.dumps({'shared_images': images}, indent=settings.DEBUG)
......@@ -350,3 +350,38 @@ def update_image_members(request, image_id):
request.backend.replace_users(image_id, members)
return HttpResponse(status=204)
@plankton_method('GET')
def list_shared_images(request, detail=False):
def get_request_params(keys):
params = {}
for key in keys:
val = request.GET.get(key, None)
if val is not None:
params[key] = val
return params
log.debug('list_shared_images detail=%s, request %s', detail, request)
filters = get_request_params(FILTERS)
params = get_request_params(PARAMS)
params.setdefault('sort_key', 'created_at')
params.setdefault('sort_dir', 'desc')
assert params['sort_key'] in SORT_KEY_OPTIONS
assert params['sort_dir'] in SORT_DIR_OPTIONS
images = request.backend.list(filters, params)
images = filter(lambda x: not x['is_public'], images)
# Remove keys that should not be returned
fields = DETAIL_FIELDS if detail else LIST_FIELDS
for image in images:
for key in image.keys():
if key not in fields:
del image[key]
data = json.dumps(images, indent=settings.DEBUG)
return HttpResponse(data)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment