Skip to content

Commit

Permalink
Merge pull request #348 from kbrabrand/global-image-endpoint
Browse files Browse the repository at this point in the history
Global image endpoint
  • Loading branch information
rexxars committed Oct 1, 2015
2 parents c6564c4 + 5d4d832 commit 7dfddb3
Show file tree
Hide file tree
Showing 24 changed files with 421 additions and 67 deletions.
20 changes: 19 additions & 1 deletion docs/usage/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ results in:
"lastModified": "Wed, 18 Apr 2012 15:12:52 GMT"
}
where ``id`` is the user (the same used in the URI of the request), ``numImages`` is the number of images the user has stored in Imbo and ``lastModified`` is when the user last uploaded or deleted an image, or when the user last updated metadata of an image. If the user has not added any images yet, the ``lastModified`` value will be set to the current time on the server.
where ``user`` is the user (the same used in the URI of the request), ``numImages`` is the number of images the user has stored in Imbo and ``lastModified`` is when the user last uploaded or deleted an image, or when the user last updated metadata of an image. If the user has not added any images yet, the ``lastModified`` value will be set to the current time on the server.

**Typical response codes:**

Expand Down Expand Up @@ -642,6 +642,24 @@ results in:
* 400 Bad request
* 404 Image not found

.. _global-images-resource:

Global images resource - ``/images``
++++++++++++++++++++++++++++++++++++++++++

The global images resource is used to search for images across users, given that the public key has access to the images of these users.

This resource is read only, and behaves in the same way as described in the `Get image collections` section of :doc:`_images-resource`. In addition to the parameters specified for `Get image collections`, the following query parameter must be specified:

``user[]``
An array of users to get images for.

.. code-block:: bash
curl "http://imbo/images?user[]=foo&user[]=bar"
results in a response with the exact same format as shown under `Get image collections`.

.. _publickey-resource:

