summaryrefslogtreecommitdiff
path: root/modules/rest
diff options
context:
space:
mode:
Diffstat (limited to 'modules/rest')
-rw-r--r--modules/rest/controllers/rest.php75
-rw-r--r--modules/rest/helpers/rest.php156
-rw-r--r--modules/rest/libraries/Rest_Exception.php20
-rw-r--r--modules/rest/tests/Rest_Controller_Test.php249
4 files changed, 225 insertions, 275 deletions
diff --git a/modules/rest/controllers/rest.php b/modules/rest/controllers/rest.php
index 26e5b31a..ba996b84 100644
--- a/modules/rest/controllers/rest.php
+++ b/modules/rest/controllers/rest.php
@@ -18,51 +18,54 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class Rest_Controller extends Controller {
- public function access_key() {
- try {
- $request = (object)Input::instance()->get();
- if (empty($request->user) || empty($request->password)) {
- throw new Rest_Exception(403, "Forbidden");
- }
+ public function index() {
+ $username = Input::instance()->post("user");
+ $password = Input::instance()->post("password");
- $user = identity::lookup_user_by_name($request->user);
- if (empty($user)) {
- 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);
+ }
- if (!identity::is_correct_password($user, $request->password)) {
- throw new Rest_Exception(403, "Forbidden");
- }
+ $key = rest::get_access_token($user->id);
+ rest::reply($key->access_key);
+ }
+
+ public function __call($function, $args) {
+ $input = Input::instance();
+ switch ($method = strtolower($input->server("REQUEST_METHOD"))) {
+ case "get":
+ $request->params = (object) $input->get();
+ break;
- $key = ORM::factory("user_access_token")
- ->where("user_id", "=", $user->id)
- ->find();
- if (!$key->loaded()) {
- $key->user_id = $user->id;
- $key->access_key = md5($user->name . rand());
- $key->save();
+ case "post":
+ $request->params = (object) $input->post();
+ if (isset($_FILES["file"])) {
+ $request->file = upload::save("file");
}
- print rest::success(array("token" => $key->access_key));
- } catch (Rest_Exception $e) {
- $e->sendHeaders();
+ break;
}
- }
- public function __call($function, $args) {
- $request = rest::normalize_request($args);
- try {
- if (rest::set_active_user($request->access_token)) {
- $handler_class = "{$function}_rest";
- $handler_method = $request->method;
+ $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);
+
+ 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("Bad Request", 400);
+ }
+
+ try {
+ print rest::reply(call_user_func(array($handler_class, $handler_method), $request));
+ } catch (ORM_Validation_Exception $e) {
+ foreach ($e->validation->errors() as $key => $value) {
+ $msgs[] = "$key: $value";
}
- } catch (Rest_Exception $e) {
- $e->sendHeaders();
+ throw new Rest_Exception("Bad Request: " . join(", ", $msgs), 400);
}
}
} \ No newline at end of file
diff --git a/modules/rest/helpers/rest.php b/modules/rest/helpers/rest.php
index be0644f2..0d2ec9d4 100644
--- a/modules/rest/helpers/rest.php
+++ b/modules/rest/helpers/rest.php
@@ -18,87 +18,119 @@
* 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));
+
+ if ($data) {
+ if (Input::instance()->get("output") == "html") {
+ header("Content-type: text/html");
+ $html = preg_replace(
+ "#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t<]*)#ise", "'\\1<a href=\"\\2\" >\\2</a>'",
+ print_r($data, 1));
+ print "<pre>$html</pre>";
+ } else {
+ header("Content-type: application/json");
+ print json_encode($data);
+ }
+ }
}
- /**
- * Success
- */
- static function success($response_data=array(), $message=null) {
- $response = array("status" => "OK");
- if (!empty($message)) {
- $response["message"] = (string)$message;
+ static function set_active_user($access_token) {
+ if (empty($access_token)) {
+ identity::set_active_user(identity::guest());
+ return;
}
- $response = array_merge($response, $response_data);
- // We don't need to save the session for this request
- Session::abort_save();
- return json_encode($response);
+ $key = ORM::factory("user_access_token")
+ ->where("access_key", "=", $access_token)
+ ->find();
+
+ if (!$key->loaded()) {
+ throw new Rest_Exception("Forbidden", 403);
+ }
+
+ $user = identity::lookup_user($key->user_id);
+ if (empty($user)) {
+ throw new Rest_Exception("Forbidden", 403);
+ }
+
+ identity::set_active_user($user);
}
- /**
- * Validation Error
- */
- static function validation_error($error_data) {
- $response = array("status" => "VALIDATE_ERROR");
- $response = array_merge($response, array("fields" => $error_data));
+ static function get_access_token($user_id) {
+ $key = ORM::factory("user_access_token")
+ ->where("user_id", "=", $user_id)
+ ->find();
- // We don't need to save the session for this request
- Session::abort_save();
- return json_encode($response);
+ if (!$key->loaded()) {
+ $key->user_id = $user_id;
+ $key->access_key = md5(rand());
+ $key->save();
+ }
+ return $key;
}
+ /**
+ * Convert a REST url into an object.
+ * Eg:
+ * http://example.com/gallery3/index.php/rest/item/35 -> Item_Model
+ * http://example.com/gallery3/index.php/rest/tag/16 -> Tag_Model
+ * http://example.com/gallery3/index.php/rest/tagged_item/1,16 -> [Tag_Model, 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);
- 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 (count($components) != 3) {
+ throw new Kohana_404_Exception($url);
}
- 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];
- }
+
+ $class = "$components[1]_rest";
+ if (!method_exists($class, "resolve")) {
+ throw new Kohana_404_Exception($url);
}
- $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
+ return call_user_func(array($class, "resolve"), !empty($components[2]) ? $components[2] : null);
+ }
- return $request;
+ /**
+ * Return an absolute url used for REST resource location.
+ * @param string resource type (eg, "item", "tag")
+ * @param object resource
+ */
+ static function url() {
+ $args = func_get_args();
+ $resource_type = array_shift($args);
+
+ $class = "{$resource_type}_rest";
+ if (!method_exists($class, "url")) {
+ throw new Rest_Exception("Bad Request", 400);
+ }
+
+ $url = call_user_func_array(array($class, "url"), $args);
+ if (Input::instance()->get("output") == "html") {
+ $url .= "?output=html";
+ }
+ return $url;
}
- 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();
-
- if ($key->loaded()) {
- $user = identity::lookup_user($key->user_id);
- if (empty($user)) {
- throw new Rest_Exception(403, "Forbidden");
+ static function relationships($resource_type, $resource) {
+ $results = array();
+ foreach (module::active() as $module) {
+ foreach (glob(MODPATH . "{$module->name}/helpers/*_rest.php") as $filename) {
+ $class = str_replace(".php", "", basename($filename));
+ if (method_exists($class, "relationships")) {
+ $results = array_merge(
+ $results,
+ call_user_func(array($class, "relationships"), $resource_type, $resource));
}
- } else {
- throw new Rest_Exception(403, "Forbidden");
}
}
- identity::set_active_user($user);
- return true;
+
+ return $results;
}
}
diff --git a/modules/rest/libraries/Rest_Exception.php b/modules/rest/libraries/Rest_Exception.php
index 905b94a0..c3548b7e 100644
--- a/modules/rest/libraries/Rest_Exception.php
+++ b/modules/rest/libraries/Rest_Exception.php
@@ -17,20 +17,14 @@
* along with this program; if not, write to the Free Software
* 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");
+class Rest_Exception_Core extends Kohana_Exception {
+ public function __construct($message, $code) {
+ parent::__construct($message, null, $code);
}
- /**
- * Sends the headers, to emulate server behavior.
- *
- * @return void
- */
public function sendHeaders() {
- header('HTTP/1.1 {$this->getMessage()}');
+ if (!headers_sent()) {
+ header("HTTP/1.1 " . $this->getCode() . " " . $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..5e624112 100644
--- a/modules/rest/tests/Rest_Controller_Test.php
+++ b/modules/rest/tests/Rest_Controller_Test.php
@@ -17,208 +17,129 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
-class Rest_Controller_Test extends Unit_Test_Case {
+class Rest_Controller_Test extends Gallery_Unit_Test_Case {
public function setup() {
$this->_save = array($_GET, $_POST, $_SERVER);
}
- private function _create_user() {
- if (empty($this->_user)) {
- $this->_user = identity::create_user("access_test" . rand(), "Access Test", "password");
- $this->_key = ORM::factory("user_access_token");
- $this->_key->access_key = md5($this->_user->name . rand());
- $this->_key->user_id = $this->_user->id;
- $this->_key->save();
- identity::set_active_user($this->_user);
- }
- return array($this->_key->access_key, $this->_user);
- }
-
public function teardown() {
list($_GET, $_POST, $_SERVER) = $this->_save;
- if (!empty($this->_user)) {
- try {
- $this->_user->delete();
- } catch (Exception $e) { }
- }
- }
-
- private function _create_image($parent=null) {
- $filename = MODPATH . "gallery/tests/test.jpg";
- $image_name = "image_" . rand();
- if (empty($parent)) {
- $parent = ORM::factory("item", 1);
- }
- return photo::create($parent, $filename, "$image_name.jpg", $image_name);
}
- public function rest_access_key_exists_test() {
- list ($access_key, $user) = $this->_create_user();
- $_SERVER["REQUEST_METHOD"] = "GET";
- $_GET["user"] = $user->name;;
- $_GET["password"] = "password";
+ public function login_test() {
+ $user = test::random_user("password");
- $this->assert_equal(
- json_encode(array("status" => "OK", "token" => $access_key)),
- $this->_call_controller());
- }
+ // There's no access key at first
+ $this->assert_false(
+ ORM::factory("user_access_token")->where("user_id", "=", $user->id)->find()->loaded());
- public function rest_access_key_generated_test() {
- list ($access_key, $user) = $this->_create_user();
- ORM::factory("user_access_token")
- ->where("access_key", $access_key)
- ->delete();
- $_SERVER["REQUEST_METHOD"] = "GET";
- $_GET["user"] = $user->name;
- $_GET["password"] = "password";
+ $_POST["user"] = $user->name;
+ $_POST["password"] = "password";
- $results = json_decode($this->_call_controller());
+ $response = test::call_and_capture(array(new Rest_Controller(), "index"));
+ $expected =
+ ORM::factory("user_access_token")->where("user_id", "=", $user->id)->find()->access_key;
- $this->assert_equal("OK", $results->status);
- $this->assert_false(empty($results->token));
+ // Now there is an access key, and it was returned
+ $this->assert_equal(json_encode($expected), $response);
}
- public function rest_access_key_no_parameters_test() {
- $_SERVER["REQUEST_METHOD"] = "GET";
+ public function login_failed_test() {
+ $user = test::random_user("password");
try {
- $this->_call_controller();
+ $_POST["user"] = $user->name;
+ $_POST["password"] = "WRONG PASSWORD";
+ test::call_and_capture(array(new Rest_Controller(), "index"));
} catch (Rest_Exception $e) {
- $this->assert_equal("403 Forbidden", $e->getMessage());
- } catch (Exception $e) {
- $this->assert_false(true, $e->__toString());
+ $this->assert_equal(403, $e->getCode());
+ return;
}
- }
-
- public function rest_access_key_user_not_found_test() {
- $_SERVER["REQUEST_METHOD"] = "POST";
- $_POST["request"] = json_encode(array("user" => "access_test2", "password" => "password"));
- try {
- $this->_call_controller();
- } catch (Rest_Exception $e) {
- $this->assert_equal("403 Forbidden", $e->getMessage());
- } catch (Exception $e) {
- $this->assert_false(true, $e->__toString());
- }
+ $this->assert_true(false, "Shouldn't get here");
}
- public function rest_access_key_invalid_password_test() {
- $_SERVER["REQUEST_METHOD"] = "POST";
+ public function get_test() {
+ $_SERVER["REQUEST_METHOD"] = "GET";
+ $_GET["key"] = "value";
- try {
- $this->_call_controller();
- } catch (Rest_Exception $e) {
- $this->assert_equal("403 Forbidden", $e->getMessage());
- } catch (Exception $e) {
- $this->assert_false(true, $e->__toString());
- }
+ $this->assert_array_equal_to_json(
+ array("params" => array("key" => "value"),
+ "method" => "get",
+ "access_token" => null,
+ "url" => "http://./index.php/gallery_unit_test"),
+ test::call_and_capture(array(new Rest_Controller(), "mock")));
}
- public function rest_get_resource_no_request_key_test() {
- $_SERVER["REQUEST_METHOD"] = "GET";
- $photo = $this->_create_image();
-
- $this->assert_equal(
- json_encode(array("status" => "OK", "message" => (string)t("Processed"),
- "photo" => array("path" => $photo->relative_url(),
- "title" => $photo->title,
- "thumb_url" => $photo->thumb_url(),
- "description" => $photo->description,
- "internet_address" => $photo->slug))),
- $this->_call_controller("rest", explode("/", $photo->relative_url())));
- }
+ public function get_with_access_key_test() {
+ $key = rest::get_access_token(1); // admin user
- public function rest_get_resource_invalid_key_test() {
- list ($access_key, $user) = $this->_create_user();
- $_SERVER["HTTP_X_GALLERY_REQUEST_KEY"] = md5($access_key); // screw up the access key;
$_SERVER["REQUEST_METHOD"] = "GET";
+ $_SERVER["HTTP_X_GALLERY_REQUEST_KEY"] = $key->access_key;
+ $_GET["key"] = "value";
- try {
- $this->_call_controller();
- } catch (Rest_Exception $e) {
- $this->assert_equal("403 Forbidden", $e->getMessage());
- } catch (Exception $e) {
- $this->assert_false(true, $e->__toString());
- }
+ $this->assert_array_equal_to_json(
+ array("params" => array("key" => "value"),
+ "method" => "get",
+ "access_token" => $key->access_key,
+ "url" => "http://./index.php/gallery_unit_test"),
+ test::call_and_capture(array(new Rest_Controller(), "mock")));
}
- public function rest_get_resource_no_user_for_key_test() {
- list ($access_key, $user) = $this->_create_user();
- $_SERVER["REQUEST_METHOD"] = "GET";
- $_SERVER["HTTP_X_GALLERY_REQUEST_KEY"] = $access_key;
+ public function post_test() {
+ $_SERVER["REQUEST_METHOD"] = "POST";
+ $_POST["key"] = "value";
- $user->delete();
+ $this->assert_array_equal_to_json(
+ array("params" => array("key" => "value"),
+ "method" => "post",
+ "access_token" => null,
+ "url" => "http://./index.php/gallery_unit_test"),
+ test::call_and_capture(array(new Rest_Controller(), "mock")));
+ }
- $photo = $this->_create_image();
+ public function put_test() {
+ $_SERVER["REQUEST_METHOD"] = "POST";
+ $_SERVER["HTTP_X_GALLERY_REQUEST_METHOD"] = "put";
+ $_POST["key"] = "value";
- try {
- $this->_call_controller("rest", explode("/", $photo->relative_url()));
- } catch (Rest_Exception $e) {
- $this->assert_equal("403 Forbidden", $e->getMessage());
- } catch (Exception $e) {
- $this->assert_false(true, $e->__toString());
- }
+ $this->assert_array_equal_to_json(
+ array("params" => array("key" => "value"),
+ "method" => "put",
+ "access_token" => null,
+ "url" => "http://./index.php/gallery_unit_test"),
+ test::call_and_capture(array(new Rest_Controller(), "mock")));
}
- public function rest_get_resource_no_handler_test() {
- list ($access_key, $user) = $this->_create_user();
- $_SERVER["REQUEST_METHOD"] = "GET";
- $_SERVER["HTTP_X_GALLERY_REQUEST_KEY"] = $access_key;
- $_SERVER["HTTP_X_GALLERY_REQUEST_METHOD"] = "PUT";
- $photo = $this->_create_image();
+ public function delete_test() {
+ $_SERVER["REQUEST_METHOD"] = "POST";
+ $_SERVER["HTTP_X_GALLERY_REQUEST_METHOD"] = "delete";
+ $_POST["key"] = "value";
+ $this->assert_array_equal_to_json(
+ array("params" => array("key" => "value"),
+ "method" => "delete",
+ "access_token" => null,
+ "url" => "http://./index.php/gallery_unit_test"),
+ test::call_and_capture(array(new Rest_Controller(), "mock")));
+ }
+
+ public function bogus_method_test() {
+ $_SERVER["REQUEST_METHOD"] = "POST";
+ $_SERVER["HTTP_X_GALLERY_REQUEST_METHOD"] = "BOGUS";
try {
- $this->_call_controller("rest", explode("/", $photo->relative_url()));
- } catch (Rest_Exception $e) {
- $this->assert_equal("501 Not Implemented", $e->getMessage());
+ test::call_and_capture(array(new Rest_Controller(), "mock"));
} catch (Exception $e) {
- $this->assert_false(true, $e->__toString());
+ $this->assert_equal(400, $e->getCode());
+ return;
}
- }
-
- public function rest_get_resource_test() {
- list ($access_key, $user) = $this->_create_user();
- $_SERVER["REQUEST_METHOD"] = "GET";
- $_SERVER["HTTP_X_GALLERY_REQUEST_KEY"] = $access_key;
-
- $photo = $this->_create_image();
- $this->assert_equal(
- json_encode(array("status" => "OK", "message" => (string)t("Processed"),
- "photo" => array("path" => $photo->relative_url(),
- "title" => $photo->title,
- "thumb_url" => $photo->thumb_url(),
- "description" => $photo->description,
- "internet_address" => $photo->slug))),
- $this->_call_controller("rest", explode("/", $photo->relative_url())));
- }
-
- private function _call_controller($method="access_key", $arg=null) {
- $controller = new Rest_Controller();
-
- ob_start();
- call_user_func_array(array($controller, $method), $arg);
- $results = ob_get_contents();
- ob_end_clean();
-
- return $results;
+ $this->assert_true(false, "Shouldn't get here");
}
}
-class rest_rest {
- static $request = null;
-
- static function get($request) {
- self::$request = $request;
- $item = ORM::factory("item")
- ->where("relative_url_cache", "=", implode("/", $request->arguments))
- ->find();
- $response["path"] = $item->relative_url();
- $response["title"] = $item->title;
- $response["thumb_url"] = $item->thumb_url();
- $response["description"] = $item->description;
- $response["internet_address"] = $item->slug;
- return rest::success(array($item->type => $response), t("Processed"));
- }
-
-}
+class mock_rest {
+ function get($request) { return $request; }
+ function post($request) { return $request; }
+ function put($request) { return $request; }
+ function delete($request) { return $request; }
+} \ No newline at end of file