From 5b9030efbd90c464165c80a63c75a78da7cd52d0 Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:04:42 +0200 Subject: [PATCH 1/8] Remove the deprecated tag_item REST resource. --- .../tag/classes/Controller/Rest/TagItem.php | 3 - .../classes/Tag/Controller/Rest/ItemTags.php | 47 ---------- .../classes/Tag/Controller/Rest/TagItem.php | 87 ------------------- .../classes/Tag/Controller/Rest/TagItems.php | 47 ---------- 4 files changed, 184 deletions(-) delete mode 100644 modules/tag/classes/Controller/Rest/TagItem.php delete mode 100644 modules/tag/classes/Tag/Controller/Rest/TagItem.php diff --git a/modules/tag/classes/Controller/Rest/TagItem.php b/modules/tag/classes/Controller/Rest/TagItem.php deleted file mode 100644 index f8d6a8732f..0000000000 --- a/modules/tag/classes/Controller/Rest/TagItem.php +++ /dev/null @@ -1,3 +0,0 @@ - array("item_tags", $id)) : null; } - - /** - * POST a tag_item. This feature is deprecated in v3.1, and is here to maintain - * backward-compatibility with v3.0. - */ - static function post_entity($id, $params) { - list ($t_type, $t_id, $t_params) = Rest::resolve($params["entity"]->tag); - list ($i_type, $i_id, $i_params) = Rest::resolve($params["entity"]->item); - - if (($t_type != "tag") || ($i_type != "item")) { - throw Rest_Exception::factory(404); - } - - $tag = ORM::factory("Tag", $t_id); - $item = ORM::factory("Item", $i_id); - - - Access::required("edit", $item); - if (!$tag->loaded()) { - throw Rest_Exception::factory(404); - } - - Tag::add($item, $tag->name); - - return array("tag_item", "$t_id,$i_id"); - } - - /** - * Overload Controller_Rest::action_post() to block access unless they've sent a - * well-formed tag_item entity POST. If so, add the deprecated header and carry on. - */ - public function action_post() { - if (($entity = $this->request->post("entity")) && - property_exists($entity, "tag") && - property_exists($entity, "item") && - !$this->request->post("members") && - !$this->request->post("relationships")) { - $this->response->headers("x-gallery-api-notice", - "Deprecated from 3.1 - POSTing a tag_item resource to tag_items or item_tags"); - return parent::action_post(); - } - - throw Rest_Exception::factory(400, array("method" => "invalid")); - } } diff --git a/modules/tag/classes/Tag/Controller/Rest/TagItem.php b/modules/tag/classes/Tag/Controller/Rest/TagItem.php deleted file mode 100644 index cc4b093fc3..0000000000 --- a/modules/tag/classes/Tag/Controller/Rest/TagItem.php +++ /dev/null @@ -1,87 +0,0 @@ -loaded() || !$item->loaded() || - !$tag->has("items", $item) || !Access::can("view", $item)) { - throw Rest_Exception::factory(404); - } - - return array("tag" => Rest::url("tag", $tag->id), "item" => Rest::url("item", $item->id)); - } - - /** - * DELETE the tag_item resource. This removes the tag from the item. - */ - static function delete($id, $params) { - $ids = explode(",", $id); - - $tag = ORM::factory("Tag", Arr::get($ids, 0)); - $item = ORM::factory("Item", Arr::get($ids, 1)); - - if (!$tag->loaded() || !$item->loaded() || - !$tag->has("items", $item) || !Access::can("edit", $item)) { - throw Rest_Exception::factory(404); - } - - $tag->remove("items", $item); - $tag->save(); - } - - /** - * Override Controller_Rest::action_get() to add the deprecated notice header. - */ - public function action_get() { - $this->response->headers("x-gallery-api-notice", - "Deprecated from 3.1 - use of tag_item resource"); - return parent::action_get(); - } - - /** - * Override Controller_Rest::action_delete() to add the deprecated notice header. - */ - public function action_delete() { - $this->response->headers("x-gallery-api-notice", - "Deprecated from 3.1 - use of tag_item resource"); - return parent::action_delete(); - } -} diff --git a/modules/tag/classes/Tag/Controller/Rest/TagItems.php b/modules/tag/classes/Tag/Controller/Rest/TagItems.php index 941cc283a3..174dc3539e 100644 --- a/modules/tag/classes/Tag/Controller/Rest/TagItems.php +++ b/modules/tag/classes/Tag/Controller/Rest/TagItems.php @@ -46,9 +46,6 @@ class Tag_Controller_Rest_TagItems extends Controller_Rest { * RELATIONSHIPS: "tag_items" is the "items" relationship of a "tag" resource. * * Note: similar to the standard UI, only admins can PUT or DELETE tag_items. - * - * Deprecated features: POST a "tag_item" entity. This is deprecated from 3.1, - * but functionality is maintained for backward compatibility. */ /** @@ -148,48 +145,4 @@ static function delete($id, $params) { static function relationships($type, $id, $params) { return ($type == "tag") ? array("items" => array("tag_items", $id)) : null; } - - /** - * POST a tag_item. This feature is deprecated in v3.1, and is here to maintain - * backward-compatibility with v3.0. - */ - static function post_entity($id, $params) { - list ($t_type, $t_id, $t_params) = Rest::resolve($params["entity"]->tag); - list ($i_type, $i_id, $i_params) = Rest::resolve($params["entity"]->item); - - if (($t_type != "tag") || ($i_type != "item")) { - throw Rest_Exception::factory(404); - } - - $tag = ORM::factory("Tag", $t_id); - $item = ORM::factory("Item", $i_id); - - - Access::required("edit", $item); - if (!$tag->loaded()) { - throw Rest_Exception::factory(404); - } - - Tag::add($item, $tag->name); - - return array("tag_item", "$t_id,$i_id"); - } - - /** - * Overload Controller_Rest::action_post() to block access unless they've sent a - * well-formed tag_item entity POST. If so, add the deprecated header and carry on. - */ - public function action_post() { - if (($entity = $this->request->post("entity")) && - property_exists($entity, "tag") && - property_exists($entity, "item") && - !$this->request->post("members") && - !$this->request->post("relationships")) { - $this->response->headers("x-gallery-api-notice", - "Deprecated from 3.1 - POSTing a tag_item resource to tag_items or item_tags"); - return parent::action_post(); - } - - throw Rest_Exception::factory(400, array("method" => "invalid")); - } } From 971e0f5e108caeec26a6c23d8097e5916884ee89 Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:04:55 +0200 Subject: [PATCH 2/8] Remove deprecated Model_Item::get_position() function. --- modules/gallery/classes/Gallery/Model/Item.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/modules/gallery/classes/Gallery/Model/Item.php b/modules/gallery/classes/Gallery/Model/Item.php index 8834212bfc..545d3a6862 100644 --- a/modules/gallery/classes/Gallery/Model/Item.php +++ b/modules/gallery/classes/Gallery/Model/Item.php @@ -714,17 +714,6 @@ public function album_cover() { } } - /** - * Find the position of the given child id in this album. The resulting value is 1-indexed, so - * the first child in the album is at position 1. - * - * This method stands as a backward compatibility for gallery 3.0, and will - * be deprecated in version 3.1. - */ - public function get_position($child, $where=array()) { - return Item::get_position($child, $where); - } - /** * Return an tag for the thumbnail. * @param array $extra_attrs Extra attributes to add to the img tag From 6b40799a78f144393f4656e1daa453d33bc93829 Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:05:15 +0200 Subject: [PATCH 3/8] Revise Controller_G2::action_map() to no longer use deprecated "tag_name" route. --- modules/g2_import/classes/G2Import/Controller/G2.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/g2_import/classes/G2Import/Controller/G2.php b/modules/g2_import/classes/G2Import/Controller/G2.php index a2ae5de36a..f911d3ea0b 100644 --- a/modules/g2_import/classes/G2Import/Controller/G2.php +++ b/modules/g2_import/classes/G2Import/Controller/G2.php @@ -44,12 +44,12 @@ public function action_map() { $tag_name = $this->request->query("g2_tagName"); } - if (!$id) { - $this->redirect("tag_name/$tag_name", 301); - } - $tag = ORM::factory("Tag")->where("name", "=", $tag_name)->find(); if ($tag->loaded()) { + if (!$id) { + $this->redirect($tag->abs_url(), 301); + } + Item::set_display_context_callback("Controller_Tags::get_display_context", $tag->id); // We want to show the item as part of the tag virtual album. Most of this code is below; we'll // change $path and $view to let it fall through From 18f43860368bfd6766d5e644d0f6f749064a6176 Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:05:28 +0200 Subject: [PATCH 4/8] Controller_Rest_User - change 403 --> 404. --- modules/gallery/classes/Gallery/Controller/Rest/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/classes/Gallery/Controller/Rest/User.php b/modules/gallery/classes/Gallery/Controller/Rest/User.php index 1cb55c0663..6a75142740 100644 --- a/modules/gallery/classes/Gallery/Controller/Rest/User.php +++ b/modules/gallery/classes/Gallery/Controller/Rest/User.php @@ -35,7 +35,7 @@ class Gallery_Controller_Rest_User extends Controller_Rest { static function get_entity($id, $params) { $user = Identity::lookup_user($id); if (!Identity::can_view_profile($user)) { - throw Rest_Exception::factory(403); + throw Rest_Exception::factory(404); } // Add fields from a whitelist. From 7692c0f4bb25a06abb9d40c7af6dbef557cc630c Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:06:02 +0200 Subject: [PATCH 5/8] Add Controller_Rest_UserComments / UserItems resources. --- .../classes/Controller/Rest/UserComments.php | 3 + .../classes/Controller/Rest/UserItems.php | 3 + .../Gallery/Controller/Rest/UserComments.php | 120 +++++++++++++++ .../Gallery/Controller/Rest/UserItems.php | 139 ++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 modules/gallery/classes/Controller/Rest/UserComments.php create mode 100644 modules/gallery/classes/Controller/Rest/UserItems.php create mode 100644 modules/gallery/classes/Gallery/Controller/Rest/UserComments.php create mode 100644 modules/gallery/classes/Gallery/Controller/Rest/UserItems.php diff --git a/modules/gallery/classes/Controller/Rest/UserComments.php b/modules/gallery/classes/Controller/Rest/UserComments.php new file mode 100644 index 0000000000..8cc3878583 --- /dev/null +++ b/modules/gallery/classes/Controller/Rest/UserComments.php @@ -0,0 +1,3 @@ +comments" since we have no guarantee + // that the user is an ORM model with an established relationship. + $members = ORM::factory("Comment") + ->where("author_id", "=", $user->id) + ->order_by("created", "DESC") + ->limit(Arr::get($params, "num", static::$default_params["num"])) + ->offset(Arr::get($params, "start", static::$default_params["start"])); + + $data = array(); + foreach ($members->find_all() as $member) { + $data[] = array("comment", $member->id); + } + + return $data; + } + + /** + * PUT the comment members of the user_comments resource. This replaces the comments list + * with this one, and removes (but doesn't add) comments as needed. This is only for admins. + * @see Controller_Rest_ItemComments::put_members() + */ + static function put_members($id, $params) { + if (!Identity::active_user()->admin) { + throw Rest_Exception::factory(403); + } + + $user = Identity::lookup_user($id); + if (!Identity::can_view_profile($user)) { + throw Rest_Exception::factory(404); + } + + // Resolve our members list into an array of comment ids. + $member_ids = Rest::resolve_members($params["members"], + function($type, $id, $params, $data) { + $comment = ORM::factory("Comment", $id); + return (($type == "comment") && ($comment->author_id == $data)) ? $id : false; + }, $user->id); + + // Delete any comments that are not in the list. + foreach (ORM::factory("Comment")->where("author_id", "=", $user->id)->find_all() as $comment) { + if (!in_array($comment->id, $member_ids)) { + $comment->delete(); + } + } + } + + /** + * DELETE removes all of the user's comments, and is only for admins. + */ + static function delete($id, $params) { + if (!Identity::active_user()->admin) { + throw Rest_Exception::factory(403); + } + + $user = Identity::lookup_user($id); + if (!Identity::can_view_profile($user)) { + throw Rest_Exception::factory(404); + } + + // Delete all of the user's comments. + foreach (ORM::factory("Comment")->where("author_id", "=", $user->id)->find_all() as $comment) { + $comment->delete(); + } + } + + /** + * Return the relationship established by user_comments. This adds "comments" + * as a relationship of an "user" resource. + */ + static function relationships($type, $id, $params) { + return ($type == "user") ? array("comments" => array("user_comments", $id)) : null; + } +} diff --git a/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php b/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php new file mode 100644 index 0000000000..64ab60e0f9 --- /dev/null +++ b/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php @@ -0,0 +1,139 @@ + + * Only return items where the name contains this substring. + * type= + * Limit the type to types in this list (e.g. "type=photo,movie"). + * Also limits the types returned in the member collections (i.e. sub-albums). + * @see Controller_Rest_UserItems::get_members() + * + * PUT can accept the following post parameters: + * members + * Replace the collection of items by the user with this list (remove only, no add) + * @see Controller_Rest_UserItems::put_members() + * + * DELETE removes all of the user's items (no parameters accepted). + * @see Controller_Rest_UserItems::delete() + * + * RELATIONSHIPS: "user_items" is the "items" relationship of a "user" resource. + * + * Note: similar to the standard UI, only admins can PUT or DELETE user_items. + */ + + /** + * GET the item members of the user_items resource. + * @see Controller_Rest_Items::get_members(). + */ + static function get_members($id, $params) { + $user = Identity::lookup_user($id); + if (!Identity::can_view_profile($user)) { + throw Rest_Exception::factory(404); + } + + // Note: we can't simply do "$user->items" since we have no guarantee + // that the user is an ORM model with an established relationship. + $members = ORM::factory("Item")->viewable() + ->where("owner_id", "=", $user->id) + ->limit(Arr::get($params, "num", static::$default_params["num"])) + ->offset(Arr::get($params, "start", static::$default_params["start"])); + + if (isset($params["type"])) { + $members->where("type", "IN", $params["type"]); + } + + if (isset($params["name"])) { + $members->where("name", "LIKE", "%" . Database::escape_for_like($params["name"]) . "%"); + } + + $data = array(); + foreach ($members->find_all() as $member) { + $data[] = array("item", $member->id); + } + + return $data; + } + + /** + * PUT the item members of the user_items resource. This replaces the items list + * with this one, and removes (but doesn't add) items as needed. This is only for admins. + */ + static function put_members($id, $params) { + if (!Identity::active_user()->admin) { + throw Rest_Exception::factory(403); + } + + $user = Identity::lookup_user($id); + if (!Identity::can_view_profile($user)) { + throw Rest_Exception::factory(404); + } + + // Resolve our members list into an array of item ids. + $member_ids = Rest::resolve_members($params["members"], + function($type, $id, $params, $data) { + $item = ORM::factory("Item", $id); + return (($type == "item") && ($item->owner_id == $data)) ? $id : false; + }, $user->id); + + // Delete any items that are not in the list. + foreach (ORM::factory("Item") + ->where("owner_id", "=", $user->id) + ->where("id", "<>", Item::root()->id) // If root included, Model_Item will throw a 500. + ->find_all() as $item) { + if (!in_array($item->id, $member_ids)) { + $item->delete(); + } + } + } + + /** + * DELETE removes all of the user's items, and is only for admins. + */ + static function delete($id, $params) { + if (!Identity::active_user()->admin) { + throw Rest_Exception::factory(403); + } + + $user = Identity::lookup_user($id); + if (!Identity::can_view_profile($user)) { + throw Rest_Exception::factory(404); + } + + // Delete all of the user's items. + foreach (ORM::factory("Item") + ->where("owner_id", "=", $user->id) + ->where("id", "<>", Item::root()->id) // If root included, Model_Item will throw a 500. + ->find_all() as $item) { + $item->delete(); + } + } + + /** + * Return the relationship established by user_items. This adds "items" + * as a relationship of a "user" resource. + */ + static function relationships($type, $id, $params) { + return ($type == "user") ? array("items" => array("user_items", $id)) : null; + } +} From 76e078dac385a918370f392b49f14e03ad1e97fc Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:06:35 +0200 Subject: [PATCH 6/8] Clean up some REST-related comments. --- .../comment/classes/Comment/Controller/Rest/ItemComments.php | 5 +++-- modules/gallery/classes/Gallery/Controller/Rest/User.php | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/comment/classes/Comment/Controller/Rest/ItemComments.php b/modules/comment/classes/Comment/Controller/Rest/ItemComments.php index aaa9028c87..c6c5206cf3 100644 --- a/modules/comment/classes/Comment/Controller/Rest/ItemComments.php +++ b/modules/comment/classes/Comment/Controller/Rest/ItemComments.php @@ -19,14 +19,14 @@ */ class Comment_Controller_Rest_ItemComments extends Controller_Rest { /** - * This resource represents a collection of tag resources on a specified item. + * This resource represents a collection of comment resources on a specified item. * * GET displays the collection of comments (no parameters accepted). * @see Controller_Rest_ItemComments::get_members() * * PUT can accept the following post parameters: * members - * Replace the collection of comment on the item with this list (remove only, no add) + * Replace the collection of comments on the item with this list (remove only, no add) * @see Controller_Rest_ItemComments::put_members() * * DELETE removes all comments from the item (no parameters accepted). @@ -59,6 +59,7 @@ static function get_members($id, $params) { /** * PUT the comment members of the item_comments resource. This replaces the comments list * with this one, and removes (but doesn't add) comments as needed. This is only for admins. + * @see Controller_Rest_UserComments::put_members() */ static function put_members($id, $params) { if (!Identity::active_user()->admin) { diff --git a/modules/gallery/classes/Gallery/Controller/Rest/User.php b/modules/gallery/classes/Gallery/Controller/Rest/User.php index 6a75142740..6546ac42e4 100644 --- a/modules/gallery/classes/Gallery/Controller/Rest/User.php +++ b/modules/gallery/classes/Gallery/Controller/Rest/User.php @@ -19,7 +19,7 @@ */ class Gallery_Controller_Rest_User extends Controller_Rest { /** - * This read-only resource represents a user. + * This read-only resource represents a user profile. * * GET can accept the following query parameters: * show=self From e39a6366dc8f95373e2215224cde8a5c5db3609e Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:16:00 +0200 Subject: [PATCH 7/8] Make Controller_Rest_UserItems::put_members() / delete() more careful with order --- modules/gallery/classes/Gallery/Controller/Rest/UserItems.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php b/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php index 64ab60e0f9..592116bc06 100644 --- a/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php +++ b/modules/gallery/classes/Gallery/Controller/Rest/UserItems.php @@ -100,6 +100,7 @@ function($type, $id, $params, $data) { foreach (ORM::factory("Item") ->where("owner_id", "=", $user->id) ->where("id", "<>", Item::root()->id) // If root included, Model_Item will throw a 500. + ->order_by("left_ptr", "DESC") // Delete children before parents. ->find_all() as $item) { if (!in_array($item->id, $member_ids)) { $item->delete(); @@ -124,6 +125,7 @@ static function delete($id, $params) { foreach (ORM::factory("Item") ->where("owner_id", "=", $user->id) ->where("id", "<>", Item::root()->id) // If root included, Model_Item will throw a 500. + ->order_by("left_ptr", "DESC") // Delete children before parents. ->find_all() as $item) { $item->delete(); } From c9bd7257af57854527deb32c14f76b845722bbd5 Mon Sep 17 00:00:00 2001 From: shadlaws Date: Fri, 14 Jun 2013 09:38:15 +0200 Subject: [PATCH 8/8] Make GET /gallery3/rest return 200 if guest access is allowed (and 403 if not). --- .../Rest/Controller/Rest/AccessKey.php | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/rest/classes/Rest/Controller/Rest/AccessKey.php b/modules/rest/classes/Rest/Controller/Rest/AccessKey.php index 3a838c6cf3..5ee4b646be 100644 --- a/modules/rest/classes/Rest/Controller/Rest/AccessKey.php +++ b/modules/rest/classes/Rest/Controller/Rest/AccessKey.php @@ -19,19 +19,27 @@ */ class Rest_Controller_Rest_AccessKey extends Controller_Rest { public function check_auth($auth) { - // Check login using "user" and "password" fields in POST. Fire a 403 Forbidden if it fails. - if (!Validation::factory($this->request->post()) - ->rule("user", "Auth::validate_login", array(":validation", ":data", "user", "password")) - ->check()) { - throw Rest_Exception::factory(403); - } + if ($this->request->method() != HTTP_Request::GET) { + // Check login using "user" and "password" fields in POST. Fire a 403 Forbidden if it fails. + if (!Validation::factory($this->request->post()) + ->rule("user", "Auth::validate_login", array(":validation", ":data", "user", "password")) + ->check()) { + throw Rest_Exception::factory(403); + } - // Set the access key - $this->request->headers("x-gallery-request-key", Rest::access_key()); + // Set the access key + $this->request->headers("x-gallery-request-key", Rest::access_key()); + } return parent::check_auth($auth); } + public function action_get() { + // We want to return an empty response with either status 200 or 403, depending on if guest + // access is allowed. Since Controller_Rest::check_auth() would have already fired a 403 + // if a login was required, we have nothing left to do here - this will return a 200. + } + public function action_post() { // If we got here, login was already successful - simply return the key. $this->rest_response = Rest::access_key();