Public key resource - ``/keys/<publicKey>``
Expand Down
1 change: 1 addition & 0 deletions library/Imbo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public function run(array $config) {
'Imbo\Resource\ShortUrls',
'Imbo\Resource\ShortUrl',
'Imbo\Resource\User',
'Imbo\Resource\GlobalImages',
'Imbo\Resource\Images',
'Imbo\Resource\Image',
'Imbo\Resource\Metadata',
Expand Down
9 changes: 9 additions & 0 deletions library/Imbo/Auth/AccessControl/Adapter/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ interface AdapterInterface {
const RESOURCE_SHORTURLS_POST = 'shorturls.post';
const RESOURCE_SHORTURLS_DELETE = 'shorturls.delete';

/**
* Get a list of users the public key has access for on a given resource
*
* @param string $publicKey Public key to check access for
* @param string $resource Resource identifier (e.g. image.get, images.post)
* @return array List of users the public key kan access the given resource for
*/
function getUsersForResource($publicKey, $resource);

/**
* Check if a given public key has access to a given resource
*
Expand Down
33 changes: 33 additions & 0 deletions library/Imbo/Auth/AccessControl/Adapter/ArrayAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,39 @@ public function __construct(array $accessList = [], $groups = []) {
$this->keys = $this->getKeysFromAcl();
}

/**
* {@inheritdoc}
*/
public function getUsersForResource($publicKey, $resource) {
if (!$publicKey || !$resource) {
return [];
}

$accessList = $this->getAccessListForPublicKey($publicKey);

// Get all user lists
$userLists = array_filter(array_map(function($acl) {
return isset($acl['users']) ? $acl['users'] : false;
}, $accessList));

// Merge user lists
$users = call_user_func_array('array_merge', $userLists);

// Check if public key has access to user with same name
if ($this->hasAccess($publicKey, $resource, $publicKey)) {
$userList[] = $publicKey;
}

// Check for each user specified in acls
foreach ($users as $user) {
if ($this->hasAccess($publicKey, $resource, $user)) {
$userList[] = $user;
}
}

return $userList;
}

/**
* {@inheritdoc}
*/
Expand Down
33 changes: 33 additions & 0 deletions library/Imbo/Auth/AccessControl/Adapter/MongoDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,39 @@ public function __construct(array $params = null, MongoClient $client = null, Mo
}
}

/**
* {@inheritdoc}
*/
public function getUsersForResource($publicKey, $resource) {
if (!$publicKey || !$resource) {
return [];
}

$accessList = $this->getAccessListForPublicKey($publicKey);

// Get all user lists
$userLists = array_filter(array_map(function($acl) {
return isset($acl['users']) ? $acl['users'] : false;
}, $accessList));

// Merge user lists
$users = call_user_func_array('array_merge', $userLists);

// Check if public key has access to user with same name
if ($this->hasAccess($publicKey, $resource, $publicKey)) {
$userList[] = $publicKey;
}

// Check for each user specified in acls
foreach ($users as $user) {
if ($this->hasAccess($publicKey, $resource, $user)) {
$userList[] = $user;
}
}

return $userList;
}

/**
* {@inheritdoc}
*/
Expand Down
14 changes: 7 additions & 7 deletions library/Imbo/Database/DatabaseInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ function deleteMetadata($user, $imageIdentifier);
*
* This method is also responsible for setting a correct "hits" number in the images model.
*
* @param string $user The user which the image belongs to
* @param array $users The users which the images belongs to
* @param Query $query A query instance
* @param Images $model The images model
* @return array
* @throws DatabaseException
*/
function getImages($user, Query $query, Images $model);
function getImages(array $users, Query $query, Images $model);

/**
* Load information from database into the image object
Expand All @@ -114,18 +114,18 @@ function load($user, $imageIdentifier, Image $image);
function getImageProperties($user, $imageIdentifier);

/**
* Get the last modified timestamp of a user
* Get the last modified timestamp for given users
*
* If the $imageIdentifier parameter is set, return when that image was last updated. If not
* set, return when the user last updated any image. If the user does not have any images
* stored, return the current timestamp.
* set, return the most recent date when one of the specified users last updated any image. If
* the provided users does not have any images stored, return the current timestamp.
*
* @param string $user The user which the image belongs to
* @param array $users The users
* @param string $imageIdentifier The image identifier
* @return DateTime Returns an instance of DateTime
* @throws DatabaseException
*/
function getLastModified($user, $imageIdentifier = null);
function getLastModified(array $users, $imageIdentifier = null);

/**
* Fetch the number of images, optionally filtered by a given user
Expand Down
34 changes: 26 additions & 8 deletions library/Imbo/Database/Doctrine.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,22 @@ public function deleteMetadata($user, $imageIdentifier) {
/**
* {@inheritdoc}
*/
public function getImages($user, Query $query, Images $model) {
public function getImages(array $users, Query $query, Images $model) {
$images = array();

$qb = $this->getConnection()->createQueryBuilder();
$qb->select('*')
->from($this->tableNames['imageinfo'], 'i')
->where('i.user = :user')->setParameter(':user', $user);
$qb->select('*')->from($this->tableNames['imageinfo'], 'i');

// Filter on users
$expr = $qb->expr();
$composite = $expr->orX();

foreach ($users as $i => $user) {
$composite->add($expr->eq('i.user', ':user' . $i));
$qb->setParameter(':user' . $i, $user);
}

$qb->where($composite);

if ($sort = $query->sort()) {
// Fields valid for sorting
Expand Down Expand Up @@ -399,12 +408,21 @@ public function load($user, $imageIdentifier, Image $image) {
/**
* {@inheritdoc}
*/
public function getLastModified($user, $imageIdentifier = null) {
public function getLastModified(array $users, $imageIdentifier = null) {
$query = $this->getConnection()->createQueryBuilder();
$query->select('updated')
->from($this->tableNames['imageinfo'], 'i')
->where('i.user = :user')
->setParameter(':user', $user);
->from($this->tableNames['imageinfo'], 'i');

// Filter on users
$expr = $query->expr();
$composite = $expr->orX();

foreach ($users as $i => $user) {
$composite->add($expr->eq('i.user', ':user' . $i));
$query->setParameter(':user' . $i, $user);
}

$query->where($composite);

if ($imageIdentifier) {
$query->andWhere('i.imageIdentifier = :imageIdentifier')
Expand Down
10 changes: 4 additions & 6 deletions library/Imbo/Database/MongoDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,12 @@ public function deleteMetadata($user, $imageIdentifier) {
/**
* {@inheritdoc}
*/
public function getImages($user, Query $query, Images $model) {
public function getImages(array $users, Query $query, Images $model) {
// Initialize return value
$images = [];

// Query data
$queryData = [
'user' => $user,
];
$queryData = ['user' => ['$in' => $users]];

$from = $query->from();
$to = $query->to();
Expand Down Expand Up @@ -371,10 +369,10 @@ public function load($user, $imageIdentifier, Image $image) {
/**
* {@inheritdoc}
*/
public function getLastModified($user, $imageIdentifier = null) {
public function getLastModified(array $users, $imageIdentifier = null) {
try {
// Query on the user
$query = ['user' => $user];
$query = ['user' => ['$in' => $users]];

if ($imageIdentifier) {
// We want information about a single image. Add the identifier to the query
Expand Down
2 changes: 2 additions & 0 deletions library/Imbo/EventListener/AccessToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ public static function getSubscribedEvents() {
'image.head',
'images.get',
'images.head',
'globalimages.get',
'globalimages.head',
'metadata.get',
'metadata.head',
'shorturl.get',
Expand Down
21 changes: 15 additions & 6 deletions library/Imbo/EventListener/DatabaseOperations.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public function loadMetadata(EventInterface $event) {
$model->setData($database->getMetadata($user, $imageIdentifier));

$response->setModel($model)
->setLastModified($database->getLastModified($user, $imageIdentifier));
->setLastModified($database->getLastModified([$user], $imageIdentifier));
}

/**
Expand Down Expand Up @@ -226,7 +226,16 @@ public function loadImages(EventInterface $event) {
}
}

$user = $event->getRequest()->getUser();
if ($event->hasArgument('users')) {
$users = $event->getArgument('users');
} else {
$users = $event->getRequest()->getUsers();

if (!is_array($users)) {
$users = [];
}
}

$response = $event->getResponse();
$database = $event->getDatabase();

Expand All @@ -235,15 +244,15 @@ public function loadImages(EventInterface $event) {
$model->setLimit($query->limit())
->setPage($query->page());

$images = $database->getImages($user, $query, $model);
$images = $database->getImages($users, $query, $model);
$modelImages = array();

foreach ($images as $image) {
$entry = new Model\Image();
$entry->setFilesize($image['size'])
->setWidth($image['width'])
->setHeight($image['height'])
->setUser($user)
->setUser($image['user'])
->setImageIdentifier($image['imageIdentifier'])
->setChecksum($image['checksum'])
->setOriginalChecksum(isset($image['originalChecksum']) ? $image['originalChecksum'] : null)
Expand All @@ -270,7 +279,7 @@ public function loadImages(EventInterface $event) {
}
}

$lastModified = $database->getLastModified($user);
$lastModified = $database->getLastModified($users);

$response->setModel($model)
->setLastModified($lastModified);
Expand All @@ -288,7 +297,7 @@ public function loadUser(EventInterface $event) {
$database = $event->getDatabase();

$numImages = $database->getNumImages($user);
$lastModified = $database->getLastModified($user);
$lastModified = $database->getLastModified([$user]);

$userModel = new Model\User();
$userModel->setUserId($user)
Expand Down
20 changes: 20 additions & 0 deletions library/Imbo/Http/Request/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ public function getUser() {
return $this->route ? $this->route->get('user') : null;
}

/**
* Get users specified in the request
*
* @return array Users specified in the request
*/
public function getUsers() {
$routeUser = $this->getUser();
$queryUsers = $this->query->get('user', []);

if (!$routeUser && !$queryUsers) {
return [];
} elseif (!$queryUsers) {
return [$routeUser];
} elseif (!$routeUser) {
return $queryUsers;
}

return array_merge([$routeUser], $queryUsers);
}

/**
* Get image transformations from the request
*
Expand Down

0 comments on commit 7dfddb3

Please sign in to comment.