diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gallery/helpers/gallery_rest.php | 299 | ||||
-rw-r--r-- | modules/gallery/helpers/item.php | 16 | ||||
-rw-r--r-- | modules/gallery/libraries/ORM_MPTT.php | 20 | ||||
-rw-r--r-- | modules/gallery/tests/Gallery_Rest_Helper_Test.php | 3 | ||||
-rw-r--r-- | modules/image_block/helpers/image_block_block.php | 24 | ||||
-rw-r--r-- | modules/image_block/helpers/image_block_rest.php | 62 | ||||
-rw-r--r-- | modules/kohana23_compat/libraries/MY_Database_Builder.php | 12 | ||||
-rw-r--r-- | modules/rest/controllers/rest.php | 60 | ||||
-rw-r--r-- | modules/rest/helpers/rest.php | 104 | ||||
-rw-r--r-- | modules/rest/libraries/Rest_Exception.php | 17 | ||||
-rw-r--r-- | modules/rest/tests/Rest_Controller_Test.php | 20 | ||||
-rw-r--r-- | modules/tag/helpers/tag.php | 2 | ||||
-rw-r--r-- | modules/tag/helpers/tag_rest.php | 161 | ||||
-rw-r--r-- | modules/tag/helpers/tags_rest.php | 48 | ||||
-rw-r--r-- | modules/tag/tests/Tag_Rest_Helper_Test.php | 12 |
15 files changed, 328 insertions, 532 deletions
diff --git a/modules/gallery/helpers/gallery_rest.php b/modules/gallery/helpers/gallery_rest.php index a87ebb4e..0de5da2b 100644 --- a/modules/gallery/helpers/gallery_rest.php +++ b/modules/gallery/helpers/gallery_rest.php @@ -17,232 +17,139 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class gallery_rest_Core { - static function get($request) { - $path = implode("/", $request->arguments); - - $item = gallery_rest::_get_item($path); - - $parent = $item->parent(); - $response_data = array("type" => $item->type, - "name" => $item->name, - "path" => $item->relative_url(), - "parent_path" => empty($parent) ? null : $parent->relative_url(), - "title" => $item->title, - "thumb_url" => $item->thumb_url(true), - "thumb_size" => array("height" => $item->thumb_height, - "width" => $item->thumb_width), - "resize_url" => $item->resize_url(true), - "resize_size" => array("height" => (int)$item->resize_height, - "width" => (int)$item->resize_width), - "url" => $item->file_url(true), - "size" => array("height" => $item->height, - "width" => $item->width), - "description" => $item->description, - "slug" => $item->slug); - - $children = self::_get_children($item, $request); - if (!empty($children) || $item->is_album()) { - $response_data["children"] = $children; - } - return rest::success(array("resource" => $response_data)); - } - static function put($request) { - if (empty($request->arguments)) { - throw new Rest_Exception(400, "Bad request"); - } - $path = implode("/", $request->arguments); - $item = gallery_rest::_get_item($path, "edit"); - - // Validate the request data - $new_values = gallery_rest::_validate($request, $item->parent_id, $item->id); - $errors = $new_values->errors(); - if (empty($errors)) { - $item->title = $new_values->title; - $item->description = $new_values->description; - if ($item->id != 1) { - $item->rename($new_values->name); - } - $item->slug = $new_values->slug; - $item->save(); +// @todo Add logging +// @todo VALIDATION + +// Validation questions +// +// We need to be able to properly validate anything we want to enter here. But all of our +// validation currently happens at the controller / form level, and we're not using the same +// controllers or forms. +// +// Possible solutions: +// 1) Move validation into the model and use it both here and in the regular controllers. But +// if we do that, how do we translate validation failures into a user-consumable output which +// we need so that we can return proper error responses to form submissions? +// +// 2) Create some kind of validation helper that can validate every field. Wait, isn't this +// just like #1 except in a helper instead of in the model? - log::success("content", "Updated $item->type", - "<a href=\"{$item->type}s/$item->id\">view</a>"); +class gallery_rest_Core { - return rest::success(); - } else { - return rest::validation_error($errors); - } - } + /** + * For items that are collections, you can specify the following additional query parameters to + * query the collection. You can specify them in any combination. + * + * scope=direct + * only return items that are immediately under this one + * scope=all + * return items anywhere under this one + * + * name=<substring> + * only return items where the name contains this substring + * + * random=true + * return a single random item + * + * type=<comma separate list of photo, movie or album> + * limit the type to types in this list. eg, "type=photo,movie" + */ + static function get($request) { + $item = rest::resolve($request->url); + access::required("view", $item); - static function post($request) { - if (empty($request->arguments)) { - throw new Rest_Exception(400, "Bad request"); + $p = $request->params; + if (isset($p->random)) { + $orm = item::random_query()->offset(0)->limit(1); + } else { + $orm = ORM::factory("item")->viewable(); } - $components = $request->arguments; - $name = urldecode(array_pop($components)); - - $parent = gallery_rest::_get_item(implode("/", $components), "edit"); - - // Validate the request data - $request->name = $name; - $new_values = gallery_rest::_validate($request, $parent->id); - $errors = $new_values->errors(); - if (!empty($errors)) { - return rest::validation_error($errors); + if (!empty($p->scope) && !in_array($p->scope, array("direct", "all"))) { + throw new Exception("Bad Request", 400); } - - if (empty($new_values["image"])) { - $new_item = album::create( - $parent, - $name, - empty($new_values["title"]) ? $name : $new_values["title"], - empty($new_values["description"]) ? null : $new_values["description"], - identity::active_user()->id, - empty($new_values["slug"]) ? $name : $new_values["slug"]); - $log_message = t("Added an album"); - } else { - $temp_filename = upload::save("image"); - $path_info = @pathinfo($temp_filename); - if (array_key_exists("extension", $path_info) && - in_array(strtolower($path_info["extension"]), array("flv", "mp4"))) { - $new_item = - movie::create($parent, $temp_filename, $new_values["name"], $new_values["title"]); - $log_message = t("Added a movie"); + if (!empty($p->scope)) { + if ($p->scope == "direct") { + $orm->where("parent_id", "=", $item->id); } else { - $new_item = - photo::create($parent, $temp_filename, $new_values["name"], $new_values["title"]); - $log_message = t("Added a photo"); + $orm->where("left_ptr", ">=", $item->left_ptr); + $orm->where("right_ptr", "<=", $item->left_ptr); + $orm->where("id", "<>", $item->id); } } - log::success("content", $log_message, "<a href=\"{$new_item->type}s/$new_item->id\">view</a>"); - - return rest::success(array("path" => $new_item->relative_url())); - } - - static function delete($request) { - if (empty($request->arguments)) { - throw new Rest_Exception(400, "Bad request"); + if (isset($p->name)) { + $orm->where("name", "LIKE", "%{$p->name}%"); } - $path = implode("/", $request->arguments); - - $item = gallery_rest::_get_item($path, "edit"); - if ($item->id == 1) { - throw new Rest_Exception(400, "Bad request"); + if (isset($p->type)) { + $orm->where("type", "IN", explode(",", $p->type)); } - $parent = $item->parent(); - $item->delete(); - - if ($item->is_album()) { - $msg = t("Deleted album <b>%title</b>", array("title" => html::purify($item->title))); - } else { - $msg = t("Deleted photo <b>%title</b>", array("title" => html::purify($item->title))); + $members = array(); + foreach ($orm->find_all() as $child) { + $members[] = url::abs_site("rest/gallery/" . $child->relative_url()); } - log::success("content", $msg); - return rest::success(array("resource" => array("parent_path" => $parent->relative_url()))); + return rest::reply(array("resource" => $item->as_array(), "members" => $members)); } - private static function _get_item($path, $permission="view") { - $item = url::get_item_from_uri($path); - - if (!$item->loaded()) { - throw new Kohana_404_Exception(); - } - - if (!access::can($permission, $item)) { - throw new Kohana_404_Exception(); + static function put($request) { + $item = rest::resolve($request->url); + access::required("edit", $item); + + $params = $request->params; + foreach (array("captured", "description", "slug", "sort_column", "sort_order", + "title", "view_count", "weight") as $key) { + if (isset($params->$key)) { + $item->$key = $params->$key; + } } + $item->save(); - return $item; + return rest::reply(array("url" => url::abs_site("/rest/gallery/" . $item->relative_url()))); } - private static function _get_children($item, $request) { - $children = array(); - $limit = empty($request->limit) ? null : $request->limit; - $offset = empty($request->offset) ? null : $request->offset; - $where = empty($request->filter) ? array() : array("type" => $request->filter); - foreach ($item->viewable()->children($limit, $offset, $where) as $child) { - $children[] = array("type" => $child->type, - "has_children" => $child->children_count() > 0, - "path" => $child->relative_url(), - "thumb_url" => $child->thumb_url(true), - "thumb_dimensions" => array("width" => $child->thumb_width, - "height" => $child->thumb_height), - "has_thumb" => $child->has_thumb(), - "title" => $child->title); - } - - return $children; - } + static function post($request) { + $parent = rest::resolve($request->url); + access::required("edit", $parent); - private static function _validate($request, $parent_id, $item_id=0) { - $item = ORM::factory("item", $item_id); + $params = $request->params; + switch ($params->type) { + case "album": + $item = album::create( + $parent, + $params->name, + isset($params->title) ? $params->title : $name, + isset($params->description) ? $params->description : null); + break; - // Normalize the inputs so all fields have a value - $new_values = Validation::factory(array()); - foreach ($item->form_rules as $field => $rule_set) { - if (isset($request->$field)) { - $new_values[$field] = $request->$field; - } else if (isset($item->$field)) { - $new_values[$field] = $item->$field; - } - foreach (explode("|", $rule_set) as $rule) { - $new_values->add_rules($field, $rule); - } - } - $name = $new_values["name"]; - $new_values["title"] = empty($new_values["title"]) ? $name : $new_values["title"]; - $new_values["description"] = - empty($new_values["description"]) ? null : $new_values["description"]; - $new_values["slug"] = empty($new_values["slug"]) ? $name : $new_values["slug"]; - - if (!empty($request->image)) { - $new_values["image"] = $request->image; - $new_values->add_rules( - "image", "upload::valid", "upload::required", "upload::type[gif,jpg,jpeg,png,flv,mp4]"); - } + case "photo": + $item = photo::create( + $parent, + $request->file, + $params->name, + isset($params->title) ? $params->title : $name, + isset($params->description) ? $params->description : null); + break; - if ($new_values->validate() && $item_id != 1) { - $errors = gallery_rest::_check_for_conflicts($parent_id, $item_id, - $new_values["name"], $new_values["slug"]); - if (!empty($errors)) { - !empty($errors["name_conflict"]) OR $new_values->add_error("name", "Duplicate name"); - !empty($errors["slug_conflict"]) OR - $new_values->add_error("slug", "Duplicate Internet address"); - } + default: + throw new Rest_Exception("Invalid type: $args->type", 400); } - return $new_values; + return rest::reply(array("url" => url::abs_site("/rest/gallery/" . $item->relative_url()))); } - private static function _check_for_conflicts($parent_id, $item_id, $new_name, $new_slug) { - $errors = array(); - - if ($row = db::build() - ->select(array("name", "slug")) - ->from("items") - ->where("parent_id", "=", $parent_id) - ->where("id", "<>", $item_id) - ->and_open() - ->where("name", "=", $new_name) - ->or_where("slug", "=", $new_slug) - ->close() - ->execute() - ->current()) { - if ($row->name == $new_name) { - $errors["name_conflict"] = 1; - } - if ($row->slug == $new_slug) { - $errors["slug_conflict"] = 1; - } - } + static function delete($request) { + $item = rest::resolve($request->url); + access::required("edit", $item); + + $item->delete(); + return rest::reply(); + } - return $errors; + static function resolve($path) { + return url::get_item_from_uri($path); } } diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php index f6181f8a..1fd9ef16 100644 --- a/modules/gallery/helpers/item.php +++ b/modules/gallery/helpers/item.php @@ -173,4 +173,20 @@ class item_Core { static function root() { return model_cache::get("item", 1); } + + /** + * Return a query to get a random Item_Model, with optional filters + * + * @param array (optional) where tuple + */ + static function random_query($where=null) { + // Pick a random number and find the item that's got nearest smaller number. + // This approach works best when the random numbers in the system are roughly evenly + // distributed so this is going to be more efficient with larger data sets. + return ORM::factory("item") + ->viewable() + ->where("rand_key", "<", ((float)mt_rand()) / (float)mt_getrandmax()) + ->merge_where($where) + ->order_by("rand_key", "DESC"); + } }
\ No newline at end of file diff --git a/modules/gallery/libraries/ORM_MPTT.php b/modules/gallery/libraries/ORM_MPTT.php index 0ea519c9..ed77cac9 100644 --- a/modules/gallery/libraries/ORM_MPTT.php +++ b/modules/gallery/libraries/ORM_MPTT.php @@ -165,11 +165,8 @@ class ORM_MPTT_Core extends ORM { * @return array ORM */ function children($limit=null, $offset=null, $where=null, $order_by=array("id" => "ASC")) { - if ($where) { - $this->merge_where($where); - } - return $this + ->merge_where($where) ->where("parent_id", "=", $this->id) ->order_by($order_by) ->find_all($limit, $offset); @@ -183,11 +180,8 @@ class ORM_MPTT_Core extends ORM { * @return array ORM */ function children_count($where=null) { - if ($where) { - $this->merge_where($where); - } - return $this + ->merge_where($where) ->where("parent_id", "=", $this->id) ->count_all(); } @@ -202,11 +196,8 @@ class ORM_MPTT_Core extends ORM { * @return object ORM_Iterator */ function descendants($limit=null, $offset=null, $where=null, $order_by=array("id" => "ASC")) { - if ($where) { - $this->merge_where($where); - } - return $this + ->merge_where($where) ->where("left_ptr", ">", $this->left_ptr) ->where("right_ptr", "<=", $this->right_ptr) ->order_by($order_by) @@ -220,11 +211,8 @@ class ORM_MPTT_Core extends ORM { * @return integer child count */ function descendants_count($where=null) { - if ($where) { - $this->merge_where($where); - } - return $this + ->merge_where($where) ->where("left_ptr", ">", $this->left_ptr) ->where("right_ptr", "<=", $this->right_ptr) ->count_all(); diff --git a/modules/gallery/tests/Gallery_Rest_Helper_Test.php b/modules/gallery/tests/Gallery_Rest_Helper_Test.php index cd0aabae..c5c8a890 100644 --- a/modules/gallery/tests/Gallery_Rest_Helper_Test.php +++ b/modules/gallery/tests/Gallery_Rest_Helper_Test.php @@ -136,7 +136,8 @@ class Gallery_Rest_Helper_Test extends Unit_Test_Case { try { gallery_rest::put($request); } catch (Rest_Exception $e) { - $this->assert_equal("400 Bad request", $e->getMessage()); + $this->assert_equal("Bad request", $e->getMessage()); + $this->assert_equal(400, $e->getCode()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } diff --git a/modules/image_block/helpers/image_block_block.php b/modules/image_block/helpers/image_block_block.php index f591e8d1..f28e775f 100644 --- a/modules/image_block/helpers/image_block_block.php +++ b/modules/image_block/helpers/image_block_block.php @@ -30,29 +30,9 @@ class image_block_block_Core { $block->css_id = "g-image-block"; $block->title = t("Random image"); $block->content = new View("image_block_block.html"); + $block->content->items = item::random_query(array(array("type", "!=", "album")))->find_all(1); - $random = ((float)mt_rand()) / (float)mt_getrandmax(); - - $items = ORM::factory("item") - ->viewable() - ->where("type", "!=", "album") - ->where("rand_key", "<", $random) - ->order_by(array("rand_key" => "DESC")) - ->find_all(1); - - if ($items->count() == 0) { - // Try once more. If this fails, just ditch the block altogether - $items = ORM::factory("item") - ->viewable() - ->where("type", "!=", "album") - ->where("rand_key", ">=", $random) - ->order_by(array("rand_key" => "DESC")) - ->find_all(1); - } - - if ($items->count() > 0) { - $block->content->item = $items->current(); - } else { + if ($block->content->items->count() == 0) { $block = ""; } break; diff --git a/modules/image_block/helpers/image_block_rest.php b/modules/image_block/helpers/image_block_rest.php deleted file mode 100644 index 7afd974c..00000000 --- a/modules/image_block/helpers/image_block_rest.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php defined("SYSPATH") or die("No direct script access."); -/** - * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2009 Bharat Mediratta - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. - */ -class image_block_rest_Core { - static function get($request) { - $type = empty($request->type) ? "random" : $request->type; - switch ($type) { - case "random": - $random = ((float)mt_rand()) / (float)mt_getrandmax(); - - $items = ORM::factory("item") - ->viewable() - ->where("type", "!=", "album") - ->where("rand_key", "<", $random) - ->order_by(array("rand_key" => "DESC")) - ->find_all(1); - - if ($items->count() == 0) { - // Try once more. If this fails, just ditch the block altogether - $items = ORM::factory("item") - ->viewable() - ->where("type", "!=", "album") - ->where("rand_key", ">= ", $random) - ->order_by(array("rand_key" => "DESC")) - ->find_all(1); - } - break; - default: - return rest::fail("Unsupported image block type: '{$type}'"); - } - - if ($items->count() > 0) { - $item = $items->current(); - $response_data = array("name" => $item->name, - "path" => $item->relative_url(), - "title" => $item->title, - "thumb_url" => $item->thumb_url(true), - "thumb_size" => array("height" => $item->thumb_height, - "width" => $item->thumb_width)); - - return rest::success(array("resource" => $response_data)); - } else { - return rest::fail("No Image found"); - } - } -} diff --git a/modules/kohana23_compat/libraries/MY_Database_Builder.php b/modules/kohana23_compat/libraries/MY_Database_Builder.php index c82b6ac4..b2a5c92a 100644 --- a/modules/kohana23_compat/libraries/MY_Database_Builder.php +++ b/modules/kohana23_compat/libraries/MY_Database_Builder.php @@ -23,8 +23,10 @@ class Database_Builder extends Database_Builder_Core { * @chainable */ public function merge_where($tuples) { - foreach ($tuples as $tuple) { - $this->where($tuple[0], $tuple[1], $tuple[2]); + if ($tuples) { + foreach ($tuples as $tuple) { + $this->where($tuple[0], $tuple[1], $tuple[2]); + } } return $this; } @@ -34,8 +36,10 @@ class Database_Builder extends Database_Builder_Core { * @chainable */ public function merge_or_where($tuples) { - foreach ($tuples as $tuple) { - $this->or_where($tuple[0], $tuple[1], $tuple[2]); + if ($tuples) { + foreach ($tuples as $tuple) { + $this->or_where($tuple[0], $tuple[1], $tuple[2]); + } } return $this; } diff --git a/modules/rest/controllers/rest.php b/modules/rest/controllers/rest.php index 26e5b31a..5ef9eb84 100644 --- a/modules/rest/controllers/rest.php +++ b/modules/rest/controllers/rest.php @@ -18,20 +18,14 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Rest_Controller extends Controller { - public function access_key() { + public function index() { try { - $request = (object)Input::instance()->get(); - if (empty($request->user) || empty($request->password)) { - throw new Rest_Exception(403, "Forbidden"); - } - - $user = identity::lookup_user_by_name($request->user); - if (empty($user)) { - throw new Rest_Exception(403, "Forbidden"); - } + $username = Input::instance()->post("user"); + $password = Input::instance()->post("password"); - if (!identity::is_correct_password($user, $request->password)) { - throw new Rest_Exception(403, "Forbidden"); + $user = identity::lookup_user_by_name($username); + if (empty($user) || !identity::is_correct_password($user, $password)) { + throw new Rest_Exception("Forbidden", 403); } $key = ORM::factory("user_access_token") @@ -42,27 +36,45 @@ class Rest_Controller extends Controller { $key->access_key = md5($user->name . rand()); $key->save(); } - print rest::success(array("token" => $key->access_key)); - } catch (Rest_Exception $e) { - $e->sendHeaders(); + + rest::reply($key->access_key); + } catch (Exception $e) { + rest::send_headers($e); } } public function __call($function, $args) { - $request = rest::normalize_request($args); + $input = Input::instance(); + switch ($method = strtolower($input->server("REQUEST_METHOD"))) { + case "get": + $request->params = (object) Input::instance()->get(); + break; + + case "post": + $request->params = (object) Input::instance()->post(); + if (isset($_FILES["file"])) { + $request->file = upload::save("file"); + } + break; + } + + $request->method = strtolower($input->server("HTTP_X_GALLERY_REQUEST_METHOD", $method)); + $request->access_token = $input->server("HTTP_X_GALLERY_REQUEST_KEY"); + $request->url = url::abs_current(true); + try { - if (rest::set_active_user($request->access_token)) { - $handler_class = "{$function}_rest"; - $handler_method = $request->method; + rest::set_active_user($request->access_token); - if (!method_exists($handler_class, $handler_method)) { - throw new Rest_Exception(403, "Forbidden"); - } + $handler_class = "{$function}_rest"; + $handler_method = $request->method; - print call_user_func(array($handler_class, $handler_method), $request); + if (!method_exists($handler_class, $handler_method)) { + throw new Rest_Exception("Forbidden", 403); } + + print call_user_func(array($handler_class, $handler_method), $request); } catch (Rest_Exception $e) { - $e->sendHeaders(); + rest::send_headers($e); } } }
\ No newline at end of file diff --git a/modules/rest/helpers/rest.php b/modules/rest/helpers/rest.php index be0644f2..121191f2 100644 --- a/modules/rest/helpers/rest.php +++ b/modules/rest/helpers/rest.php @@ -18,87 +18,57 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class rest_Core { - /** - * Request failed - */ - static function fail($log_message=null) { - if (!empty($log_message)) { - Kohana_Log::add("info", $log_message); - } - // We don't need to save the session for this request + static function reply($data=array()) { Session::abort_save(); - return json_encode(array("status" => "ERROR", "message" => (string)$message)); - } - /** - * Success - */ - static function success($response_data=array(), $message=null) { - $response = array("status" => "OK"); - if (!empty($message)) { - $response["message"] = (string)$message; + if ($data) { + print json_encode($data); } - $response = array_merge($response, $response_data); - - // We don't need to save the session for this request - Session::abort_save(); - return json_encode($response); } - /** - * Validation Error - */ - static function validation_error($error_data) { - $response = array("status" => "VALIDATE_ERROR"); - $response = array_merge($response, array("fields" => $error_data)); - - // We don't need to save the session for this request - Session::abort_save(); - return json_encode($response); - } + static function set_active_user($access_token) { + if (empty($access_token)) { + identity::set_active_user(identity::guest()); + return; + } + $key = ORM::factory("user_access_token") + ->where("access_key", "=", $access_token) + ->find(); - static function normalize_request($args=array()) { - $input = Input::instance(); - $method = strtolower($input->server("REQUEST_METHOD")); - $request = new stdClass(); - foreach (array_keys($input->get()) as $key) { - $request->$key = $input->get($key); + if (!$key->loaded()) { + throw new Rest_Exception("Forbidden", 403); } - if ($method != "get") { - foreach (array_keys($input->post()) as $key) { - $request->$key = $input->post($key); - } - foreach (array_keys($_FILES) as $key) { - $request->$key = $_FILES[$key]; - } + + $user = identity::lookup_user($key->user_id); + if (empty($user)) { + throw new Rest_Exception("Forbidden", 403); } - $request->method = strtolower($input->server("HTTP_X_GALLERY_REQUEST_METHOD", $method)); - $request->access_token = $input->server("HTTP_X_GALLERY_REQUEST_KEY"); - $request->arguments = $args; // Let the rest handler figure out what the arguments mean + identity::set_active_user($user); + } - return $request; + static function send_headers($exception) { + header("HTTP/1.1 " . $exception->getCode() . " " . $exception->getMessage()); } - static function set_active_user($access_token) { - if (empty($access_token)) { - $user = identity::guest(); - } else { - $key = ORM::factory("user_access_token") - ->where("access_key", "=", $access_token) - ->find(); + /** + * Convert a REST url into an object. + * Eg: "http://example.com/gallery3/index.php/rest/gallery/Family/Wedding" -> Item_Model + * + * @param string the fully qualified REST url + * @return mixed the corresponding object (usually a model of some kind) + */ + static function resolve($url) { + $relative_url = substr($url, strlen(url::abs_site("rest"))); + $path = parse_url($relative_url, PHP_URL_PATH); + $components = explode("/", $path, 3); - if ($key->loaded()) { - $user = identity::lookup_user($key->user_id); - if (empty($user)) { - throw new Rest_Exception(403, "Forbidden"); - } - } else { - throw new Rest_Exception(403, "Forbidden"); - } + $class = "$components[1]_rest"; + if (!method_exists($class, "resolve")) { + throw new Kohana_404_Exception($url); } - identity::set_active_user($user); - return true; + + return call_user_func(array($class, "resolve"), !empty($components[2]) ? $components[2] : null); } } diff --git a/modules/rest/libraries/Rest_Exception.php b/modules/rest/libraries/Rest_Exception.php index 905b94a0..596b3712 100644 --- a/modules/rest/libraries/Rest_Exception.php +++ b/modules/rest/libraries/Rest_Exception.php @@ -18,19 +18,4 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Rest_Exception_Core extends Exception { - /** - * Set internal properties. - */ - public function __construct($code, $text) { - parent::__construct("$code $text"); - } - - /** - * Sends the headers, to emulate server behavior. - * - * @return void - */ - public function sendHeaders() { - header('HTTP/1.1 {$this->getMessage()}'); - } -} // End Rest Exception
\ No newline at end of file +}
\ No newline at end of file diff --git a/modules/rest/tests/Rest_Controller_Test.php b/modules/rest/tests/Rest_Controller_Test.php index 83bd9db6..c881583c 100644 --- a/modules/rest/tests/Rest_Controller_Test.php +++ b/modules/rest/tests/Rest_Controller_Test.php @@ -84,7 +84,8 @@ class Rest_Controller_Test extends Unit_Test_Case { try { $this->_call_controller(); } catch (Rest_Exception $e) { - $this->assert_equal("403 Forbidden", $e->getMessage()); + $this->assert_equal(403, $e->getCode()); + $this->assert_equal("Forbidden", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -97,7 +98,8 @@ class Rest_Controller_Test extends Unit_Test_Case { try { $this->_call_controller(); } catch (Rest_Exception $e) { - $this->assert_equal("403 Forbidden", $e->getMessage()); + $this->assert_equal(403, $e->getCode()); + $this->assert_equal("Forbidden", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -109,7 +111,8 @@ class Rest_Controller_Test extends Unit_Test_Case { try { $this->_call_controller(); } catch (Rest_Exception $e) { - $this->assert_equal("403 Forbidden", $e->getMessage()); + $this->assert_equal(403, $e->getCode()); + $this->assert_equal("Forbidden", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -137,7 +140,8 @@ class Rest_Controller_Test extends Unit_Test_Case { try { $this->_call_controller(); } catch (Rest_Exception $e) { - $this->assert_equal("403 Forbidden", $e->getMessage()); + $this->assert_equal(403, $e->getCode()); + $this->assert_equal("Forbidden", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -155,7 +159,8 @@ class Rest_Controller_Test extends Unit_Test_Case { try { $this->_call_controller("rest", explode("/", $photo->relative_url())); } catch (Rest_Exception $e) { - $this->assert_equal("403 Forbidden", $e->getMessage()); + $this->assert_equal(403, $e->getCode()); + $this->assert_equal("Forbidden", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -171,7 +176,8 @@ class Rest_Controller_Test extends Unit_Test_Case { try { $this->_call_controller("rest", explode("/", $photo->relative_url())); } catch (Rest_Exception $e) { - $this->assert_equal("501 Not Implemented", $e->getMessage()); + $this->assert_equal(501, $e->getCode()); + $this->assert_equal("Not Implemented", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -218,7 +224,7 @@ class rest_rest { $response["thumb_url"] = $item->thumb_url(); $response["description"] = $item->description; $response["internet_address"] = $item->slug; - return rest::success(array($item->type => $response), t("Processed")); + return rest::reply(array($item->type => $response)); } } diff --git a/modules/tag/helpers/tag.php b/modules/tag/helpers/tag.php index 8075afe4..d895e08f 100644 --- a/modules/tag/helpers/tag.php +++ b/modules/tag/helpers/tag.php @@ -41,7 +41,7 @@ class tag_Core { } if (!$tag->has($item)) { - if (!$tag->add($item, $tag)) { + if (!$tag->add($item)) { throw new Exception("@todo {$tag->name} WAS_NOT_ADDED_TO {$item->id}"); } $tag->count++; diff --git a/modules/tag/helpers/tag_rest.php b/modules/tag/helpers/tag_rest.php index cd1ca6c6..c1bbf4fb 100644 --- a/modules/tag/helpers/tag_rest.php +++ b/modules/tag/helpers/tag_rest.php @@ -18,143 +18,80 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class tag_rest_Core { - // If no arguments just return all the tags. If 2 or more then it is a path then - // return the tags for that item. But if its only 1, then is it a path or a tag? - // Assume a tag first, if nothing is found then try finding the item. static function get($request) { - $resources = array(); - switch (count($request->arguments)) { - case 0: - $tags = ORM::factory("tag") - ->select("name", "count") - ->order_by("count", "DESC"); - if (!empty($request->limit)) { - $tags->limit($request->limit); - } - if (!empty($request->offset)) { - $tags->offset($request->offset); - } - $resources = array("tags" => array()); - foreach ($tags->find_all() as $row) { - $resources["tags"][] = array("name" => $row->name, "count" => $row->count); - } - break; - case 1: - $resources = tag_rest::_get_items($request); - if (!empty($resources)) { - $resources = array("resources" => $resources); - break; - } - default: - $item = ORM::factory("item") - ->where("relative_url_cache", "=", implode("/", $request->arguments)) - ->viewable() - ->find(); - if ($item->loaded()) { - $resources = array("tags" => tag::item_tags($item)); - } + $tag = rest::resolve($request->url); + $items = array(); + foreach ($tag->items() as $item) { + $items[] = url::abs_site("rest/gallery/" . $item->relative_url()); } - return rest::success($resources); + return rest::reply(array("resource" => $tag->as_array(), "members" => $items)); } static function post($request) { - if (empty($request->arguments) || count($request->arguments) != 1 || empty($request->path)) { - throw new Rest_Exception(400, "Bad request"); + if (empty($request->params->url)) { + throw new Rest_Exception("Bad request", 400); } - $path = $request->path; - $tags = explode(",", $request->arguments[0]); - $item = ORM::factory("item") - ->where("relative_url_cache", "=", $path) - ->viewable() - ->find(); - if (!$item->loaded()) { - throw new Kohana_404_Exception(); - } + $tag = rest::resolve($request->url); + $item = rest::resolve($request->params->url); + access::required("edit", $item); - if (!access::can("edit", $item)) { - throw new Kohana_404_Exception(); - } - - foreach ($tags as $tag) { - tag::add($item, $tag); - } - return rest::success(); + tag::add($item, $tag->name); + return rest::reply(array("url" => url::abs_site("rest/tag/" . rawurlencode($tag->name)))); } static function put($request) { - if (empty($request->arguments[0]) || empty($request->new_name)) { - throw new Rest_Exception(400, "Bad request"); - } + $tag = rest::resolve($request->url); - $name = $request->arguments[0]; + // @todo: what permission should be required to edit a tag? + // for now, require edit at the top level. Perhaps later, just require any edit perms, + // anywhere in the gallery? - $tag = ORM::factory("tag") - ->where("name", "=", $name) - ->find(); - if (!$tag->loaded()) { - throw new Kohana_404_Exception(); + if (isset($request->params->remove)) { + if (!is_array($request->params->remove)) { + throw new Exception("Bad request", 400); + } + + foreach ($request->params->remove as $item_url) { + $item = rest::resolve($item_url); + access::required("edit", $item); + $tag->remove($item); + } } - $tag->name = $request->new_name; - $tag->save(); + if (isset($request->params->name)) { + $tag->name = $request->params->name; + } - return rest::success(); + $tag->save(); + return rest::reply(array("url" => url::abs_site("rest/tag/" . rawurlencode($tag->name)))); } static function delete($request) { - if (empty($request->arguments[0])) { - throw new Rest_Exception(400, "Bad request"); - } - $tags = explode(",", $request->arguments[0]); - if (!empty($request->path)) { - $tag_list = ORM::factory("tag") - ->join("items_tags", "tags.id", "items_tags.tag_id") - ->join("items", "items.id", "items_tags.item_id") - ->where("tags.name", "IN", $tags) - ->where("relative_url_cache", "=", $request->path) - ->viewable() - ->find_all(); - } else { - $tag_list = ORM::factory("tag") - ->where("name", "IN", $tags) - ->find_all(); - } + $tag = rest::resolve($request->url); - foreach ($tag_list as $row) { - $row->delete(); - }; + if (empty($request->params->url)) { + // Delete the tag + $tag->delete(); + return rest::reply(); + } else { + // Remove an item from the tag + $item = rest::resolve($request->params->url); + $tag->remove($item); + $tag->save(); - tag::compact(); - return rest::success(); + tag::compact(); + return rest::reply(array("url" => url::abs_site("rest/tag/" . rawurlencode($tag->name)))); + } } - private static function _get_items($request) { - $tags = explode(",", $request->arguments[0]); - $items = ORM::factory("item") - ->select_distinct("*") - ->join("items_tags", "items.id", "items_tags.item_id") - ->join("tags", "tags.id", "items_tags.tag_id") - ->where("tags.name", "IN", $tags); - if (!empty($request->limit)) { - $items->limit($request->limit); - } - if (!empty($request->offset)) { - $items->offset($request->offset); - } - $resources = array(); - foreach ($items->find_all() as $item) { - $resources[] = array("type" => $item->type, - "has_children" => $item->children_count() > 0, - "path" => $item->relative_url(), - "thumb_url" => $item->thumb_url(true), - "thumb_dimensions" => array("width" => $item->thumb_width, - "height" => $item->thumb_height), - "has_thumb" => $item->has_thumb(), - "title" => $item->title); + static function resolve($tag_name) { + $tag = ORM::factory("tag")->where("name", "=", $tag_name)->find(); + if (!$tag->loaded()) { + throw new Kohana_404_Exception(); } - return $resources; + return $tag; } } diff --git a/modules/tag/helpers/tags_rest.php b/modules/tag/helpers/tags_rest.php new file mode 100644 index 00000000..3ef897fd --- /dev/null +++ b/modules/tag/helpers/tags_rest.php @@ -0,0 +1,48 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class tags_rest_Core { + static function get($request) { + $tags = array(); + foreach (ORM::factory("tag")->find_all() as $tag) { + $tags[$tag->name] = url::abs_site("rest/tags/" . rawurlencode($tag->name)); + } + return rest::reply(array("members" => $tags)); + } + + static function post($request) { + // @todo: what permission should be required to create a tag here? + // for now, require edit at the top level. Perhaps later, just require any edit perms, + // anywhere in the gallery? + access::required("edit", item::root()); + + if (empty($request->params->name)) { + throw new Rest_Exception("Bad Request", 400); + } + + $tag = ORM::factory("tag")->where("name", "=", $request->params->name)->find(); + if (!$tag->loaded()) { + $tag->name = $request->params->name; + $tag->count = 0; + $tag->save(); + } + + return rest::reply(array("url" => url::abs_site("rest/tag/" . rawurlencode($tag->name)))); + } +} diff --git a/modules/tag/tests/Tag_Rest_Helper_Test.php b/modules/tag/tests/Tag_Rest_Helper_Test.php index 4e8dd527..185953ab 100644 --- a/modules/tag/tests/Tag_Rest_Helper_Test.php +++ b/modules/tag/tests/Tag_Rest_Helper_Test.php @@ -133,7 +133,8 @@ class Tag_Rest_Helper_Test extends Unit_Test_Case { try { tag_rest::post($request); } catch (Rest_Exception $e) { - $this->assert_equal("400 Bad request", $e->getMessage()); + $this->assert_equal(400, $e->getCode()); + $this->assert_equal("Bad request", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -191,7 +192,8 @@ class Tag_Rest_Helper_Test extends Unit_Test_Case { try { tag_rest::put($request); } catch (Rest_Exception $e) { - $this->assert_equal("400 Bad request", $e->getMessage()); + $this->assert_equal(400, $e->getCode()); + $this->assert_equal("Bad request", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -202,7 +204,8 @@ class Tag_Rest_Helper_Test extends Unit_Test_Case { try { tag_rest::put($request); } catch (Rest_Exception $e) { - $this->assert_equal("400 Bad request", $e->getMessage()); + $this->assert_equal(400, $e->getCode()); + $this->assert_equal("Bad request", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } @@ -211,7 +214,8 @@ class Tag_Rest_Helper_Test extends Unit_Test_Case { try { tag_rest::put($request); } catch (Rest_Exception $e) { - $this->assert_equal("400 Bad request", $e->getMessage()); + $this->assert_equal(400, $e->getCode()); + $this->assert_equal("Bad request", $e->getMessage()); } catch (Exception $e) { $this->assert_false(true, $e->__toString()); } |