diff options
author | Benoit Tremblay <bentremblay@benoit-tremblays-macbook-pro.local> | 2009-09-25 18:52:07 (GMT) |
---|---|---|
committer | Benoit Tremblay <bentremblay@benoit-tremblays-macbook-pro.local> | 2009-09-25 18:52:07 (GMT) |
commit | 40b90e363e538112e2f64863229b214fbb2b698c (patch) | |
tree | 57659f376c985dba73d86969d4967042f331034b /site | |
parent | 1927c85b30c48c09a069443c0e69dff752d3c858 (diff) |
Tutorius API code
Diffstat (limited to 'site')
-rw-r--r-- | site/app/controllers/components/tutorius.php | 131 | ||||
-rw-r--r-- | site/app/controllers/tutorius_api_controller.php | 896 | ||||
-rw-r--r-- | site/app/views/tutorius_api/error.thtml | 43 | ||||
-rw-r--r-- | site/app/views/tutorius_api/index.thtml | 62 | ||||
-rw-r--r-- | site/app/views/tutorius_api/register_new_user.thtml | 44 | ||||
-rw-r--r-- | site/app/views/tutorius_api/review.thtml | 52 |
6 files changed, 1228 insertions, 0 deletions
diff --git a/site/app/controllers/components/tutorius.php b/site/app/controllers/components/tutorius.php new file mode 100644 index 0000000..25d9496 --- /dev/null +++ b/site/app/controllers/components/tutorius.php @@ -0,0 +1,131 @@ +<?php +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is addons.mozilla.org site. + * + * The Initial Developer of the Original Code is + * Justin Scott <fligtar@gmail.com>. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Frederic Wenzel <fwenzel@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +class TutoriusComponent extends Object { + var $controller; + var $platforms; + var $applications; + var $versionIds; + var $navCategories; + + /** + * Save a reference to the controller on startup + * @param object &$controller the controller using this component + */ + function startup(&$controller) { + $this->controller =& $controller; + + } + + /** + * Given a base URL and a relative URL, produce an absolute URL. + * see: http://us.php.net/manual/en/function.parse-url.php#76979 + */ + function resolveUrl($base, $url) { + if (!strlen($base)) return $url; + if (!strlen($url)) return $base; + if (preg_match('!^[a-z]+:!i', $url)) return $url; + + $base = parse_url($base); + if ($url{0} == "#") { + $base['fragment'] = substr($url, 1); + return $this->unparseUrl($base); + } + unset($base['fragment']); + unset($base['query']); + + if (substr($url, 0, 2) == "//") { + return $this->unparseUrl(array( + 'scheme'=>$base['scheme'], + 'path'=>substr($url,2), + )); + } else if ($url{0} == "/") { + $base['path'] = $url; + } else { + $path = explode('/', $base['path']); + $url_path = explode('/', $url); + array_pop($path); + $end = array_pop($url_path); + foreach ($url_path as $segment) { + if ($segment == '.') { + // skip + } else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') { + array_pop($path); + } else { + $path[] = $segment; + } + } + if ($end == '.') { + $path[] = ''; + } else if ($end == '..' && $path && $path[sizeof($path)-1] != '..') { + $path[sizeof($path)-1] = ''; + } else { + $path[] = $end; + } + $base['path'] = join('/', $path); + + } + return $this->unparseUrl($base); + } + + /** + * Given the results of parse_url, produce a URL. + * see: http://us.php.net/manual/en/function.parse-url.php#85963 + */ + function unparseUrl($parsed) + { + if (!is_array($parsed)) return false; + + $uri = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '' : '//') : ''; + $uri .= isset($parsed['user']) ? $parsed['user'].(isset($parsed['pass']) ? ':'.$parsed['pass'] : '').'@' : ''; + $uri .= isset($parsed['host']) ? $parsed['host'] : ''; + $uri .= isset($parsed['port']) ? ':'.$parsed['port'] : ''; + + if (isset($parsed['path'])) { + $uri .= (substr($parsed['path'], 0, 1) == '/') ? + $parsed['path'] : ((!empty($uri) ? '/' : '' ) . $parsed['path']); + } + + $uri .= isset($parsed['query']) ? '?'.$parsed['query'] : ''; + $uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : ''; + + return $uri; + } + + +} +?>
\ No newline at end of file diff --git a/site/app/controllers/tutorius_api_controller.php b/site/app/controllers/tutorius_api_controller.php new file mode 100644 index 0000000..24446f8 --- /dev/null +++ b/site/app/controllers/tutorius_api_controller.php @@ -0,0 +1,896 @@ +<?php +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is addons.mozilla.org site. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * l.m.orchard <lorchard@mozilla.com> (Original Author) + * Frederic Wenzel <fwenzel@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +uses('sanitize'); + +/** + * Controller implementing addon sharing API + * see: https://wiki.mozilla.org/User:LesOrchard/BandwagonAPI + */ +class TutoriusApiController extends AppController +{ + var $name = 'TutoriusApi'; + + // bump for new releases + // 0 or unspecified is for Fx3b3 + // 0.9 is for Fx3b4 + var $newest_api_version = 0.1; + + var $beforeFilter = array( + '_checkSandbox' + ); + var $uses = array( + 'Addon', 'Review', 'Addonlog', 'AddonCollection', 'Addontype', 'ApiAuthToken', + 'Application', 'Collection', 'File', 'Platform', 'Category', 'Translation', + 'UpdateCount', 'Version', 'User' + ); + var $components = array( + 'Amo', 'Developers', 'Email', 'Image', 'Pagination', 'Search', 'Session', + 'Versioncompare' + ); + var $helpers = array( + 'Html', 'Link', 'Time', 'Localization', 'Ajax', 'Number', + 'Pagination' + ); + + var $securityLevel = 'low'; + + const STATUS_OK = '200 OK'; + const STATUS_CREATED = '201 Created'; + const STATUS_ACCEPTED = '202 Accepted'; + const STATUS_FOUND = '302 Found'; + const STATUS_SEE_OTHER = '303 See Other'; + const STATUS_NOT_MODIFIED = '304 Not Modified'; + const STATUS_BAD_REQUEST = '400 Bad Request'; + const STATUS_UNAUTHORIZED = '401 Unauthorized'; + const STATUS_FORBIDDEN = '403 Forbidden'; + const STATUS_NOT_FOUND = '404 Not Found'; + const STATUS_METHOD_NOT_ALLOWED = '405 Method Not Allowed'; + const STATUS_CONFLICT = '409 Conflict'; + const STATUS_GONE = '410 Gone'; + const STATUS_UNSUPPORTED_MEDIA = '415 Unsupported Media Type'; + const STATUS_ERROR = '500 Internal Server Error'; + + var $cache_lifetime = 0; // 0 seconds + + function forceCache() { + header('Cache-Control: public, max-age=' . $this->cache_lifetime); + header('Vary: X-API-Auth'); + header('Last-Modified: ' . gmdate("D, j M Y H:i:s", $this->last_modified) . " GMT"); + header('Expires: ' . gmdate("D, j M Y H:i:s", $this->last_modified + $this->cache_lifetime) . " GMT"); + } + + /** + * This function is executed for every request to the API + * + */ + function beforeFilter() { + Configure::write('Session.checkAgent', false); + + $this->last_modified = time(); + + $this->layout = 'rest'; + + if (!$this->isWriteHttpMethod()) { + // Only force shadow DB on reads. + $this->forceShadowDb(); + } + + $this->Collection->caching = false; + $this->AddonCollection->caching = false; + $this->User->caching = false; + $this->ApiAuthToken->caching = false; + + $this->SimpleAuth->enabled = false; + $this->SimpleAcl->enabled = false; + + // extract API version + $url = $_SERVER['REQUEST_URI']; + + $matches = array(); + if (preg_match('/api\/([\d\.]*)\//', $url, $matches)) { + $this->api_version = $matches[1]; + if (!is_numeric($this->api_version)) { + $this->api_version = $this->newest_api_version; + } + } else { + // nothing supplied: assume Fx3b3 + $this->api_version = 0; + } + + // Establish a base URL for this request. + $this->base_url = ( empty($_SERVER['HTTPS']) ? 'http' : 'https' ) . + '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + if ( ($qpos = strpos($this->base_url, '?')) !== FALSE) { + // Toss out any query parameters. + $this->base_url = substr($this->base_url, 0, $qpos); + } + $this->_sendToView('base_url', $this->base_url); + + $pos = strpos($this->base_url, 'api/'); + $this->site_base_url = substr($this->base_url, 0, $pos); + $this->_sendToView('site_base_url', $this->site_base_url); + + + // Trying to get the current authenticated user + $this->auth_user = $this->_getAuthUser(); + + $this->_sendToView('auth_user', $this->auth_user); + } + + /** + * This is the main function for this controller + * its role is to list all available functions via the API + */ + function index() { + + + } + + /********************************************** + /*************** AUTHENTIFICATION ************* + /*********************************************/ + + /* + * Authenticate a user and then + * return an authentication key so the user doesn't have to authenticate with its + * username/password every request + * + */ + function auth() { + $args = func_get_args(); + return $this->dispatchHttpMethod(array( + 'POST' => 'auth_POST' + ), $args); + } + + /** + * Generate a new auth token for the authenticated user. + */ + function auth_POST($context) { + extract($context); + + // Check HTTP basic auth + if (null == $this->auth_user && + !empty($_SERVER['PHP_AUTH_USER']) && + !empty($_SERVER['PHP_AUTH_PW'])) { + // Try validating the user by HTTP Basic auth username and password. + $someone = $this->User->findByEmail($_SERVER['PHP_AUTH_USER']); + if (!empty($someone['User']['id']) && $someone['User']['confirmationcode'] != '') { + // User not yet verified. + $auth_user = null; + } else if ($this->User->checkPassword($someone['User'], $_SERVER['PHP_AUTH_PW'])) { + $this->auth_user = $someone['User']; + $this->auth_user['Group'] = $someone['Group']; + } + } + + // If authentification was successful, this will allow + // the function to continue. Otherwise, an access denied + // message will be displayed. + $this->_checkLoggedIn(); + + $token_value = $this->ApiAuthToken->generateTokenValue(); + + $data = array( + 'ApiAuthToken' => array( + 'token' => $token_value, + 'user_id' => $this->auth_user['id'] + ) + ); + $this->Amo->clean($data); + + if (!$this->ApiAuthToken->save($data)) { + return $this->renderStatus( + self::STATUS_ERROR, 'error', + array('reason' => 'auth_token_generation_failed') + ); + } + + $token_url = $this->base_url . '/' . $token_value; + + return $this->renderStatus( + self::STATUS_CREATED, 'auth_token', array( + 'value' => $token_value, + 'url' => $token_url + ), $token_url + ); + } + + /** + * Dispatcher for auth token detail resource. + */ + function auth_detail($token) { + $args = func_get_args(); + return $this->dispatchHttpMethod(array( + 'DELETE' => 'auth_detail_DELETE' + ), $args); + } + + /** + * Delete an existing token, rendering it unusable in the future. (eg. for + * logout) + */ + function auth_detail_DELETE($context, $token) { + extract($context); + + $rv = $this->ApiAuthToken->deleteByUserIdAndToken( + $this->auth_user['id'], $token + ); + + if ($rv) { + return $this->renderStatus(self::STATUS_GONE, 'empty'); + } else { + return $this->renderStatus( + self::STATUS_NOT_FOUND, 'error', + array('reason' => 'token_unknown') + ); + } + } + + /********************************************** + /************** USER REGISTRATION ************* + /*********************************************/ + + function registerNewUser() { + + $args = func_get_args(); + return $this->dispatchHttpMethod(array( + 'POST' => 'registerNewUser_POST' + ), $args); + + } + + /** + * This creates an account via a POST request + * + */ + function registerNewUser_POST($context) { + extract($context); + + // Create the User array and map it with the POST variables + $data['User'] = $this->getParams(array( + 'nickname' => '', + 'password' => '', + 'email' => '', + )); + + // filter nickname characters + //$this->data['User']['nickname'] = $this->_filterNick($this->data['User']['nickname']); + + + // No confirmation code. We want to simplify the process for now. + // User is auto-approved + $data['User']['confirmationcode'] = ''; + + $this->User->data = $data; + $this->Amo->clean($this->User->data); + + // hash password + $this->User->data['User']['password'] = $this->User->createPassword($this->User->data['User']['password']); + + // no empty pw + if ($data['User']['password'] == '') + $this->User->invalidate('password'); + + // email has to be unique + $allemail = $this->User->findAll("email='{$this->User->data['User']['email']}'"); + if (!empty($allemail)) { + $this->User->invalidate('email'); + return $this->_renderError( + array( + 'reason' => 'Email already in use', + 'details' => 'You cannot create another user with the same email' + ) + ); + } + + // if nickname is defined it has to be unique + if (!$data['User']['nickname'] == '') { + $allnicks = $this->User->findAll("nickname='{$this->User->data['User']['nickname']}'"); + if (!empty($allnicks)) { + $this->User->invalidate('nickname'); + return $this->_renderError( + array( + 'reason' => 'nickname already in use', + 'details' => 'cannot create a new user because the selected nickname is already in use.' + ) + ); + } + } + + // any errors? Get out of here. + if (!$this->User->save()) { + return $this->_renderError( + array( + 'reason' => 'There was an error while creating the account' + ) + ); + $this->render(); + return; + } + } + + /********************************************** + /*************** PUBLISH PROCESS ************** + /*********************************************/ + + /** + * Dispatcher for the publish method + * + */ + function publish() { + + $args = func_get_args(); + return $this->dispatchHttpMethod(array( + 'POST' => 'publish_POST' + ), $args); + + } + + /** + * Publish a new tutorial + * + */ + function publish_POST($context) { + extract($context); + + $this->_checkLoggedIn(); + + + + } + + /********************************************** + /**************** REVIEW PROCESS ************** + /*********************************************/ + + function review($id) { + + $args = func_get_args(); + return $this->dispatchHttpMethod(array( + 'POST' => 'review_POST' + ), $args); + + } + + /** + * This function allow rating on activities for the authenticated user. + * + */ + function review_POST($context, $id) { + extract($context); + + // Restricted part of the api + $this->_checkLoggedIn(); + + // First, search for the addon we want to rate + $this->_getAddons(array($id)); + + // Check if the addon we are looking for exist + // the viewVars is set via _getAddons function + if (isset($this->viewVars['addonsdata'][$id])) { + + // The addon we want to rate is found + $addon = $this->viewVars['addonsdata'][$id]; + $this->_sendToView('addon', $addon); + + // check if the current user owns this Addon + // A user can't review his own add-on + $isauthor = $this->_checkOwnership($id); + + if($isauthor) { + return $this->_renderError( + array( + 'reason' => 'You cannot review your own tutorial' + ) + ); + } + + // Start the review process + $this->_saveOrUpdateReview($addon); + + } else { + + // Output error to view if tutorial not found + return $this->_renderError( + array('reason' => 'Tutorial not found') + ); + } + + } + + + /********************************************** + /*************** HELPER FUNCTIONS ************* + /*********************************************/ + + /** + * This function execute the review process for a particular addon + * + */ + function _saveOrUpdateReview($addon) { + global $valid_status; + + // Create the Review array and map it with the POST variables + $data['Review'] = $this->getParams(array( + 'rating' => '', + 'title' => '', + 'body' => '', + 'id' => 0, + )); + + // Add the new review or edit an existing review + if (isset($data['Review'])) { + $old_title = $data['Review']['title']; + $old_body = $data['Review']['body']; + $this->Amo->clean($data['Review']); + + // validate rating + if ($data['Review']['rating'] < 0 || $data['Review']['rating'] > 5) { + $this->Review->invalidate('rating'); + return; + } + + // Fill in basic details for the review + $data['Review']['version_id'] = $this->Version->getVersionByAddonId($addon['Addon']['id'], $valid_status); // add version id to data array + $data['Review']['user_id'] = $this->auth_user['id']; + $data['Review']['editorreview'] = 0; // auto-approve review + + // if id is set for the review, check if it's valid + if ($data['Review']['id'] !== 0) { + $oldreview = $this->Review->find("Version.addon_id = {$addon['Addon']['id']} AND Review.user_id = {$this->auth_user['id']}"); + if (!isset($oldreview['Review']['id']) || $oldreview['Review']['id'] === $data['Review']['id']) + $this->Review->invalidate('id'); + } + + // Save information in DB + if ($this->Review->save($data)) { + //Log addon action for new reviews + if (empty($data['Review']['id'])) { + //$this->Addonlog->logAddReview($this, $addon['Addon']['id'], $this->Review->getLastInsertID()); + } + + $this->Review->updateBayesianRating(array($addon['Addon']['id'])); + $this->_sendToView('success', true); + + // We return the saved review to the View + $reviews = $this->Review->getReviews(array($this->Review->getLastInsertID())); + $thisReview = $reviews[0]; + + $this->_sendToView('review', $thisReview); + + return; + + } else { + $data['Review']['title'] = $old_title; + $data['Review']['body'] = $old_body; + + return $this->_renderError( + array('reason' => 'There was an error while saving the review') + ); + } + } + + } + + + /** + * API specific publish + * Uses XML encoding and is UTF-8 safe + * @param mixed the data array (or string) to be html-encoded (by reference) + * @param bool clean the array keys as well? + * @return void + */ + function _sendToView($viewvar, $value, $sanitizeme = true) { + if ($sanitizeme) { + if (is_array($value)) { + $this->_sanitizeArrayForXML($value); + } else { + $tmp = array($value); + $this->_sanitizeArrayForXML($tmp); + $value = $tmp[0]; + } + } + $this->set($viewvar, $value); + } + + /** + * API specific sanitize + * xml-encode an array, recursively + * UTF-8 safe + * + * @param mixed the data array to be encoded + * @param bool clean the array keys as well? + * @return void + */ + var $sanitize_patterns = array( + "/\&/u", "/</u", "/>/u", + '/"/u', "/'/u", + '/[\cA-\cL]/u', + '/[\cN-\cZ]/u', + ); + var $sanitize_replacements = array( + "&", "<", ">", + """, "'", + "", + "" + ); + var $sanitize_field_exceptions = array( + 'id'=>1, 'guid'=>1, 'addontype_id'=>1, 'status'=>1, 'higheststatus'=>1, + 'icontype'=>1, 'version_id'=>1, 'platform_id'=>1, 'size'=>1, 'hash'=>1, + 'codereview'=>1, 'password'=>1, 'emailhidden'=>1, 'sandboxshown'=>1, + 'averagerating'=>1, 'textdir'=>1, 'locale'=>1, 'locale_html'=>1, + 'created'=>1, 'modified'=>1, 'datestatuschanged'=>1 + ); + + function _sanitizeArrayForXML(&$data, $cleankeys = false) { + + if (empty($data)) return; + + foreach ($data as $key => $value) { + if (isset($this->sanitize_field_exceptions[$key])) { + // @todo This if() statement is a temporary solution until we come up with + // a better way of excluding fields from being sanitized. + continue; + } else if (empty($value)) { + continue; + } else if (is_array($value)) { + $this->_sanitizeArrayForXML($data[$key], $cleankeys); + } else { + $data[$key] = preg_replace( + $this->sanitize_patterns, + $this->sanitize_replacements, + $data[$key] + ); + } + } + + // change the keys if necessary + if ($cleankeys) { + $keys = array_keys($data); + $this->_sanitizeArrayForXML($keys, false); + $data = array_combine($keys, array_values($data)); + } + + } + + /** + * Render an HTTP status along with optional template and location. + * + * @param string HTTP status + * @param string (optional) Name of a view to render + * @param array (optional) Vars to be published to the template + * @param string (optional) URL for Location: header + */ + function renderStatus($status, $view=null, $ns=null, $location=null) { + $this->layout = ($view == 'empty') ? '' : 'rest'; + header('HTTP/1.1 ' . $status); + if (!empty($ns)) foreach ($ns as $k=>$v) + $this->_sendToView($k, $v); + if (null !== $location) + header('Location: '.$location); + if (null !== $view) + return $this->render($view); + } + + /** + * Dispatch to the appropriate handler based on HTTP method and a map of + * handlers. + */ + function dispatchHttpMethod($map, $args=NULL, $context=null) { + + if (null == $args) $args = array(); + if (null == $context) $context = array(); + + $method = $this->getHttpMethod(); + + if ('OPTIONS' == $method) { + header('Allow: ' . join(', ', array_keys($map))); + $this->_sendToView('methods', array_keys($map)); + return $this->render('options'); + } + + if (!isset($map[$method])) { + return $this->renderStatus( + self::STATUS_METHOD_NOT_ALLOWED, 'error', + array('reason' => $method . '_not_allowed') + ); + } + + return call_user_func_array( + array($this, $map[$method]), + array_merge(array($context), $args) + ); + } + + /** + * Grab named keys from POST parameters. Missing parameters will be + * set as null. + * + * @param array list of named parameters. + */ + function getParams($list) { + $params = array(); + $raw = array(); + if ($this->getHttpMethod() != 'PUT') { + $raw = array_merge($_GET, $_POST); + } else { + $raw = array(); + if (!empty($_SERVER['CONTENT_LENGTH'])) { + // HACK: $_POST isn't populated by PUT + $data = file_get_contents('php://input'); + mb_parse_str($data, $raw); + } + $raw = array_merge($_GET, $raw); + } + foreach ($list as $name=>$default) { + $params[$name] = isset($raw[$name]) ? + $raw[$name] : $default; + } + return $params; + } + + /** + * Figure out the current HTTP method, with overrides accepted in a _method + * parameter (GET/POST) or in an X_HTTP_METHOD_OVERRIDE header ala Google + */ + function getHttpMethod() { + if (!empty($_POST['_method'])) + return strtoupper($_POST['method']); + if (!empty($_GET['_method'])) + return strtoupper($_GET['method']); + if (!empty($_SERVER['X_HTTP_METHOD_OVERRIDE'])) + return strtoupper($_SERVER['X_HTTP_METHOD_OVERRIDE']); + if (!empty($_SERVER['REQUEST_METHOD'])) + return strtoupper($_SERVER['REQUEST_METHOD']); + } + + /** + * Return whether the current HTTP method is a request to write in some + * way. + */ + function isWriteHttpMethod() { + return in_array($this->getHttpMethod(), array('POST', 'DELETE', 'PUT')); + } + + /** + * If an if-modified-since header was provided, return a 304 if the + * collection indeed has not been modified since the given time. + */ + function isNotModifiedSince() { + $since = @$_SERVER['HTTP_IF_MODIFIED_SINCE']; + if ('GET' == $this->getHttpMethod() && $since) { + if ($this->last_modified <= strtotime($since)) { + return $this->renderStatus( + self::STATUS_NOT_MODIFIED, 'empty' + ); + } + } + } + + /** + * Standalone string sanitize for XML + * + * @param string + * @return string + */ + function sanitizeForXML($value) { + return preg_replace( + $this->sanitize_patterns, + $this->sanitize_replacements, + $value + ); + } + + + /** + * Check if the current authenticated user has ownership + * of the specified addon id + */ + function _checkOwnership($id) { + + $user_id = $this->auth_user['id']; + + //Check if user is an admin + if ($this->SimpleAcl->actionAllowed('Admin', 'EditAnyAddon', $this->auth_user)) { + return false; + } + + // Query + $results = $this->Addon->query("SELECT * FROM addons_users WHERE addon_id={$id} AND user_id={$user_id}"); + + //check if user is an author of the add-on + if ($results) + return true; + else + return false; + } + + + /** + * Get Addon details + * + * @param ids: Array containing ids of the addons we want + */ + function _getAddons($ids) { + + $addonsdata = array(); + foreach ($ids as $id) { + $_conditions = array( + 'Addon.id' => $id, + 'Addon.inactive' => 0, + 'Addon.addontype_id' => array(ADDON_EXTENSION,ADDON_PLUGIN) + ); + + // get basic addon data + // same criteria as used by the amo display action + $this->Addon->bindOnly('User', 'Version', 'Tag', 'AddonCategory'); + $addon_data = $this->Addon->find($_conditions, null , null , 1); + + if (empty($addon_data)) { + // this covers the case where we turned up something in the requested set that + // was invalid for whatever reason. + continue; + } + + // get addon type + $this_addon_type = $this->Addontype->findById($addon_data['Addon']['addontype_id']); + $addon_data['Addon_type'] = $this_addon_type; + + $install_version + = $this->Version->getVersionByAddonId($addon_data['Addon']['id'], + STATUS_PUBLIC); + + // find the addon version to report to user + foreach ($addon_data['Version'] as $v) { + if ($v['id'] == $install_version) { + $addon_data['install_version'] = $v['version']; + break; + } + } + + // get filename for install + $fileinfo = $this->File->findAllByVersion_id( + $install_version, null, null, null, null, 0); + + if (!is_array($fileinfo) || count($fileinfo)==0) { + // don't return addons that don't have a valid + // file associated with them + continue; + } + + // get compatible apps + $compatible_apps = $this->Version->getCompatibleApps($install_version); + $addon_data['Compatible_apps'] = $compatible_apps; + + + // get compatible platforms + + foreach($fileinfo as &$file) { + $this->Platform->unbindFully(); + $this_plat = $this->Platform->findById($file['Platform']['id']); + $file['Platform']['apiname'] = $this_plat['Translation']['name']['string']; + $platforms[] = $this_plat; + } + + if ($this->api_version > 0 ) { + // return an array of compatible os names + // right now logic is still wrong, but this enables + // xml changes and logic will be fixed later + if (empty($platforms)) { + $addon_data['all_compatible_os'] = array(); + } else { + $addon_data['all_compatible_os'] = $platforms; + } + + + } + + // pull highlighted preview thumbnail url + $addon_data['Thumbnail'] = $this->Image->getHighlightedPreviewURL($id); + + // the icon + $addon_data['Icon'] = $this->Image->getAddonIconURL($id); + + $addon_data['fileinfo'] = $fileinfo; + + // add data to array + $addonsdata[$id] = $addon_data; + } + + $this->set('addonsdata' , $addonsdata); + + } + + /** + * Return the current authenticated user, or return null and set 401 + * Unauthorized headers. + * + * @return mixed Authenticated user details. + */ + function _getAuthUser() { + $auth_user = null; + + // Check an auth header token + if (null == $auth_user && !empty($_SERVER['HTTP_X_API_AUTH'])) { + // Try accepting an API auth token in a header. + $token = $_SERVER['HTTP_X_API_AUTH']; + $auth_user = $this->ApiAuthToken->getUserForAuthToken($token); + } + + return $auth_user; + } + + /** + * Returns a access denied "401 Unauthorized" + * error when the user is not authenticated + */ + function _access_denied() { + + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Basic realm="Tutorius API"'); + $this->_sendToView('reason', 'unauthorized'); + $this->_sendToView('href', $this->base_url . 'auth'); + $this->render('error'); + exit(); + } + + /** + * This function check if the user is authenticated. + * + */ + function _checkLoggedIn( $admin = false ) { + + if (!$this->auth_user || ($admin && $this->SimpleAcl->actionAllowed('Admin', '%', $this->auth_user))) + $this->_access_denied(); + } + + /** + * Render the error view with an error message and details + * + */ + function _renderError($ns) { + $this->layout = ('error' == 'empty') ? '' : 'rest'; + if (!empty($ns)) foreach ($ns as $k=>$v) + $this->_sendToView($k, $v); + + return $this->render('error'); + } +} diff --git a/site/app/views/tutorius_api/error.thtml b/site/app/views/tutorius_api/error.thtml new file mode 100644 index 0000000..f83d00d --- /dev/null +++ b/site/app/views/tutorius_api/error.thtml @@ -0,0 +1,43 @@ +<?php +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is addons.mozilla.org site. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * l.m.orchard <lorchard@mozilla.com> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +?> + +<error xmlns="http://addons.mozilla.org/" + reason="<?php echo $reason ?>" + <?php if (isset($details)): ?>details="<?php echo $details ?>"<?php endif ?> +/>
\ No newline at end of file diff --git a/site/app/views/tutorius_api/index.thtml b/site/app/views/tutorius_api/index.thtml new file mode 100644 index 0000000..2a790e2 --- /dev/null +++ b/site/app/views/tutorius_api/index.thtml @@ -0,0 +1,62 @@ +<?php +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is addons.mozilla.org site. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Laura Thomson <lthomson@mozilla.com> (Original Author) + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +<tutorius xmlns="http://tutorius.org" xml:base="<?php echo $base_url ?>"> + <review href="review" > + <description>Used to post or update a review</description> + <method>POST</method> + <params> + <param> + <name>title</name> + <type>string</type> + <description>Title of the review</description> + </param> + <param> + <name>body</name> + <type>string</type> + <description>Review content</description> + </param> + <param> + <name>rating</name> + <type>int</type> + <description>rating between 0 and 5</description> + </param> + </params> + </review> + <login href="login" /> + <creatAccount href="createAccount" /> + </tutorius>
\ No newline at end of file diff --git a/site/app/views/tutorius_api/register_new_user.thtml b/site/app/views/tutorius_api/register_new_user.thtml new file mode 100644 index 0000000..212c493 --- /dev/null +++ b/site/app/views/tutorius_api/register_new_user.thtml @@ -0,0 +1,44 @@ +<?php +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is addons.mozilla.org site. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Laura Thomson <lthomson@mozilla.com> (Original Author) + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + if (isset($error)) { ?> + <error><?php echo ($error); ?></error> +<?php + } else { ?> + + <createAccount>success</createAccount> + + <?php } ?>
\ No newline at end of file diff --git a/site/app/views/tutorius_api/review.thtml b/site/app/views/tutorius_api/review.thtml new file mode 100644 index 0000000..3590839 --- /dev/null +++ b/site/app/views/tutorius_api/review.thtml @@ -0,0 +1,52 @@ +<?php +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is addons.mozilla.org site. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Laura Thomson <lthomson@mozilla.com> (Original Author) + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + if (isset($error)) { ?> + <error><?php echo ($error); ?></error> +<?php + } else { ?> + + <review xml:base="<?php echo $base_url ?>"> + <meta> + <added><?php echo $review['Review']['created'] ?></added> + <addedby><?php echo $review['User']['nickname']?></addedby> + </meta> + <title><?php echo $review['Translation']['en-US']['title']['string'] ?></title> + <body><?php echo $review['Translation']['en-US']['body']['string']?><body> + <rating><?php echo $review['Review']['rating']?></rating> + </review> + + <?php } ?>
\ No newline at end of file |