. * * XenAPI is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * XenAPI 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ // To change the API key, replace the REPLACE_THIS_WITH_AN_API_KEY with your desired API key. $restAPI = new RestAPI('REPLACE_THIS_WITH_AN_API_KEY'); # DO NOT CHANGE ANYTHING BELOW THIS LINE UNLESS # YOU REALLY KNOW WHAT ARE YOU DOING // Process the request if ($restAPI->getAPIKey() !== NULL && $restAPI->isDefaultAPIKey()) { // API is set but not changed from the default API key. $restAPI->throwError(17); } else if ($restAPI->getAPIKey() !== NULL && !$restAPI->hasRequest('hash') && !$restAPI->isPublicAction()) { // Hash argument is required and was not found, throw error. $restAPI->throwError(3, 'hash'); } else if (!$restAPI->getHash() && !$restAPI->isPublicAction()) { // Hash argument is empty or not set, throw error. $restAPI->throwError(1, 'hash'); } else if (!$restAPI->isAuthenticated() && !$restAPI->isPublicAction()) { // Hash is not valid and action is not public, throw error. $restAPI->throwError(6, $restAPI->getHash(), 'hash'); } else if (!$restAPI->hasRequest('action')) { // Action argument was not found, throw error. $restAPI->throwError(3, 'action'); } else if (!$restAPI->getAction()) { // Action argument is empty or not set, throw error. $restAPI->throwError(1, 'action'); } else if (!$restAPI->isSupportedAction()) { // Action is not supported, throw error. $restAPI->throwError(2, $restAPI->getAction()); } else if (!$restAPI->isPermitted()) { // User does not have permission to use this action, throw error. if ($restAPI->hasRequest('value') && $restAPI->isUserAction()) { $restAPI->throwError(9, $restAPI->getAction()); } else { $restAPI->throwError(10, $restAPI->getAction()); } } // Process the request. $restAPI->processRequest(); class RestAPI { const VERSION = '1.4.fix'; const DEFAULT_APIKEY = 'REPLACE_THIS_WITH_AN_API_KEY'; const GENERAL_ERROR = 0x201; const USER_ERROR = 0x202; const THREAD_ERROR = 0x203; const POST_ERROR = 0x204; /** * Contains all the actions in an array, each action is 'action' => 'permission_name' * 'action' is the name of the action in lowercase. * 'permission_name' is the permission requirement of the action, see description under. * * Permission names and meaning: * - public: A hash is not required to use this action, it can be used without * without being 'authenticated'. * - authenticated: The action requires the user to be authenticated to use the action * with a 'value' argument. * - moderator: The action requires the user to be a moderator to use the action * with a 'value' argument. * - administrator: The action requires the user to be an administrator to use the action * with a 'value' argument. * - private: User is only allowed to use the action on himself/herself. * Example: If user tries to use 'getAlerts' with a 'value' argument, * an error will be thrown. * - api_key: An API key is required to perform this action. * * NOTE: Permissions are ignored when the API key is used as a hash, permissions are only * used when the user is using the 'username:hash' format for the 'hash' argument. */ private $actions = array( 'authenticate' => 'public', 'createalert' => 'api_key', 'createconversation' => 'authenticated', 'createconversationreply' => 'authenticated', 'createpost' => 'authenticated', 'createprofilepost' => 'authenticated', 'createprofilepostcomment' => 'authenticated', 'createthread' => 'authenticated', 'deletepost' => 'authenticated', 'deleteuser' => 'authenticated', 'downgradeuser' => 'api_key', 'editpost' => 'authenticated', 'editthread' => 'authenticated', 'edituser' => 'api_key', 'getactions' => 'public', 'getaddon' => 'administrator', 'getaddons' => 'administrator', 'getalerts' => 'private', 'getavatar' => 'public', 'getconversation' => 'private', 'getconversations' => 'private', 'getgroup' => 'public', 'getnode' => 'public', 'getnodes' => 'public', 'getpost' => 'public', 'getposts' => 'public', 'getprofilepost' => 'authenticated', 'getprofileposts' => 'authenticated', 'getresource' => 'administrator', 'getresources' => 'administrator', 'getresourcecategories' => 'administrator', 'getstats' => 'public', 'getthread' => 'public', 'getthreads' => 'public', 'getuser' => 'authenticated', 'getusers' => 'public', 'getuserupgrade' => 'api_key', 'getuserupgrades' => 'api_key', 'login' => 'public', 'register' => 'api_key', 'search' => 'public', 'upgradeuser' => 'api_key' ); // Array of actions that are user specific and require an username, ID or email for the 'value' parameter. private $user_actions = array('getalerts', 'getavatar', 'getconversation', 'getconversations', 'createprofilepost', 'getuser'); // List of general errors, this is where the 'throwError' function gets the messages from. private $general_errors = array( 0 => 'Unknown error', 1 => 'Argument: "{ERROR}", is empty/missing a value', 2 => '"{ERROR}", is not a supported action', 3 => 'Missing argument: "{ERROR}"', 4 => 'No {ERROR} found with the argument: "{ERROR2}"', 5 => 'Authentication error: "{ERROR}"', 6 => '"{ERROR}" is not a valid {ERROR2}', 7 => 'Something went wrong when "{ERROR}": "{ERROR2}"', 8 => 'The request had no values set, available fields are: "({ERROR})"', 9 => 'You are not permitted to use the "{ERROR}" action on others (remove the value argument)', 10 => 'You do not have permission to use the "{ERROR}" action', 11 => '"{ERROR}" is a supported action but there is no code for it yet', 12 => '"{ERROR}" is a unknown request method', 13 => '"{ERROR}" is not an installed addon', 14 => '"{ERROR}" is not an author of any resources', 15 => 'Could not find a resource with ID "{ERROR}"', 16 => 'Could not find a required model to perform this request: "{ERROR}"', 17 => 'The API key has not been changed, make sure you use another API key before using this API', 18 => '"{ERROR} is a unknown permission name, the request was terminated.', 19 => 'Could not find a {ERROR} with ID "{ERROR2}"', 20 => '{ERROR} not have permissions to view {ERROR2}', 21 => 'The "{ERROR}" argument has to be a number', 22 => 'The argument for "order_by", "{ERROR}", was not found in the list available order by list: "({ERROR2})"', 23 => 'The argument for "node_type", "{ERROR}", was not found in the list available node type list: "({ERROR2})"', 24 => 'The argument for "discussion_state", "{ERROR}", was not found in the list available discussion state list: "({ERROR2})"' ); // Specific errors related to user actions. private $user_errors = array( 0 => 'Unknown user error', 1 => 'Field was not recognised', 2 => 'Group not found', 3 => 'User data array was missing', 4 => 'The specified user is not registered', 5 => 'Invalid custom field array', 6 => 'Editing super admins is disabled', 7 => 'The add_groups parameter needs to be an array and have at least 1 item', 8 => 'The user is already a member of the group(s)', 9 => 'No values were changed', 10 => 'Missing required a required parameter', 11 => 'The remove_groups parameter needs to be an array and have at least 1 item', 12 => 'The user is not a member of the group(s)', 13 => 'An user is required to create a post/thread', 14 => 'The user does not have permissions to post in this thread', 30 => 'Missing required registration fields', 31 => 'Password invalid', 32 => 'Name length is too short', 33 => 'Name length is too long', 34 => 'Name contains disallowed words', 35 => 'Name does not follow the required format', 36 => 'Name contains censored words', 37 => 'Name contains CTRL characters', 38 => 'Name contains comma', 39 => 'Name resembles an email', 40 => 'User already exists', 41 => 'Invalid email', 42 => 'Email already used', 43 => 'Email banned by administrator', 44 => 'Invalid timezone', 45 => 'Custom title contains censored words', 46 => 'Custom title contains disallowed words', 47 => 'Invalid date of birth', 48 => 'Cannot delete your own account', 49 => 'Field contained an invalid value' ); private $xenAPI, $method, $data = array(), $hash = FALSE, $apikey = FALSE; /** * Default constructor for the RestAPI class. * The data gets set here depending on what kind of request method is being used. */ public function __construct($api_key = NULL) { $this->method = strtolower($_SERVER['REQUEST_METHOD']); switch ($this->method) { case 'get': $this->data = $_GET; break; case 'post': $this->data = $_POST; break; case 'put': case 'delete': parse_str(file_get_contents('php://input'), $put_vars); $this->data = $put_vars; break; default: $this->throwError(12, $this->method); } $this->xenAPI = new XenAPI(); // Set the API key. $this->apikey = $api_key; // Lowercase the key data, ignores the case of the arguments. $this->data = array_change_key_case($this->data); if ($this->hasRequest('hash')) { // Sets the hash variable if the hash argument is set. $this->hash = $this->getRequest('hash'); } // Check if grab_as by argument is set. if ($this->hasRequest('grab_as') && $this->hasAPIKey()) { if (!$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } // Create a user object with the 'grab_as' argument. $this->grab_as = $this->xenAPI->getUser($this->getRequest('grab_as')); if (!$this->grab_as->isRegistered()) { // Throw error if the 'grab_as' user is not registered. $this->throwError(4, 'user', $this->getRequest('grab_as')); } } // Check if order by argument is set. if ($this->hasRequest('order_by')) { if (!$this->getRequest('order_by')) { // Throw error if the 'order_by' argument is set but empty. $this->throwError(1, 'order_by'); } $this->order_by = $this->getRequest('order_by'); } // Check if order argument is set. if ($this->hasRequest('order')) { if (!$this->getRequest('order')) { // Throw error if the 'order' argument is set but empty. $this->throwError(1, 'order'); } $this->order = strtolower($this->getRequest('order')); if ($this->order == 'd' || $this->order == 'desc' || $this->order == 'descending') { // Order is descending (10-0). $this->order = 'desc'; } else if ($this->order == 'a' || $this->order == 'asc' || $this->order == 'ascending') { // Order is ascending (0-10). $this->order = 'asc'; } else { // Order is unknown, default to descending (10-0). $this->order = 'desc'; } } else { // Order is not set, default to descending (10-0). $this->order = 'desc'; } // Set the limit. $this->setLimit(100); } /** * Returns the XenAPI, returns NULL if the XenAPI was not set. */ public function getXenAPI() { return $this->xenAPI; } public function isDefaultAPIKey() { return $this->getAPIKey() == self::DEFAULT_APIKEY; } /** * Returns the API key, returns FALSE if an API key was not set. */ public function getAPIKey() { return $this->apikey; } /** * Sets the API key. */ public function setAPIKey($apikey) { $this->apikey = $apikey; } /** * Return the hash, returns FALSE if the hash was not set. */ public function getHash() { return $this->hash; } /** * TODO */ public function setLimit($default) { // Check if limit argument is set. if ($this->hasRequest('limit')) { if (!$this->getRequest('limit') && (is_numeric($this->getRequest('limit')) && $this->getRequest('limit') != 0)) { // Throw error if the 'limit' argument is set but empty. $this->throwError(1, 'limit'); } else if (!is_numeric($this->getRequest('limit'))) { // Throw error if the 'limit' argument is set but not a number. $this->throwError(21, 'limit'); } $this->limit = $this->getRequest('limit'); } else { // Limit is not set, default to $default variable. $this->limit = $default; } } private function stripUserData($user) { /* * Run through an additional permission check if the request is * not using an API key, unset some variables depending on the * user level. */ $data = $user->getData(); if (!$this->hasAPIKey()) { // Unset variables since the API key isn't used. if (isset($data['style_id'])) { unset($data['style_id']); } if (isset($data['display_style_group_id'])) { unset($data['display_style_group_id']); } if (isset($data['permission_combination_id'])) { unset($data['permission_combination_id']); } if (!$this->getUser()->isAdmin()) { // Unset variables if user is not an admin. if (isset($data['is_banned'])) { unset($data['is_banned']); } } if (!$this->getUser()->isModerator() && $this->getUser()->getID() != $user->getID()) { // Unset variables if user is not a moderator. if (isset($data['user_state'])) { unset($data['user_state']); } if (isset($data['visible'])) { unset($data['visible']); } if (isset($data['email'])) { unset($data['email']); } if (isset($data['custom_fields'])) { unset($data['custom_fields']); } } if ($this->getUser()->getID() != $user->getID()) { // Unset variables if user does not equal the requested user by the 'value' argument. if (isset($data['language_id'])) { unset($data['language_id']); } if (isset($data['message_count'])) { unset($data['message_count']); } if (isset($data['conversations_unread'])) { unset($data['conversations_unread']); } if (isset($data['alerts_unread'])) { unset($data['alerts_unread']); } if (isset($data['upgrades'])) { unset($data['upgrades']); } } } return $data; } /** * Checks if the request is authenticated. * Returns TRUE if the hash equals the API key. * Returns TRUE if the hash equals the user hash. * Returns FALSE if none of the above are TRUE. */ public function isAuthenticated() { if ($this->getHash()) { // Hash argument is set, continue. if ($this->getHash() == $this->getAPIKey()) { // The hash equals the API key, return TRUE. return TRUE; } if (strpos($this->getHash(), ':') !== FALSE) { // The hash contains : (username:hash), split it into an array. $array = explode(':', $this->getHash()); // Get the user and check if the user is valid (registered). $user = $this->xenAPI->getUser($array[0]); if ($user->isRegistered()) { // User is registered, get the hash from the authentication record. $record = $user->getAuthenticationRecord(); $ddata = unserialize($record['data']); $decoded = base64_decode($array[1], TRUE); if ($ddata['hash'] == $array[1] || ($decoded !== FALSE && $ddata['hash'] == $decoded)) { // The hash in the authentication record equals the hash in the 'hash' argument. return TRUE; } } } } return FALSE; } /** * Checks if the request is permitted. * Returns TRUE if API key is set and valid or the action's permission is public. */ public function isPermitted() { $permission = $this->getActionPermission(); // Check if the request is authenticated and it's an user hash (and not an API key). if ($this->isAuthenticated() && $this->getUser()) { switch ($permission) { case 'public': return TRUE; case 'authenticated': return TRUE; case 'moderator': return $this->getUser()->isModerator(); case 'administrator': return $this->getUser()->isAdmin(); case 'private': // Check if the 'value' argument is set. if ($this->hasRequest('value') && $this->getRequest('value')) { /** * Returns TRUE if the 'value' argument equals the username of the user hash. * In other words, the request is not permitted if 'value' != username. */ return $this->getUser()->getUsername() == $this->getRequest('value'); } // The value argument is not, request is permitted, return TRUE. return TRUE; case 'api_key': return $this->hasAPIKey(); default: $this->throwError(10, $this->getAction()); } } // Returns TRUE if permission of the action is public or the request has a valid API key. return $permission == 'public' || $this->hasAPIKey(); } public function getCustomArray($input_data) { // Custom fields are set. $custom_array_data = array(); // Check if there are more than one custom array. if (strpos($input_data, ',') !== FALSE) { // There are more than one custom array set. $custom_arrays = explode(',', $input_data); // Loop through the custom fields. foreach ($custom_arrays as $custom_array) { // Check if custom array string contains = symbol, ignore if not. if (strpos($custom_array, '=') !== FALSE) { // Custom array string contains = symbol, explode it. $custom_array_list = explode('=', $custom_array); // Add the custom item data to the array. $custom_array_data[$custom_array_list[0]] = $custom_array_list[1]; } } } else if (strpos($input_data, '=') !== FALSE) { // Custom array string contains = symbol, explode it. $custom_array_list = explode('=', $input_data); // Add the custom item data to the array. $custom_array_data[$custom_array_list[0]] = $custom_array_list[1]; } // Return the array(s). return $custom_array_data; } /** * Returns TRUE if the request has an API key that is valid, returns FALSE if not. */ public function hasAPIKey() { if ($this->getHash()) { return $this->getHash() == $this->getAPIKey(); } return FALSE; } /** * Returns the User class of the username if the hash is set and is an userhash. * Returns FALSE if the hash is not an userhash. */ public function getUser() { if (isset($this->user) && $this->user !== NULL) { return $this->user; } else if (isset($this->grab_as) && $this->grab_as !== NULL) { return $this->grab_as; } else if (strpos($this->getHash(), ':') !== FALSE) { $array = explode(':', $this->getHash()); $this->user = $this->xenAPI->getUser($array[0]); return $this->user; } return NULL; } /** * */ public function checkOrderBy($order_by_array) { if ($this->hasRequest('order_by')) { if (!$this->getRequest('order_by')) { // Throw error if the 'order_by' argument is set but empty. $this->throwError(1, 'order_by'); } if (!in_array(strtolower($this->getRequest('order_by')), $order_by_array)) { // Throw error if the 'order_by' argument is set but could not be found in list of allowed order_by. $this->throwError(22, $this->getRequest('order_by'), implode(', ', $order_by_array)); } return strtolower($this->getRequest('order_by')); } return FALSE; } /** * Returns the method (get, post, put, delete). */ public function getMethod() { return $this->method; } /** * Returns the action name. */ public function getAction() { return $this->getRequest('action'); } /** * Returns the permission name of the action. */ public function getActionPermission() { return (isset($this->data['action']) && isset($this->actions[strtolower($this->getAction())])) ? strtolower($this->actions[strtolower($this->getAction())]) : NULL; } /** * Returns TRUE if the '$key' is set a argument, returns FALSE if not. */ public function hasRequest($key) { return isset($this->data[strtolower($key)]); } /** * Gets the data of the '$key', returns FALSE if the '$key' argument was not set. */ public function getRequest($key) { if ($this->hasRequest($key)) { return $this->data[strtolower($key)]; } else { return FALSE; } } /** * Returns the array of all the arguments in the request. */ public function getData() { return $this->data; } /** * Returns TRUE if the action is supported, FALSE if not. */ public function isSupportedAction() { return isset($this->data['action']) && array_key_exists(strtolower($this->data['action']), $this->actions); } /** * Returns TRUE if the action is a public action (does not require a hash), FALSE if not. */ public function isPublicAction() { return isset($this->data['action']) && isset($this->actions[strtolower($this->data['action'])]) && strtolower($this->actions[strtolower($this->data['action'])]) == 'public'; } /** * Returns TRUE if the action is a user action (the 'value' parameter has to be an username/id/email), FALSE if not. */ public function isUserAction() { return isset($this->data['action']) && in_array(strtolower($this->data['action']), $this->user_actions); } /** * TODO */ public function checkRequestParameter($parameter, $required = TRUE) { if ($required && !$this->hasRequest($parameter)) { // The '$parameter' argument has not been set, throw error. $this->throwError(3, $parameter); } else if ($this->hasRequest($parameter) && $this->getRequest($parameter) === FALSE) { // Throw error if the '$parameter' argument is set but empty. $this->throwError(1, $parameter); } return TRUE; } /** * TODO */ public function checkRequestParameters(array $parameters, $required = TRUE) { foreach ($parameters as $parameter) { $this->checkRequestParameter($parameter, $required); } return TRUE; } /** * TODO */ public function getUserErrorID($phrase_name) { switch ($phrase_name) { case 'please_enter_value_for_all_required_fields': return 30; case 'please_enter_valid_password': return 31; case 'please_enter_name_that_is_at_least_x_characters_long': return 32; case 'please_enter_name_that_is_at_most_x_characters_long': return 33; case 'please_enter_another_name_disallowed_words': return 34; case 'please_enter_another_name_required_format': return 35; case 'please_enter_name_that_does_not_contain_any_censored_words': return 36; case 'please_enter_name_without_using_control_characters': return 37; case 'please_enter_name_that_does_not_contain_comma': return 38; case 'please_enter_name_that_does_not_resemble_an_email_address': return 39; case 'usernames_must_be_unique': return 40; case 'please_enter_valid_email': return 41; case 'email_addresses_must_be_unique': return 42; case 'email_address_you_entered_has_been_banned_by_administrator': return 43; case 'please_select_valid_time_zone': return 44; case 'please_enter_custom_title_that_does_not_contain_any_censored_words': return 45; case 'please_enter_another_custom_title_disallowed_words': return 46; case 'please_enter_valid_date_of_birth': return 47; case 'you_cannot_delete_your_own_account': return 48; case 'please_enter_valid_value': return 49; default: return 0; } } /** * Gets the error message and replaces {ERROR} with the $extra parameter. */ public function getError($error, $extra = NULL, $extra2 = NULL, $error_type = self::GENERAL_ERROR) { if ($error_type == NULL) { $error_type = self::GENERAL_ERROR; } if ($error_type == self::GENERAL_ERROR) { if (!array_key_exists($error, $this->general_errors)) { $error = 0; } $error_string = $this->general_errors[$error]; } else if ($error_type == self::USER_ERROR) { if (!array_key_exists($error, $this->user_errors)) { $error = 0; } $error_string = $this->user_errors[$error]; } if ($extra !== NULL) { $error_string = str_replace('{ERROR}', $extra, $error_string); } if ($extra2 !== NULL) { $error_string = str_replace('{ERROR2}', $extra2, $error_string); } return array('id' => $error, 'message' => $error_string); } /** * Throw the error message. */ public function throwError($error, $extra = NULL, $extra2 = NULL) { if ($error == self::USER_ERROR || $error == self::THREAD_ERROR || $error == self::POST_ERROR) { if ($error == self::USER_ERROR) { $error_key = 'user'; } else if ($error == self::THREAD_ERROR) { $error_key = 'thread'; } else if ($error == self::POST_ERROR) { $error_key = 'post'; } if ($extra2 == NULL) { $extra2 = 'performing a ' . $error_key . ' action'; } $user_error = $this->getError($extra['error_id'], NULL, NULL, self::USER_ERROR); $general_error = $this->getError(7, $extra2, $user_error['message']); $error_response = array( 'error' => $general_error['id'], 'message' => $general_error['message'], $error_key . '_error_id' => $user_error['id'], $error_key . '_error_field' => $extra['error_field'], $error_key . '_error_key' => $extra['error_key'], $error_key . '_error_phrase' => $extra['error_phrase'] ); } else { if (is_array($extra)) { $extra = implode(', ', $extra); } if (is_array($extra2)) { $extra2 = implode(', ', $extra2); } $error = $this->getError($error, $extra, $extra2, $error_type); $error_response = array('error' => $error['id'], 'message' => $error['message']); } // Throw a 400 error. header('HTTP/1.1 400 API error', TRUE, 400); // Send error. $this->sendResponse($error_response); } private function handleUserError($user_results, $error_key, $error_message) { if (!empty($user_results['error'])) { // Contains errors, process errors. if (is_array($user_results['errors'])) { // The error message was an array, loop through the messages. $error_keys = array(); foreach ($user_results['errors'] as $error_field => $error) { if (!($error instanceof XenForo_Phrase)) { $post_error = array( 'error_id' => 1, 'error_key' => 'field_not_recognised', 'error_field' => $error_field, 'error_phrase' => $error ); $this->throwError(self::USER_ERROR, $post_error, $error_message); } // Let's init the error array. $post_error = array( 'error_id' => $this->getUserErrorID($error->getPhraseName()), 'error_key' => $error->getPhraseName(), 'error_field' => $error_field, 'error_phrase' => $error->render() ); $this->throwError(self::USER_ERROR, $post_error, $error_message); } } else { $post_error = array( 'error_id' => $user_results['error'], 'error_key' => 'general_user_' . $error_key, 'error_phrase' => $user_results['errors'] ); $this->throwError(self::USER_ERROR, $post_error, $error_message); // Throw error message. } } else { // Reesult was successful, return results. $this->sendResponse($user_results); } } /** * Processes the REST request. */ public function processRequest() { // Check if the action is an user action. if ($this->isUserAction()) { if ($this->hasRequest('value')) { if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } // Create a user variable with the 'value' argument. $user = $this->xenAPI->getUser($this->getRequest('value')); if (!$user->isRegistered()) { // Throw error if the 'value' user is not registered. $this->throwError(4, 'user', $this->getRequest('value')); } } else if ($this->hasRequest('hash')) { // The 'value' argument was not set, check if hash is an API key. if ($this->hasAPIKey() && !isset($this->grab_as)) { /** * The 'hash' argument is an API key, and the 'value' argument * is required but not set, throw error. */ $this->throwError(3, 'value'); } // Get the user from the hash. $user = $this->getUser(); } else { // Nor the 'value' argument or the 'hash' argument has been set, throw error. $this->throwError(3, 'value'); } if ($this->hasRequest('with_upgrades')) { $user_upgrades = $this->getXenAPI()->getUserUpgrades($user); if (!$user_upgrades && $this->hasRequest('user')) { $this->throwError(4, 'user upgrades', $this->getRequest('user')); } $user->data['upgrades'] = $user_upgrades; } } switch (strtolower($this->getAction())) { case 'authenticate': /** * Authenticates the user and returns the hash that the user has to use for future requests. * * EXAMPLE: * - api.php?action=authenticate&username=USERNAME&password=PASSWORD */ if (!$this->hasRequest('username')) { // The 'username' argument has not been set, throw error. $this->throwError(3, 'username'); } else if (!$this->getRequest('username')) { // Throw error if the 'username' argument is set but empty. $this->throwError(1, 'username'); } else if (!$this->hasRequest('password')) { // The 'password' argument has not been set, throw error. $this->throwError(3, 'password'); } else if (!$this->getRequest('password')) { // Throw error if the 'password' argument is set but empty. $this->throwError(1, 'password'); } // Get the user object. $user = $this->xenAPI->getUser($this->getRequest('username')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('username')); } else { // Requested user was registered, check authentication. if ($user->validateAuthentication($this->getRequest('password'))) { // Authentication was valid, grab the user's authentication record. $record = $user->getAuthenticationRecord(); $ddata = unserialize($record['data']); // Send the hash in responsel. $this->sendResponse(array('hash' => base64_encode($ddata['hash']))); } else { // The username or password was wrong, throw error. $this->throwError(5, 'Invalid username or password!'); } } case 'createalert': if (!$this->hasRequest('user')) { // The 'user' argument has not been set, throw error. $this->throwError(3, 'user'); } else if (!$this->getRequest('user')) { // Throw error if the 'user' argument is set but empty. $this->throwError(1, 'user'); } else if (!$this->hasRequest('cause_user')) { // The 'cause_user' argument has not been set, throw error. $this->throwError(3, 'cause_user'); } else if (!$this->getRequest('cause_user')) { // Throw error if the 'cause_user' argument is set but empty. $this->throwError(1, 'cause_user'); } else if (!$this->hasRequest('content_type')) { // The 'content_type' argument has not been set, throw error. $this->throwError(3, 'content_type'); } else if (!$this->getRequest('content_type')) { // Throw error if the 'content_type' argument is set but empty. $this->throwError(1, 'content_type'); } else if (!$this->hasRequest('content_id')) { // The 'content_id' argument has not been set, throw error. $this->throwError(3, 'content_id'); } else if (!$this->getRequest('content_id')) { // Throw error if the 'content_id' argument is set but empty. $this->throwError(1, 'content_id'); } else if (!$this->hasRequest('alert_action')) { // The 'alert_action' argument has not been set, throw error. $this->throwError(3, 'alert_action'); } else if (!$this->getRequest('alert_action')) { // Throw error if the 'alert_action' argument is set but empty. $this->throwError(1, 'alert_action'); } $alert_user = $this->getXenAPI()->getUser($this->getRequest('user')); if (!$alert_user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('user')); } $cause_user = $this->getXenAPI()->getUser($this->getRequest('cause_user')); if (!$cause_user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'cause_user', $this->getRequest('cause_user')); } $alert_data = array( 'content_type' => $this->getRequest('content_type'), 'content_id' => $this->getRequest('content_id'), 'action' => $this->getRequest('alert_action') ); // Create the thread object. $alert_results = $this->xenAPI->createAlert($alert_user, $cause_user, $alert_data); // Alert was successful, return results. $this->sendResponse($alert_results); case 'createconversation': /** * TODO * * EXAMPLE: * - api.php */ if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } $conversation_data = array(); // Array of required parameters. $required_parameters = array('recipients', 'title', 'message'); // Array of additional parameters. $additional_parameters = array('open_invite', 'conversation_locked'); foreach ($required_parameters as $required_parameter) { // Check if the required parameter is set and not empty. $this->checkRequestParameter($required_parameter); // Set the request value. $conversation_data[$required_parameter] = $this->getRequest($required_parameter); } if (strpos($this->getRequest('recipients'), ',') !== FALSE) { $recipient_array = explode(',', $this->getRequest('recipients')); foreach ($recipient_array as $recipient) { $user = $this->getXenAPI()->getUser($recipient); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $recipient); } } } else { $user = $this->getXenAPI()->getUser($this->getRequest('recipients')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('recipients')); } } foreach ($additional_parameters as $additional_parameter) { if ($this->hasRequest($additional_parameter)) { // Set the request value. $conversation_data[$additional_parameter] = TRUE; } } // Create the conversation object. $conversation_results = $this->xenAPI->createConversation($this->getUser(), $conversation_data); $this->handleUserError($conversation_results, 'conversation_creation_error', 'creating a new conversation'); case 'createconversationreply': /** * TODO * * EXAMPLE: * - api.php */ if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } $conversation_reply_data = array(); // Array of required parameters. $required_parameters = array('conversation_id', 'message'); foreach ($required_parameters as $required_parameter) { // Check if the required parameter is set and not empty. $this->checkRequestParameter($required_parameter); // Set the request value. $conversation_reply_data[$required_parameter] = $this->getRequest($required_parameter); } // Try to grab the thread from XenForo. $conversation = $this->getXenAPI()->getConversation($this->getRequest('conversation_id'), $this->getUser()); if ($conversation == NULL) { // Could not find the conversation, throw error. $this->throwError(19, 'conversation', $this->getRequest('conversation_id')); } // Create the conversation reply object. $conversation_reply_results = $this->xenAPI->createConversationReply($this->getUser(), $conversation_reply_data); $this->handleUserError($conversation_reply_results, 'conversation_reply_creation_error', 'creating a new conversation reply'); case 'createpost': /** * TODO * * EXAMPLE: * - api.php */ if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } if (!$this->hasRequest('thread_id')) { // The 'thread_id' argument has not been set, throw error. $this->throwError(3, 'thread_id'); } else if (!$this->getRequest('thread_id')) { // Throw error if the 'thread_id' argument is set but empty. $this->throwError(1, 'thread_id'); } // Try to grab the thread from XenForo. $thread = $this->getXenAPI()->getThread($this->getRequest('thread_id'), array(), $this->getUser()); if ($thread === NULL) { // Could not find the thread, throw error. $this->throwError(19, 'thread', $this->getRequest('thread_id')); } if (!$this->hasRequest('message')) { // The 'message' argument has not been set, throw error. $this->throwError(3, 'message'); } else if (!$this->getRequest('message')) { // Throw error if the 'message' argument is set but empty. $this->throwError(1, 'message'); } $post_data = array( 'thread_id' => $thread['thread_id'], 'message' => $this->getRequest('message') ); // Create the post object. $post_results = $this->xenAPI->createPost($this->getUser(), $post_data); $this->handleUserError($post_results, 'post_creation_error', 'creating a new post'); case 'createprofilepost': /** * TODO * * EXAMPLE: * - api.php */ // Array of required parameters. $required_parameters = array('message'); foreach ($required_parameters as $required_parameter) { // Check if the required parameter is set and not empty. $this->checkRequestParameter($required_parameter); } if ($this->hasRequest('user')) { if (!$this->getRequest('user')) { // Throw error if the 'user' argument is set but empty. $this->throwError(1, 'user'); } $profile_user = $this->getXenAPI()->getUser($this->getRequest('user')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('user')); } } else { $profile_user = $user; } $profile_post_data = array( 'user_id' => $profile_user->data['user_id'], 'message' => $this->getRequest('message') ); // Create the post object. $profile_post_results = $this->xenAPI->createProfilePost($user, $profile_post_data); $this->handleUserError($profile_post_results, 'profile_post_creation_error', 'creating a new profile post'); case 'createprofilepostcomment': /** * TODO * * EXAMPLE: * - api.php */ if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } // Array of required parameters. $required_parameters = array('profile_post_id', 'message'); foreach ($required_parameters as $required_parameter) { // Check if the required parameter is set and not empty. $this->checkRequestParameter($required_parameter); } // Try to grab the node from XenForo. $profile_post = $this->getXenAPI()->getProfilePost($this->getRequest('profile_post_id'), array(), $this->getUser()); if ($profile_post == NULL) { // Could not find the node, throw error. $this->throwError(19, 'profile post', $this->getRequest('profile_post_id')); } $profile_post_comment_data = array( 'profile_post_id' => $profile_post['profile_post_id'], 'profile_user_id' => $profile_post['profile_user_id'], 'message' => $this->getRequest('message') ); // Create the post object. $profile_post_comment_results = $this->xenAPI->createProfilePostComment($this->getUser(), $profile_post_comment_data); $this->handleUserError($profile_post_comment_results, 'profile_post_comment_creation_error', 'creating a new profile post comment'); case 'createthread': /** * TODO * * EXAMPLE: * - api.php */ if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } if (!$this->hasRequest('node_id')) { // The 'node_id' argument has not been set, throw error. $this->throwError(3, 'node_id'); } else if (!$this->getRequest('node_id')) { // Throw error if the 'node_id' argument is set but empty. $this->throwError(1, 'node_id'); } // Try to grab the node from XenForo. $node = $this->getXenAPI()->getNode($this->getRequest('node_id'), array(), $this->getUser()); if ($node == NULL) { // Could not find the node, throw error. $this->throwError(19, 'node', $this->getRequest('node_id')); } if (!$this->hasRequest('title')) { // The 'title' argument has not been set, throw error. $this->throwError(3, 'title'); } else if (!$this->getRequest('title')) { // Throw error if the 'title' argument is set but empty. $this->throwError(1, 'title'); } if (!$this->hasRequest('message')) { // The 'message' argument has not been set, throw error. $this->throwError(3, 'message'); } else if (!$this->getRequest('message')) { // Throw error if the 'message' argument is set but empty. $this->throwError(1, 'message'); } $thread_data = array(); // Array of additional parameters. $additional_parameters = array('prefix_id', 'discussion_open', 'discussion_state', 'sticky'); foreach ($additional_parameters as $additional_parameter) { // Check if the additional parameter is set and not empty. $this->checkRequestParameter($additional_parameter, FALSE); if ($this->getRequest($additional_parameter)) { // Set the request value. $thread_data[$additional_parameter] = $this->getRequest($additional_parameter); } } // Check if the discussion state that is set exists. if (isset($thread_data['discussion_state']) && !in_array($thread_data['discussion_state'], ['visible', 'moderated', 'deleted'])) { // Discussion state could not be found in the discussion state list, throw error. $this->throwError(24, $this->getRequest('discussion_state'), implode(', ', ['visible', 'moderated', 'deleted'])); } $thread_data += array( 'node_id' => $node['node_id'], 'title' => $this->getRequest('title'), 'message' => $this->getRequest('message') ); // Create the thread object. $thread_results = $this->xenAPI->createThread($this->getUser(), $thread_data); $this->handleUserError($thread_results, 'thread_creation_error', 'creating a new thread'); case 'deletepost': /** * TODO * * EXAMPLE: * - api.php */ if (!$this->hasRequest('post_id')) { // The 'post_id' argument has not been set, throw error. $this->throwError(3, 'post_id'); } else if (!$this->getRequest('post_id')) { // Throw error if the 'post_id' argument is set but empty. $this->throwError(1, 'post_id'); } if ($this->hasRequest('reason')) { if (!$this->getRequest('reason')) { // Throw error if the 'reason' argument is set but empty. $this->throwError(1, 'reason'); } $reason = $this->getRequest('reason'); } else { $reason = NULL; } // Try to grab the post from XenForo. $post = $this->getXenAPI()->getPost($this->getRequest('post_id'), array(), $this->getUser()); if ($post == NULL) { // Could not find the post, throw error. $this->throwError(19, 'post', $this->getRequest('post_id')); } $delete_results = $this->xenAPI->deletePost($this->getRequest('post_id'), $reason, $this->hasRequest('hard_delete'), $this->getUser()); $this->handleUserError($delete_results, 'post_deletion_error', 'deleting post'); case 'deleteuser': /** * TODO * * EXAMPLE: * - api.php */ if ($this->hasRequest('value')) { if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $user = $this->getRequest('value'); } else if ($this->hasAPIKey()) { if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $user = $this->getRequest('value'); } else { $user = NULL; } //if ($this->hasAPIKey() || $this->getUser()->isAdmin()) { if ($this->hasRequest('reason')) { if (!$this->getRequest('reason')) { // Throw error if the 'reason' argument is set but empty. $this->throwError(1, 'reason'); } $reason = $this->getRequest('reason'); } else { $reason = NULL; } // Try to grab the user from XenForo. $user = $this->getXenAPI()->getUser($user); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('value')); } $delete_results = $this->getXenAPI()->deleteUser($user); $this->handleUserError($delete_results, 'user_deletion_error', 'deleting user'); case 'editpost': if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } if (!$this->hasRequest('post_id')) { // The 'post_id' argument has not been set, throw error. $this->throwError(3, 'post_id'); } else if (!$this->getRequest('post_id')) { // Throw error if the 'post_id' argument is set but empty. $this->throwError(1, 'post_id'); } $post = $this->getXenAPI()->getPost($this->getRequest('post_id'), array(), $this->getUser()); if ($post === NULL) { // Could not find the post, throw error. $this->throwError(19, 'post', $this->getRequest('post_id')); } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) { if (isset($this->grab_as)) { // Post was found but the 'grab_as' user is not permitted to view the post. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post'); } else { // Post was found but the user is not permitted to view the post. $this->throwError(20, 'You do', 'this post'); } } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) { // Post was found but the 'grab_as' user is not permitted to view the thread. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post'); } // List of fields that are accepted to be edited. $edit_fields = array('thread_id', 'message'); // List of fields that the request should ignore. $ignore_fields = array('hash', 'action', 'grab_as'); // Let's check which fields are set. foreach ($this->data as $data_key => $data_item) { if (!in_array($data_key, $ignore_fields) && in_array($data_key, $edit_fields) && $this->checkRequestParameter($data_key, FALSE)) { $edit_data[$data_key] = $data_item; } } if (count($edit_data) == 0) { // There are no fields set, throw error. $this->throwError(8, $edit_fields); } else if (array_key_exists('thread_id', $edit_data)) { $thread = $this->getXenAPI()->getThread($edit_data['thread_id'], array(), $this->getUser()); if ($thread == NULL) { // Could not find the thread, throw error. $this->throwError(19, 'thread', $edit_data['thread_id']); } } // Get edit results. $edit_results = $this->getXenAPI()->editPost($post, $this->getUser(), $edit_data); if (empty($edit_results['error'])) { // Edit was successful, return results. $this->sendResponse($edit_results); } else { // The registration failed, process errors. if (is_array($edit_results['errors'])) { // The error message was an array, loop through the messages. $error_keys = array(); foreach ($edit_results['errors'] as $error_field => $error) { if (!($error instanceof XenForo_Phrase)) { $edit_error = array( 'error_id' => 1, 'error_key' => 'field_not_recognised', 'error_field' => $error_field, 'error_phrase' => $error ); // Throw error message. $this->throwError(self::POST_ERROR, $edit_error, 'editing a post'); } // Let's init the edit error array. $edit_error = array( 'error_id' => $this->getUserErrorID($error->getPhraseName()), 'error_key' => $error->getPhraseName(), 'error_field' => $error_field, 'error_phrase' => $error->render() ); // Throw error message. $this->throwError(self::POST_ERROR, $edit_error, 'editing a post'); } } else { $edit_error = array( 'error_id' => $edit_results['error'], 'error_key' => 'general_post_edit_error', 'error_phrase' => $edit_results['errors'] ); // Throw error message. $this->throwError(self::POST_ERROR, $edit_error, 'editing a post'); } } case 'editthread': if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) { // The 'grab_as' argument has not been set, throw error. $this->throwError(3, 'grab_as'); } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) { // Throw error if the 'grab_as' argument is set but empty. $this->throwError(1, 'grab_as'); } if (!$this->hasRequest('thread_id')) { // The 'thread_id' argument has not been set, throw error. $this->throwError(3, 'thread_id'); } else if (!$this->getRequest('thread_id')) { // Throw error if the 'thread_id' argument is set but empty. $this->throwError(1, 'thread_id'); } $thread = $this->getXenAPI()->getThread($this->getRequest('thread_id'), array(), $this->getUser()); if ($thread === NULL) { // Could not find the thread, throw error. $this->throwError(19, 'thread', $this->getRequest('thread_id')); } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) { if (isset($this->grab_as)) { // Thread was found but the 'grab_as' user is not permitted to view the thread. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread'); } else { // Thread was found but the user is not permitted to view the thread. $this->throwError(20, 'You do', 'this thread'); } } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) { // Thread was found but the 'grab_as' user is not permitted to view the thread. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread'); } // List of fields that are accepted to be edited. $edit_fields = array('node_id', 'title', 'prefix_id', 'discussion_open', 'sticky'); // TODO: add support for message editing // List of fields that the request should ignore. $ignore_fields = array('hash', 'action', 'grab_as'); // Let's check which fields are set. foreach ($this->data as $data_key => $data_item) { if (!in_array($data_key, $ignore_fields) && in_array($data_key, $edit_fields) && $this->checkRequestParameter($data_key, FALSE)) { $edit_data[$data_key] = $data_item; } } if (count($edit_data) == 0) { // There are no fields set, throw error. $this->throwError(8, $edit_fields); } else if (array_key_exists('node_id', $edit_data)) { $node = $this->getXenAPI()->getNode($edit_data['node_id'], array(), $this->getUser()); if ($node == NULL) { // Could not find the node, throw error. $this->throwError(19, 'node', $edit_data['node_id']); } } // Get edit results. $edit_results = $this->getXenAPI()->editThread($thread, $this->getUser(), $edit_data); if (empty($edit_results['error'])) { // Edit was successful, return results. $this->sendResponse($edit_results); } else { // The registration failed, process errors. if (is_array($edit_results['errors'])) { // The error message was an array, loop through the messages. $error_keys = array(); foreach ($edit_results['errors'] as $error_field => $error) { if (!($error instanceof XenForo_Phrase)) { $edit_error = array( 'error_id' => 1, 'error_key' => 'field_not_recognised', 'error_field' => $error_field, 'error_phrase' => $error ); // Throw error message. $this->throwError(self::THREAD_ERROR, $edit_error, 'editing a thread'); } // Let's init the edit error array. $edit_error = array( 'error_id' => $this->getUserErrorID($error->getPhraseName()), 'error_key' => $error->getPhraseName(), 'error_field' => $error_field, 'error_phrase' => $error->render() ); // Throw error message. $this->throwError(self::THREAD_ERROR, $edit_error, 'editing a thread'); } } else { $edit_error = array( 'error_id' => $edit_results['error'], 'error_key' => 'general_thread_edit_error', 'error_phrase' => $edit_results['errors'] ); // Throw error message. $this->throwError(self::THREAD_ERROR, $edit_error, 'editing a thread'); } } case 'edituser': /** * Edits the user. */ if (!$this->hasRequest('user')) { // The 'user' argument has not been set, throw error. $this->throwError(3, 'user'); } else if (!$this->getRequest('user')) { // Throw error if the 'user' argument is set but empty. $this->throwError(1, 'user'); } if ($this->hasRequest('custom_field_identifier')) { if (!$this->getRequest('custom_field_identifier')) { // Throw error if the 'custom_field_identifier' argument is set but empty. $this->throwError(1, 'custom_field_identifier'); } $user = $this->getXenAPI()->getUser($this->getRequest('user'), array('custom_field' => $this->getRequest('custom_field_identifier'))); } else { // Get the user object. $user = $this->getXenAPI()->getUser($this->getRequest('user')); } if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('user')); } // Init the edit array. $edit_data = array(); if ($this->hasRequest('group')) { // Request has value. if (!$this->getRequest('group')) { // Throw error if the 'group' argument is set but empty. $this->throwError(1, 'group'); } $group = $this->getXenAPI()->getGroup($this->getRequest('group')); if (!$group) { $edit_error = array( 'error_id' => 2, 'error_key' => 'group_not_found', 'error_field' => 'group', 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest('group') . '"' ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); } // Set the group id of the edit. $edit_data['group_id'] = $group['user_group_id']; } $group_fields = array('add_groups', 'remove_groups'); foreach ($group_fields as $group_field) { if (!$this->hasRequest($group_field)) { continue; } // Request has value. if (!$this->getRequest($group_field)) { // Throw error if the $group_field argument is set but empty. $this->throwError(1, $group_field); } // Initialize the array. $edit_data[$group_field] = array(); // Check if value is an array. if (strpos($this->getRequest($group_field), ',') !== FALSE) { // Value is an array, explode it. $groups = explode(',', $this->getRequest($group_field)); // Loop through the group values. foreach ($groups as $group_value) { // Grab the group from the group value. $group = $this->getXenAPI()->getGroup($group_value); // Check if group was found. if (!$group) { // Group was not found, throw error. $edit_error = array( 'error_id' => 2, 'error_key' => 'group_not_found', 'error_field' => $group_field, 'error_phrase' => 'Could not find group with parameter "' . $group_value . '" in array "' . $this->getRequest('add_group') . '"' ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); } // Add the group_id to the the add_group array. $edit_data[$group_field][] = $group['user_group_id']; } } else { // Grab the group from the group value. $group = $this->getXenAPI()->getGroup($this->getRequest($group_field)); // Check if group was found. if (!$group) { // Group was not found, throw error. $edit_error = array( 'error_id' => 2, 'error_key' => 'group_not_found', 'error_field' => $group_field, 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest($group_field) . '"' ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); } // Add the group_id to the the add_groups array. $edit_data[$group_field][] = $group['user_group_id']; } } if ($this->hasRequest('custom_fields')) { // Request has value. if (!$this->getRequest('custom_fields')) { // Throw error if the 'custom_fields' argument is set but empty. $this->throwError(1, 'custom_fields'); } $custom_fields = $this->getCustomArray($this->getRequest('custom_fields')); // Check if we found any valid custom fields, throw error if not. if (count($custom_fields) == 0) { // The custom fields array was empty, throw error. $edit_error = array( 'error_id' => 5, 'error_key' => 'invalid_custom_fields', 'error_field' => 'custom_fields', 'error_phrase' => 'The custom fields values were invalid, valid values are: ' . 'custom_fields=custom_field1=custom_value1,custom_field2=custom_value2 ' . 'but got: "' . $this->getRequest('custom_fields') . '" instead' ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); } $edit_data['custom_fields'] = $custom_fields; } // List of fields that are accepted to be edited. $edit_fields = array('username', 'password', 'email', 'gender', 'custom_title', 'style_id', 'timezone', 'visible', 'dob_day', 'dob_month', 'dob_year', 'user_state', 'trophy_points'); // List of fields that the request should ignore. $ignore_fields = array('hash', 'action', 'user'); // Let's check which fields are set. foreach ($this->data as $data_key => $data_item) { if (!in_array($data_key, $ignore_fields) && in_array($data_key, $edit_fields) && $this->checkRequestParameter($data_key, FALSE)) { $edit_data[$data_key] = $data_item; } } if (count($edit_data) == 0) { // There are no fields set, throw error. $this->throwError(8, $edit_fields); } // Get edit results. $edit_results = $this->getXenAPI()->editUser($user, $edit_data); if (!empty($edit_results['error'])) { // The registration failed, process errors. if (is_array($edit_results['errors'])) { // The error message was an array, loop through the messages. $error_keys = array(); foreach ($edit_results['errors'] as $error_field => $error) { if (!($error instanceof XenForo_Phrase)) { $edit_error = array( 'error_id' => 1, 'error_key' => 'field_not_recognised', 'error_field' => $error_field, 'error_phrase' => $error ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); } // Let's init the edit error array. $edit_error = array( 'error_id' => $this->getUserErrorID($error->getPhraseName()), 'error_key' => $error->getPhraseName(), 'error_field' => $error_field, 'error_phrase' => $error->render() ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); } } else { $edit_error = array( 'error_id' => $edit_results['error'], 'error_key' => 'general_user_edit_error', 'error_phrase' => $edit_results['errors'] ); $this->throwError(self::USER_ERROR, $edit_error, 'editing an user'); // Throw error message. } } else { // Edit was successful, return results. $this->sendResponse($edit_results); } case 'getactions': /** * Returns the actions and their permission levels. * * EXAMPLE: * - api.php?action=getActions */ /* // TODO: Only show actions depending on what permission level the user is. $temp = array(); foreach ($this->actions as $action => $permission) { $temp[$action] = $permission; } */ // Send the response. $this->sendResponse($this->actions); case 'getaddon': /** * Returns the addon information depending on the 'value' argument. * * NOTE: Only addon ID's can be used for the 'value' parameter. * Addon ID's can be found by using the 'getAddons' action. * * EXAMPLE: * - api.php?action=getAddon&value=PostRating&hash=USERNAME:HASH * - api.php?action=getAddon&value=PostRating&hash=API_KEY */ if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Try to grab the addon from XenForo. $addon = $this->getXenAPI()->getAddon($string); if (!$addon->isInstalled()) { // Could not find the addon, throw error. $this->throwError(13, $string); } else { // Addon was found, send response. $this->sendResponse(Addon::getLimitedData($addon)); } case 'getaddons': /** * Returns a list of addons, if a type is not specified or not supported, * default (all) is used instead. * * Options for the 'type' argument are: * - all: This is default, and will return all the addons, ignoring if they are installed or not. * - enabled: Fetches all the addons that are enabled, ignoring the disabled ones. * - disabled: Fetches all the addons that are disabled, ignoring the enabled ones. * * For more information, see /library/XenForo/Model/Alert.php. * * EXAMPLES: * - api.php?action=getAddons&hash=USERNAME:HASH * - api.php?action=getAddons&hash=API_KEY * - api.php?action=getAddons&type=enabled&hash=USERNAME:HASH * - api.php?action=getAddons&type=enabled&hash=API_KEY */ /* * Check if the request has the 'type' argument set, * if it doesn't it uses the default (all). */ if ($this->hasRequest('type')) { if (!$this->getRequest('type')) { // Throw error if the 'type' argument is set but empty. $this->throwError(1, 'type'); } // Use the value from the 'type' argument to get the alerts. $installed_addons = $this->xenAPI->getAddons($this->getRequest('type')); } else { // Use the default type to get the alerts. $installed_addons = $this->xenAPI->getAddons(); } // Create an array for the addons. $addons = array(); // Loop through all the addons and strip out any information that we don't need. foreach ($installed_addons as $addon) { $addons[] = Addon::getLimitedData($addon); } // Send the response. $this->sendResponse(array('count' => count($addons), 'addons' => $addons)); case 'getalerts': /** * Grabs the alerts from the specified user, if type is not specified, * default (recent alerts) is used instead. * * NOTE: The 'value' argument will only work for the user itself and * not on others users unless the permission argument for the * 'getalerts' action is changed (default permission: private). * * Options for the 'type' argument are: * - fetchPopupItems: Fetch alerts viewed in the last options:alertsPopupExpiryHours hours. * - fetchRecent: Fetch alerts viewed in the last options:alertExpiryDays days. * - fetchAll: Fetch alerts regardless of their view_date. * * For more information, see /library/XenForo/Model/Alert.php. * * EXAMPLES: * - api.php?action=getAlerts&hash=USERNAME:HASH * - api.php?action=getAlerts&type=fetchAll&hash=USERNAME:HASH * - api.php?action=getAlerts&value=USERNAME&hash=USERNAME:HASH * - api.php?action=getAlerts&value=USERNAME&type=fetchAll&hash=USERNAME:HASH * - api.php?action=getAlerts&value=USERNAME&hash=API_KEY * - api.php?action=getAlerts&value=USERNAME&type=fetchAll&hash=API_KEY */ /* * Check if the request has the 'type' argument set, * if it doesn't it uses the default (fetchRecent). */ if ($this->hasRequest('type')) { if (!$this->getRequest('type')) { // Throw error if the 'type' argument is set but empty. $this->throwError(1, 'type'); } // Use the value from the 'type' argument to get the alerts. $data = $user->getAlerts($this->getRequest('type')); } else { // Use the default type to get the alerts. $data = $user->getAlerts(); } // Send the response. $this->sendResponse($data); case 'getavatar': /** * Returns the avatar of the requested user. * * Options for the 'size' argument are: * - s (Small) * - m (Medium) * - l (Large) * * NOTE: The default avatar size is 'Medium'. * * EXAMPLES: * - api.php?action=getAvatar&hash=USERNAME:HASH * - api.php?action=getAvatar&size=M&hash=USERNAME:HASH * - api.php?action=getAvatar&value=USERNAME&hash=USERNAME:HASH * - api.php?action=getAvatar&value=USERNAME&size=M&hash=USERNAME:HASH * - api.php?action=getAvatar&value=USERNAME&hash=API_KEY * - api.php?action=getAvatar&value=USERNAME&size=M&hash=API_KEY */ if ($this->hasRequest('size')) { if (!$this->getRequest('size')) { // Throw error if the 'size' argument is set but empty. $this->throwError(1, 'size'); } // Use the value from the 'size' argument. $size = strtolower($this->getRequest('size')); if (!in_array($size, array('s', 'm', 'l'))) { /** * The value from the 'size' argument was not valid, * use default size (medium) instead. */ $size = 'm'; } } else { // No specific size was requested, use default size (medium): $size = 'm'; } // Send the response. $this->sendResponse(array('avatar' => $user->getAvatar($size))); case 'getconversation': if (!$this->hasRequest('conversation_id')) { // The 'conversation_id' argument has not been set, throw error. $this->throwError(3, 'conversation_id'); } else if (!$this->getRequest('conversation_id')) { // Throw error if the 'conversation_id' argument is set but empty. $this->throwError(1, 'conversation_id'); } // Try to grab the thread from XenForo. $conversation = $this->getXenAPI()->getConversation($this->getRequest('conversation_id'), $user, array('join' => XenForo_Model_Conversation::FETCH_FIRST_MESSAGE)); if ($conversation == NULL) { // Could not find the conversation, throw error. $this->throwError(19, 'conversation', $this->getRequest('conversation_id')); } // Send the response. $this->sendResponse($conversation); case 'getgroup': /** * Returns the group information depending on the 'value' argument. * * NOTE: Only group titles, user titles and group ID's can be used for the 'value' parameter. * * EXAMPLE: * - api.php?action=getGroup&value=1 * - api.php?action=getGroup&value=Guest */ if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Get the group from XenForo. $group = $this->getXenAPI()->getGroup($string); if (!$group) { // Could not find any groups, throw error. $this->throwError(4, 'group', $string); } else { // Group was found, send response. $this->sendResponse($group); } case 'getconversations': /** * Grabs the conversations from the specified user. * * NOTE: The 'value' argument will only work for the user itself and * not on others users unless the permission argument for the * 'getconversations' action is changed (default permission: private). * * EXAMPLES: * - api.php?action=getConversations&hash=USERNAME:HASH * - api.php?action=getConversations&value=USERNAME&hash=USERNAME:HASH * - api.php?action=getConversations&value=USERNAME&hash=API_KEY */ // Init variables. $conditions = array(); $this->setLimit(10); $fetch_options = array('limit' => $this->limit, 'join' => XenForo_Model_Conversation::FETCH_FIRST_MESSAGE); // Grab the conversations. $conversations = $this->getXenAPI()->getConversations($user, $conditions, $fetch_options); // Send the response. $this->sendResponse(array('count' => count($conversations), 'conversations' => $conversations)); case 'getgroup': /** * Returns the group information depending on the 'value' argument. * * NOTE: Only group titles, user titles and group ID's can be used for the 'value' parameter. * * EXAMPLE: * - api.php?action=getGroup&value=1 * - api.php?action=getGroup&value=Guest */ if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Get the group from XenForo. $group = $this->getXenAPI()->getGroup($string); if (!$group) { // Could not find any groups, throw error. $this->throwError(4, 'group', $string); } else { // Group was found, send response. $this->sendResponse($group); } case 'getnode': /** * Returns the node information depending on the 'value' argument. * * NOTE: Only node ID's can be used for the 'value' parameter. * Node ID's can be found by using the 'getNodes' action. * * The user needs permission to see the thread if the request is * using a user hash and not an API key. * * EXAMPLE: * - api.php?action=getNode&value=4&hash=USERNAME:HASH * - api.php?action=getNode&value=4&hash=API_KEY */ if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Try to grab the node from XenForo. $node = $this->getXenAPI()->getNode($string); if ($node == NULL) { // Could not find the node, throw error. $this->throwError(19, 'node', $string); } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewNode($this->getUser(), $node)) { if (isset($this->grab_as)) { // Thread was found but the 'grab_as' user is not permitted to view the node. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this node'); } else { // Thread was found but the user is not permitted to view the node. $this->throwError(20, 'You do', 'this node'); } } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewNode($this->getUser(), $node)) { // Thread was found but the 'grab_as' user is not permitted to view the node. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this node'); } else { // Thread was found, and the request was permitted. $this->sendResponse($node); } case 'getnodes': /** * Returns a list of nodes. * * EXAMPLES: * - api.php?action=getNodes&hash=USERNAME:HASH * - api.php?action=getNodes&hash=API_KEY */ // Init variables. $this->setLimit(10); $fetch_options = array('limit' => $this->limit); // Check if request has node_type. if ($this->hasRequest('node_type')) { if (!$this->getRequest('node_type')) { // Throw error if the 'node_type' argument is set but empty. $this->throwError(1, 'node_type'); } // Set the node_type. $node_type = strtolower($this->getRequest('node_type')); // Check if the node type that is set exists. if (!in_array($node_type, $this->getXenAPI()->getNodeTypes()) && $node_type != 'all') { // Node type could not be found in the node type list, throw error. $this->throwError(23, $this->getRequest('node_type'), implode(', ', $this->getXenAPI()->getNodeTypes())); } } else { $node_type = 'all'; } // Get the nodes. $nodes = $this->getXenAPI()->getNodes($node_type, $fetch_options, $this->getUser()); // Send the response. $this->sendResponse(array('count' => count($nodes), 'nodes' => $nodes)); case 'getpost': /** * Returns the post information depending on the 'value' argument. * * NOTE: Only post ID's can be used for the 'value' parameter. * Post ID's can be found by using the 'getPosts' action. * * The user needs permission to see the thread if the request is * using a user hash and not an API key. * * EXAMPLE: * - api.php?action=getPost&value=820&hash=USERNAME:HASH * - api.php?action=getPost&value=820&hash=API_KEY */ if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Try to grab the post from XenForo. $post = $this->getXenAPI()->getPost($string, array('join' => XenForo_Model_Post::FETCH_FORUM)); if ($post == NULL) { // Could not find the post, throw error. $this->throwError(19, 'post', $string); } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) { if (isset($this->grab_as)) { // Post was found but the 'grab_as' user is not permitted to view the post. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post'); } else { // Post was found but the user is not permitted to view the post. $this->throwError(20, 'You do', 'this post'); } } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) { // Post was found but the 'grab_as' user is not permitted to view the post. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post'); } else { // Post was found, and the request was permitted. $this->sendResponse($post); } case 'getposts': /** * Returns a list of posts. * * NOTE: Only usernames and user ID's can be used for the 'author' parameter. * * EXAMPLES: * - api.php?action=getPosts&hash=USERNAME:HASH * - api.php?action=getPosts&hash=API_KEY * - api.php?action=getPosts&author=Contex&hash=USERNAME:HASH * - api.php?action=getPosts&author=1&hash=API_KEY */ // Init variables. $conditions = array(); $this->setLimit(10); $fetch_options = array('limit' => $this->limit); // Check if request has author. if ($this->hasRequest('author')) { if (!$this->getRequest('author')) { // Throw error if the 'author' argument is set but empty. $this->throwError(1, 'author'); } // Grab the user object of the author. $user = $this->xenAPI->getUser($this->getRequest('author')); if (!$user->isRegistered()) { // Throw error if the 'author' user is not registered. $this->throwError(4, 'user', $this->getRequest('author')); } // Add the user ID to the query conditions. $conditions['user_id'] = $user->getID(); unset($user); } // Check if request has node id. if ($this->hasRequest('node_id')) { if (!$this->getRequest('node_id') && (is_numeric($this->getRequest('node_id')) && $this->getRequest('node_id') != 0)) { // Throw error if the 'node_id' argument is set but empty. $this->throwError(1, 'node_id'); } else if (!is_numeric($this->getRequest('node_id'))) { // Throw error if the 'node_id' argument is set but not a number. $this->throwError(21, 'node_id'); } if (!$this->xenAPI->getNode($this->getRequest('node_id'))) { // Could not find any nodes, throw error. $this->throwError(4, 'node', $this->getRequest('node_id')); } // Add the node ID to the query conditions. $conditions['node_id'] = $this->getRequest('node_id'); } // Check if request has thread id. if ($this->hasRequest('thread_id')) { if (!$this->getRequest('thread_id') && (is_numeric($this->getRequest('thread_id')) && $this->getRequest('thread_id') != 0)) { // Throw error if the 'thread_id' argument is set but empty. $this->throwError(1, 'thread_id'); } else if (!is_numeric($this->getRequest('thread_id'))) { // Throw error if the 'thread_id' argument is set but not a number. $this->throwError(21, 'thread_id'); } if (!$this->xenAPI->getThread($this->getRequest('thread_id'))) { // Could not find any threads, throw error. $this->throwError(4, 'thread_id', $this->getRequest('thread_id')); } // Add the node ID to the query conditions. $conditions['thread_id'] = $this->getRequest('thread_id'); } // Check if the order by argument is set. $order_by_field = $this->checkOrderBy(array('post_id', 'thread_id', 'user_id', 'username', 'post_date', 'attach_count', 'likes', 'node_id')); // Add the order by options to the fetch options. if ($this->hasRequest('order_by')) { $fetch_options['order'] = $order_by_field; $fetch_options['orderDirection'] = $this->order; } // Get the posts. $posts = $this->getXenAPI()->getPosts($conditions, $fetch_options, $this->getUser()); // Send the response. $this->sendResponse(array('count' => count($posts), 'posts' => $posts)); case 'getprofilepost': /** * Returns the profile post information depending on the 'value' argument. * * NOTE: Only profile post ID's can be used for the 'value' parameter. * Profile post ID's can be found by using the 'getProfilePosts' action. * * The user needs permission to see the profile post if the request is * using a user hash and not an API key. * * EXAMPLE: * - api.php?action=getProfilePost&value=820&hash=USERNAME:HASH * - api.php?action=getProfilePost&value=820&hash=API_KEY */ if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Try to grab the profile post from XenForo. $profile_post = $this->getXenAPI()->getProfilePost($string); if ($profile_post == NULL) { // Could not find the profile post, throw error. $this->throwError(19, 'profile post', $string); } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewProfilePost($this->getUser(), $profile_post)) { if (isset($this->grab_as)) { // Thread was found but the 'grab_as' user is not permitted to view the thread. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this profile post'); } else { // Thread was found but the user is not permitted to view the profile post. $this->throwError(20, 'You do', 'this profile post'); } } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewProfilePost($this->getUser(), $profile_post)) { // Thread was found but the 'grab_as' user is not permitted to view the profile post. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this profile post'); } else { // Post was found, and the request was permitted. $this->sendResponse($profile_post); } case 'getprofileposts': /** * Returns a list of profile posts. * * NOTE: Only usernames and user ID's can be used for the 'author' parameter. * * EXAMPLES: * - api.php?action=getProfilePosts&hash=USERNAME:HASH * - api.php?action=getProfilePosts&hash=API_KEY * - api.php?action=getProfilePosts&author=Contex&hash=USERNAME:HASH * - api.php?action=getProfilePosts&author=1&hash=API_KEY */ // Init variables. $conditions = array(); $this->setLimit(10); $fetch_options = array('limit' => $this->limit); // Check if request has author. if ($this->hasRequest('author')) { if (!$this->getRequest('author')) { // Throw error if the 'author' argument is set but empty. $this->throwError(1, 'author'); } // Grab the user object of the author. $user = $this->xenAPI->getUser($this->getRequest('author')); if (!$user->isRegistered()) { // Throw error if the 'author' user is not registered. $this->throwError(4, 'user', $this->getRequest('author')); } // Add the user ID to the query conditions. $conditions['author_id'] = $user->getID(); unset($user); } // Check if request has profile user. if ($this->hasRequest('profile')) { if (!$this->getRequest('profile')) { // Throw error if the 'profile' argument is set but empty. $this->throwError(1, 'profile'); } // Grab the user object of the profile. $user = $this->xenAPI->getUser($this->getRequest('profile')); if (!$user->isRegistered()) { // Throw error if the 'author' user is not registered. $this->throwError(4, 'user', $this->getRequest('profile')); } // Add the user ID to the query conditions. $conditions['profile_id'] = $user->getID(); unset($user); } // Check if the order by argument is set. $order_by_field = $this->checkOrderBy(array('profile_post_id', 'profile_user_id', 'user_id', 'username', 'post_date', 'attach_count', 'likes', 'comment_count', 'first_comment_date', 'last_comment_date')); // Add the order by options to the fetch options. if ($this->hasRequest('order_by')) { $fetch_options['order'] = $order_by_field; $fetch_options['orderDirection'] = $this->order; } // Get the profile posts. $profile_posts = $this->getXenAPI()->getProfilePosts($conditions, $fetch_options, $this->getUser()); // Send the response. $this->sendResponse(array('count' => count($profile_posts), 'profile_posts' => $profile_posts)); case 'getresource': /** * Returns the resource information depending on the 'value' argument. * * NOTE: Only resource ID's can be used for the 'value' parameter. * Resource ID's can be found by using the 'getResources' action. * * EXAMPLE: * - api.php?action=getResource&value=1&hash=USERNAME:HASH * - api.php?action=getResource&value=1&hash=API_KEY */ /* * Check the resource addon is installed */ if (!$this->getXenAPI()->getModels()->hasModel('resource')) { $this->throwError(16, 'resource'); } $fetchOptions = array(); /* * Check if the request has the 'grab_description' argument set. */ if ($this->hasRequest('grab_description')) { // Grab resources with description $fetchOptions['join'] = XenResource_Model_Resource::FETCH_DESCRIPTION; } if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Try to grab the addon from XenForo. $resource = $this->getXenAPI()->getResource($string, $fetchOptions); if (!$resource->isValid()) { // Could not find the resource, throw error. $this->throwError(15, $string); } else { // Resource was found, send response. $this->sendResponse(Resource::getLimitedData($resource)); } case 'getresources': /** * Returns a list of resources, either all the resources, * or just the resources created by an author. * * NOTE: Only usernames and user ID's can be used for the 'author' parameter. * NOTE: Only resource category ID's can be used for the 'category_id' parameter. * * EXAMPLES: * - api.php?action=getResources&hash=USERNAME:HASH * - api.php?action=getResources&hash=API_KEY * - api.php?action=getResources&author=Contex&hash=USERNAME:HASH * - api.php?action=getResources&author=1&hash=API_KEY * - api.php?action=getResources&author=Contex&category_id=1&hash=USERNAME:HASH * - api.php?action=getResources&author=1&category_id=2&hash=API_KEY */ /* * Check the resource addon is installed */ if (!$this->getXenAPI()->getModels()->hasModel('resource')) { $this->throwError(16, 'resource'); } $conditions = array(); $fetchOptions = array(); /* * Check if the request has the 'grab_description' argument set. */ if ($this->hasRequest('grab_description')) { // Grab resources with description $fetchOptions['join'] = XenResource_Model_Resource::FETCH_DESCRIPTION; } /* * Check if the request has the 'category_id' argument set. */ if ($this->hasRequest('category_id')) { if (!$this->getRequest('category_id')) { // Throw error if the 'category_id' argument is set but empty. $this->throwError(1, 'category_id'); } // Use the value from the 'category_id' argument to set the variables. $conditions['resource_category_id'] = $this->getRequest('category_id'); } /* * Check if the request has the 'author' argument set, * if it doesn't it uses the default (all). */ if ($this->hasRequest('author')) { if (!$this->getRequest('author')) { // Throw error if the 'author' argument is set but empty. $this->throwError(1, 'author'); } // Create a user variable with the 'author' argument. $user = $this->xenAPI->getUser($this->getRequest('author')); if (!$user->isRegistered()) { // Throw error if the 'author' user is not registered. $this->throwError(4, 'user', $this->getRequest('author')); } // Use the value from the 'author' argument to set the variables. $conditions['user_id'] = $user->getID(); } $resources_list = $this->getXenAPI()->getResources($conditions, $fetchOptions); // Create an array for the resources. $resources = array(); // Loop through all the resources and strip out any information that we don't need. foreach ($resources_list as $resource) { $resources[] = Resource::getLimitedData($resource); } // Send the response. $this->sendResponse(array('count' => count($resources), 'resources' => $resources)); case 'getresourcecategories': /** * Returns a list of resource categories * * EXAMPLES: * - api.php?action=getResourceCategories&hash=USERNAME:HASH * - api.php?action=getResourceCategories&hash=API_KEY */ /* * Check the resource addon is installed */ if (!$this->getXenAPI()->getModels()->hasModel('resource')) { $this->throwError(16, 'resource'); } // Grab the resource categories. $resource_categories = $this->getXenAPI()->getResourceCategories(); // Send the response. $this->sendResponse(array('count' => count($resource_categories), 'categories' => $resource_categories)); case 'getstats': /** * Returns a summary of stats. * * NOTE: "include_deleted" will count the deleted posts/threads as well * * EXAMPLE: * - api.php?action=getStats * - api.php?action=getStats&include_deleted */ $latest_user = $this->xenAPI->getLatestUser(); if (!$this->hasRequest('include_deleted')) { $include_deleted = TRUE; } else { $include_deleted = FALSE; } $this->sendResponse(array( 'threads' => $this->xenAPI->getStatsItem('threads', $include_deleted), 'posts' => $this->xenAPI->getStatsItem('posts', $include_deleted), 'conversations' => $this->xenAPI->getStatsItem('conversations', $include_deleted), 'conversations_messages' => $this->xenAPI->getStatsItem('conversations_messages', $include_deleted), 'members' => $this->xenAPI->getStatsItem('users', $include_deleted), 'latest_member' => array('user_id' => $latest_user->getID(), 'username' => $latest_user->getUsername()), 'registrations_today' => $this->xenAPI->getStatsItem('registrations_today', $include_deleted), 'threads_today' => $this->xenAPI->getStatsItem('threads_today', $include_deleted), 'posts_today' => $this->xenAPI->getStatsItem('posts_today', $include_deleted), 'users_online' => $this->xenAPI->getUsersOnlineCount($this->getUser()) )); case 'getthread': /** * Returns the thread information depending on the 'value' argument. * * NOTE: Only thread ID's can be used for the 'value' parameter. * Thread ID's can be found by using the 'getThreads' action. * * The user needs permission to see the thread if the request is * using a user hash and not an API key. * * EXAMPLE: * - api.php?action=getThread&value=820&hash=USERNAME:HASH * - api.php?action=getThread&value=820&hash=API_KEY */ $fetchOptions = array(); if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $string = $this->getRequest('value'); // Check if request has grab_content. if ($this->hasRequest('grab_content')) { $fetchOptions['grab_content'] = TRUE; // Check if request has content_limit. if ($this->hasRequest('content_limit')) { if (!$this->getRequest('content_limit') && (is_numeric($this->getRequest('content_limit')) && $this->getRequest('content_limit') != 0)) { // Throw error if the 'content_limit' argument is set but empty. $this->throwError(1, 'content_limit'); } else if (!is_numeric($this->getRequest('content_limit'))) { // Throw error if the 'content_limit' argument is set but not a number. $this->throwError(21, 'content_limit'); } $fetchOptions['content_limit'] = $this->getRequest('content_limit'); } } // Try to grab the thread from XenForo. $thread = $this->getXenAPI()->getThread($string, $fetchOptions, $this->getUser()); if ($thread === NULL) { // Could not find the thread, throw error. $this->throwError(19, 'thread', $string); } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) { if (isset($this->grab_as)) { // Thread was found but the 'grab_as' user is not permitted to view the thread. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread'); } else { // Thread was found but the user is not permitted to view the thread. $this->throwError(20, 'You do', 'this thread'); } } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) { // Thread was found but the 'grab_as' user is not permitted to view the thread. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread'); } else { // Thread was found, and the request was permitted. $this->sendResponse($thread); } case 'getthreads': /** * Returns a list of threads. * * NOTE: Only usernames and user ID's can be used for the 'author' parameter. * * EXAMPLES: * - api.php?action=getThreads&hash=USERNAME:HASH * - api.php?action=getThreads&hash=API_KEY * - api.php?action=getThreads&author=Contex&hash=USERNAME:HASH * - api.php?action=getThreads&author=1&hash=API_KEY */ // Init variables. $conditions = array(); $this->setLimit(10); $fetch_options = array('limit' => $this->limit); // Check if request has discussion_state. if ($this->hasRequest('discussion_state')) { if (!$this->getRequest('discussion_state')) { // Throw error if the 'discussion_state ' argument is set but empty. $this->throwError(1, 'discussion_state'); } // Add the discussion state to the query conditions. $conditions['discussion_state'] = $this->getRequest('discussion_state'); } // Check if request has author. if ($this->hasRequest('author')) { if (!$this->getRequest('author')) { // Throw error if the 'author' argument is set but empty. $this->throwError(1, 'author'); } // Grab the user object of the author. $user = $this->xenAPI->getUser($this->getRequest('author')); if (!$user->isRegistered()) { // Throw error if the 'author' user is not registered. $this->throwError(4, 'user', $this->getRequest('author')); } // Add the user ID to the query conditions. $conditions['user_id'] = $user->getID(); unset($user); } // Check if request has author. if ($this->hasRequest('node_id')) { if (!$this->getRequest('node_id') && (is_numeric($this->getRequest('node_id')) && $this->getRequest('node_id') != 0)) { // Throw error if the 'node_id' argument is set but empty. $this->throwError(1, 'node_id'); } else if (!is_numeric($this->getRequest('node_id'))) { // Throw error if the 'limit' argument is set but not a number. $this->throwError(21, 'node_id'); } if (!$this->xenAPI->getNode($this->getRequest('node_id'))) { // Could not find any nodes, throw error. $this->throwError(4, 'node', $this->getRequest('node_id')); } // Add the node ID to the query conditions. $conditions['node_id'] = $this->getRequest('node_id'); } // Check if request has grab_content. if ($this->hasRequest('grab_content')) { $fetch_options['grab_content'] = TRUE; // Check if request has content_limit. if ($this->hasRequest('content_limit')) { if (!$this->getRequest('content_limit') && (is_numeric($this->getRequest('content_limit')) && $this->getRequest('content_limit') != 0)) { // Throw error if the 'content_limit' argument is set but empty. $this->throwError(1, 'content_limit'); } else if (!is_numeric($this->getRequest('content_limit'))) { // Throw error if the 'content_limit' argument is set but not a number. $this->throwError(21, 'content_limit'); } $fetch_options['content_limit'] = $this->getRequest('content_limit'); } } // Check if the order by argument is set. $order_by_field = $this->checkOrderBy(array('title', 'post_date', 'view_count', 'reply_count', 'first_post_likes', 'last_post_date')); // Add the order by options to the fetch options. if ($this->hasRequest('order_by')) { $fetch_options['order'] = $order_by_field; $fetch_options['orderDirection'] = $this->order; } // Get the threads. $threads = $this->getXenAPI()->getThreads($conditions, $fetch_options, $this->getUser()); // Send the response. $this->sendResponse(array('count' => count($threads), 'threads' => $threads)); case 'getuser': /** * Grabs and returns an user object. * * EXAMPLES: * - api.php?action=getUser&hash=USERNAME:HASH * - api.php?action=getUser&value=USERNAME&hash=USERNAME:HASH * - api.php?action=getUser&value=USERNAME&hash=API_KEY */ // Send the response. $this->sendResponse($this->stripUserData($user)); case 'getusers': /** * Searches through the usernames depending on the input. * * NOTE: Asterisk (*) can be used as a wildcard. * * EXAMPLE: * - api.php?action=getUsers&value=Contex * - api.php?action=getUsers&value=Cont* * - api.php?action=getUsers&value=C* */ if ($this->hasRequest('value') && strpos($this->getRequest('value', ',')) !== false) { $userIds = explode(',', $this->getRequest('value')); $results = []; foreach ($userIds as $userId) { $user = $this->getXenAPI()->getUser($userId); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $userId); } $results[] = $this->stripUserData($user); # TODO: only return user_id & username? } } else if ($this->hasAPIKey() && $this->hasRequest('value') && !filter_var($this->getRequest('value'), FILTER_VALIDATE_IP) === false) { $ip = $this->getRequest('value'); $users = $this->getXenAPI()->getUsersByIp($ip); $results = []; foreach ($users as $user) { $results[] = [ 'user_id' => $user['user_id'], 'username' => $user['username'], 'log_date' => $user['log_date'] ]; } } else { if ($this->hasRequest('value')) { // Request has value. if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } // Replace the wildcard with '%' for the SQL query. $string = str_replace('*', '%', $this->getRequest('value')); } else if (!$this->hasRequest('order_by')) { // Nor the 'value' argument or the 'order_by' argument has been set, throw error. $this->throwError(3, 'value'); } // Check if the order by argument is set. $order_by_field = $this->checkOrderBy(array('user_id', 'message_count', 'conversations_unread', 'register_date', 'last_activity', 'trophy_points', 'alerts_unread', 'like_count')); // Perform the SQL query and grab all the usernames and user id's. // Perform the SQL query and grab all the usernames and user id's. $results = $this->xenAPI->getDatabase()->fetchAll("SELECT `user_id`, `username`" . ($this->hasRequest('order_by') ? ", " . $this->xenAPI->getDatabase()->quote($order_by_field) : '') . " FROM `xf_user`" . ($this->hasRequest('value') ? " WHERE `username` LIKE " . $this->xenAPI->getDatabase()->quote($string) : '') . ($this->hasRequest('order_by') ? " ORDER BY `$order_by_field` " . $this->order : '') . (($this->limit > 0) ? ' LIMIT ' . $this->xenAPI->getDatabase()->quote($this->limit) : '')); } // Send the response. $this->sendResponse($results); case 'getuserupgrade': /** * TODO * * EXAMPLES: */ if (!$this->hasRequest('id')) { // The 'id' argument has not been set, throw error. $this->throwError(3, 'id'); } else if (!$this->getRequest('id')) { // Throw error if the 'id' argument is set but empty. $this->throwError(1, 'id'); } $user_upgrade = $this->getXenAPI()->getUserUpgrade($this->getRequest('id')); if (!$user_upgrade) { $this->throwError(4, 'user upgrade', $this->getRequest('id')); } // Send the response. $this->sendResponse($user_upgrade); case 'getuserupgrades': /** * TODO * * EXAMPLES: */ $user = NULL; if ($this->hasRequest('user')) { if (!$this->getRequest('user')) { // Throw error if the 'user' argument is set but empty. $this->throwError(1, 'user'); } $user = $this->getXenAPI()->getUser($this->getRequest('user')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('user')); } } $user_upgrades = $this->getXenAPI()->getUserUpgrades($user); if (!$user_upgrades && $this->hasRequest('user')) { $this->throwError(4, 'user upgrades', $this->getRequest('user')); } // Send the response. $this->sendResponse($user_upgrades); case 'downgradeuser': if (!$this->hasRequest('user')) { // The 'user' argument has not been set, throw error. $this->throwError(3, 'user'); } else if (!$this->getRequest('user')) { // Throw error if the 'user' argument is set but empty. $this->throwError(1, 'user'); } $user = $this->getXenAPI()->getUser($this->getRequest('user')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('user')); } if (!$this->hasRequest('upgrade_id')) { // The 'upgrade_id' argument has not been set, throw error. $this->throwError(3, 'upgrade_id'); } else if (!$this->getRequest('upgrade_id')) { // Throw error if the 'upgrade_id' argument is set but empty. $this->throwError(1, 'upgrade_id'); } $user_upgrades = $this->getXenAPI()->getUserUpgrades($user); if (!$user_upgrades && $this->hasRequest('user')) { $this->throwError(4, 'user upgrades', $this->getRequest('user')); } $user_upgrade_object = NULL; foreach ($user_upgrades as $user_upgrade) { if ($user_upgrade['user_upgrade_id'] == $this->getRequest('upgrade_id')) { $user_upgrade_object = $user_upgrade; } } if ($user_upgrade_object === NULL) { $this->throwError(4, 'user upgrade', $this->getRequest('upgrade_id')); } $record = $this->getXenAPI()->getUserUpgradeRecord($user_upgrade_object['user_upgrade_record_id']); $this->getXenAPI()->downgradeUserUpgrade($record); // Recheck upgrades to see if the user was downgraded. $user_upgrades = $this->getXenAPI()->getUserUpgrades($user); $user_upgrade_object = NULL; foreach ($user_upgrades as $user_upgrade) { if ($user_upgrade['user_upgrade_id'] == $this->getRequest('upgrade_id')) { $user_upgrade_object = $user_upgrade; } } if ($user_upgrade_object === NULL) { $this->sendResponse(array('success' => TRUE)); } else { $this->sendResponse(array('success' => FALSE)); } case 'upgradeuser': if (!$this->hasRequest('user')) { // The 'user' argument has not been set, throw error. $this->throwError(3, 'user'); } else if (!$this->getRequest('user')) { // Throw error if the 'user' argument is set but empty. $this->throwError(1, 'user'); } $user = $this->getXenAPI()->getUser($this->getRequest('user')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('user')); } if (!$this->hasRequest('id')) { // The 'id' argument has not been set, throw error. $this->throwError(3, 'id'); } else if (!$this->getRequest('id')) { // Throw error if the 'id' argument is set but empty. $this->throwError(1, 'id'); } $upgrade = $this->getXenAPI()->getUserUpgrade($this->getRequest('id')); if (!$upgrade) { $this->throwError(4, 'user upgrade', $this->getRequest('id')); } $end_date = NULL; if ($this->hasRequest('end_date')) { // Request has end_date. if (!$this->getRequest('end_date')) { // Throw error if the 'end_date' argument is set but empty. $this->throwError(1, 'end_date'); } // Set the language id of the registration. $end_date = $this->getRequest('end_date'); if (!(((string) (int) $this->getRequest('end_date') === $this->getRequest('end_date')) && ($this->getRequest('end_date') <= PHP_INT_MAX) && ($this->getRequest('end_date') >= ~PHP_INT_MAX))) { $this->throwError(6, $this->getRequest('end_date'), 'unix timestamp'); } } $record_id = $this->getXenAPI()->upgradeUser($user, $upgrade, TRUE, $end_date); $record = $this->getXenAPI()->getUserUpgradeRecord($record_id); $return = array(); if (is_int($record_id)) { $return['result'] = 'exists'; } else { $return['result'] = 'new'; } $return['record'] = $record; $this->sendResponse($return); case 'login': /** * Logins the user. * * EXAMPLE: * - api.php?action=login&username=USERNAME&password=PASSWORD */ if (!$this->hasRequest('username')) { // The 'username' argument has not been set, throw error. $this->throwError(3, 'username'); } else if (!$this->getRequest('username')) { // Throw error if the 'username' argument is set but empty. $this->throwError(1, 'username'); } else if (!$this->hasRequest('password')) { // The 'password' argument has not been set, throw error. $this->throwError(3, 'password'); } else if (!$this->getRequest('password')) { // Throw error if the 'password' argument is set but empty. $this->throwError(1, 'password'); } else if (!$this->hasRequest('ip_address')) { // The 'ip_address' argument has not been set, throw error. $this->throwError(3, 'ip_address'); } else if (!$this->getRequest('ip_address')) { // Throw error if the 'ip_address' argument is set but empty. $this->throwError(1, 'ip_address'); } // Get the user object. $user = $this->xenAPI->getUser($this->getRequest('username')); if (!$user->isRegistered()) { // Requested user was not registered, throw error. $this->throwError(4, 'user', $this->getRequest('username')); } else { // Requested user was registered, check authentication. if ($user->validateAuthentication($this->getRequest('password'))) { // Authentication was valid, grab the user's authentication record. $record = $user->getAuthenticationRecord(); $ddata = unserialize($record['data']); // Start session and saves the session to the database $session = $this->getXenAPI()->login( $user->getID(), $user->getUsername(), XenForo_Helper_Ip::convertIpStringToBinary($this->getRequest('ip_address')) ); $cookie_domain = XenForo_Application::get('config')->cookie->domain; // Check if cookie domain is empty, grab board url and use its domain if it is empty if (empty($cookie_domain)) { $url = XenForo_Application::getOptions()->boardUrl; $parse = parse_url($url); $cookie_domain = $parse['host']; } // Return data required for creating cookie $this->sendResponse(array( 'hash' => base64_encode($ddata['hash']), 'cookie_name' => XenForo_Application::get('config')->cookie->prefix . 'session', 'cookie_id' => $session->getSessionId(), 'cookie_path' => XenForo_Application::get('config')->cookie->path, 'cookie_domain' => $cookie_domain, 'cookie_expiration' => 0, 'cookie_secure' => XenForo_Application::$secure )); } else { // The username or password was wrong, throw error. $this->throwError(5, 'Invalid username or password!'); } } case 'register': /** * Registers a user. */ // Init user array. $user_data = array(); // Array of required parameters. $required_parameters = array('username', 'password', 'email'); // Array of additional parameters. $additional_parameters = array('timezone', 'gender', 'dob_day', 'dob_month', 'dob_year', 'ip_address'); foreach ($required_parameters as $required_parameter) { // Check if the required parameter is set and not empty. $this->checkRequestParameter($required_parameter); // Set the request value. $user_data[$required_parameter] = $this->getRequest($required_parameter); } foreach ($additional_parameters as $additional_parameter) { // Check if the additional parameter is set and not empty. $this->checkRequestParameter($additional_parameter, FALSE); if ($this->getRequest($additional_parameter)) { // Set the request value. $user_data[$additional_parameter] = $this->getRequest($additional_parameter); } } if ($this->hasRequest('group')) { // Request has value. if (!$this->getRequest('group')) { // Throw error if the 'group' argument is set but empty. $this->throwError(1, 'group'); } $group = $this->getXenAPI()->getGroup($this->getRequest('group')); if (!$group) { $registration_error = array( 'error_id' => 2, 'error_key' => 'group_not_found', 'error_field' => 'group', 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest('group') . '"' ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } // Set the group id of the registration. $user_data['group_id'] = $group['user_group_id']; } if ($this->hasRequest('custom_fields')) { // Request has value. if (!$this->getRequest('custom_fields')) { // Throw error if the 'custom_fields' argument is set but empty. $this->throwError(1, 'custom_fields'); } $custom_fields = $this->getCustomArray($this->getRequest('custom_fields')); // Check if we found any valid custom fields, throw error if not. if (count($custom_fields) == 0) { // The custom fields array was empty, throw error. $registration_error = array( 'error_id' => 5, 'error_key' => 'invalid_custom_fields', 'error_field' => 'custom_fields', 'error_phrase' => 'The custom fields values were invalid, valid values are: ' . 'custom_fields=custom_field1=custom_value1,custom_field2=custom_value2 ' . 'but got: "' . $this->getRequest('custom_fields') . '" instead' ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } $user_data['custom_fields'] = $custom_fields; } // Check if add groups is set. if ($this->hasRequest('add_groups')) { // Request has value. if (!$this->getRequest('add_groups')) { // Throw error if the 'add_groups' argument is set but empty. $this->throwError(1, 'add_groups'); } // Initialize the array. $user_data['add_groups'] = array(); // Check if value is an array. if (strpos($this->getRequest('add_groups'), ',') !== FALSE) { // Value is an array, explode it. $groups = explode(',', $this->getRequest('add_groups')); // Loop through the group values. foreach ($groups as $group_value) { // Grab the group from the group value. $group = $this->getXenAPI()->getGroup($group_value); // Check if group was found. if (!$group) { // Group was not found, throw error. $registration_error = array( 'error_id' => 2, 'error_key' => 'group_not_found', 'error_field' => 'add_groups', 'error_phrase' => 'Could not find group with parameter "' . $group_value . '" in array "' . $this->getRequest('add_group') . '"' ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } // Add the group_id to the the add_group array. $user_data['add_groups'][] = $group['user_group_id']; } } else { // Grab the group from the group value. $group = $this->getXenAPI()->getGroup($this->getRequest('add_groups')); // Check if group was found. if (!$group) { // Group was not found, throw error. $registration_error = array( 'error_id' => 2, 'error_key' => 'group_not_found', 'error_field' => 'add_groups', 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest('add_groups') . '"' ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } // Add the group_id to the the add_groups array. $user_data['add_groups'][] = $group['user_group_id']; } } if ($this->hasRequest('user_state')) { // Request has user_state. if (!$this->getRequest('user_state')) { // Throw error if the 'user_state' argument is set but empty. $this->throwError(1, 'user_state'); } // Set the user state of the registration. $user_data['user_state'] = $this->getRequest('user_state'); } if ($this->hasRequest('language_id')) { // Request has language_id. if (!$this->getRequest('language_id')) { // Throw error if the 'language_id' argument is set but empty. $this->throwError(1, 'language_id'); } // Set the language id of the registration. $user_data['language_id'] = $this->getRequest('language_id'); } $registration_results = $this->getXenAPI()->register($user_data); if (!empty($registration_results['error'])) { // The registration failed, process errors. if (is_array($registration_results['errors'])) { // The error message was an array, loop through the messages. $error_keys = array(); foreach ($registration_results['errors'] as $error_field => $error) { if (!($error instanceof XenForo_Phrase)) { $registration_error = array( 'error_id' => 1, 'error_key' => 'field_not_recognised', 'error_field' => $error_field, 'error_phrase' => $error ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } // Let's init the registration error array. $registration_error = array( 'error_id' => $this->getUserErrorID($error->getPhraseName()), 'error_key' => $error->getPhraseName(), 'error_field' => $error_field, 'error_phrase' => $error->render() ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } } else { $registration_error = array( 'error_id' => $registration_results['error'], 'error_key' => 'general_user_registration_error', 'error_phrase' => $registration_results['errors'] ); $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user'); } } else { // Registration was successful, return results. $this->sendResponse($registration_results); } case 'search': if (!$this->hasRequest('value')) { // The 'value' argument has not been set, throw error. $this->throwError(3, 'value'); } else if (!$this->getRequest('value')) { // Throw error if the 'value' argument is set but empty. $this->throwError(1, 'value'); } $order = 'asc'; $type = NULL; if ($this->hasRequest('order')) { // Request has order. if (!$this->getRequest('order')) { // Throw error if the 'order' argument is set but empty. $this->throwError(1, 'order'); } // Set the language id of the registration. $order = $this->getRequest('order'); } if ($this->hasRequest('type')) { // Request has type. if (!$this->getRequest('type')) { // Throw error if the 'type' argument is set but empty. $this->throwError(1, 'type'); } // Set the language id of the registration. $type = $this->getRequest('type'); } $this->sendResponse($this->getXenAPI()->search($this->getRequest('value'), $order, $type)); default: // Action was supported but has not yet been added to the switch statement, throw error. $this->throwError(11, $this->getAction()); } $this->throwError(7, 'executing action', $this->getAction()); } /** * Send the response array in JSON. */ public function sendResponse($data) { if ($this->hasRequest('debug')) { $data['debug'] = $this->getXenAPI()->getDebugData(); } header('Content-type: application/json'); die(json_encode($data)); } } /** * The XenAPI class provides all the functions and variables * that are needed to use XenForo's classes and functions. */ class XenAPI { private $xfDir, $models; /** * Default consturctor, instalizes XenForo classes and models. */ public function __construct() { $this->xfDir = dirname(__FILE__); require_once($this->xfDir . '/library/XenForo/Autoloader.php'); XenForo_Autoloader::getInstance()->setupAutoloader($this->xfDir. '/library'); XenForo_Application::initialize($this->xfDir . '/library', $this->xfDir); XenForo_Application::set('page_start_time', microtime(TRUE)); $deps = new XenForo_Dependencies_Public(); $deps->preLoadData(); // Disable XenForo's PHP error handler. XenForo_Application::disablePhpErrorHandler(); // Enable error logging for PHP. error_reporting(E_ALL & ~E_NOTICE); $this->models = new Models(); // TODO: Don't create models on init, only create them if they're being used (see Models::checkModel($model_name, $model)). $this->getModels()->setUserModel(XenForo_Model::create('XenForo_Model_User')); $this->getModels()->setAlertModel(XenForo_Model::create('XenForo_Model_Alert')); $this->getModels()->setUserFieldModel(XenForo_Model::create('XenForo_Model_UserField')); $this->getModels()->setAvatarModel(XenForo_Model::create('XenForo_Model_Avatar')); $this->getModels()->setModel('addon', XenForo_Model::create('XenForo_Model_AddOn')); $this->getModels()->setModel('database', XenForo_Application::get('db')); if ($this->hasAddon('XenResource') && $this->hasModel('XenResource_Model_Resource')) { $this->getModels()->setModel('resource', XenForo_Model::create('XenResource_Model_Resource')); } } public function getBoardURL($node, $inner_node) { if (XenForo_Application::getOptions()->useFriendlyUrls == '1') { return XenForo_Application::getOptions()->boardUrl . '/' . $node . '/' . $inner_node . '/'; } else { return XenForo_Application::getOptions()->boardUrl . '/index.php?' . $node . '/' . $inner_node . '/'; } } public function createAlert($alert_user, $cause_user, $alert_data = array()) { if ($alert_user == NULL) { // An user is required to create a new alert. return array('error' => 13, 'errors' => 'User is required to create an alert.'); } else if ($cause_user == NULL) { // A cause user is required to create a new alert. return array('error' => 13, 'errors' => 'User is required to create an alert.'); } $this->getModels()->checkModel('alert', XenForo_Model::create('XenForo_Model_Alert')); $this->getModels()->getModel('alert')->alertUser( $alert_user->getID(), $cause_user->getID(), $cause_user->getUsername(), $alert_data['content_type'], $alert_data['content_id'], $alert_data['action'] ); return $alert_data; } public function createConversation($user, $conversation_data = array()) { if ($user == NULL) { // An user is required to create a new conversation. return array('error' => 13, 'errors' => 'User is required to create a conversation.'); } $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User')); $this->checkUserPermissions($user); if (!$this->getModels()->getModel('user')->canStartConversations($null, $user->getData())) { // User does not have permission to post in this thread. return array('error' => 14, 'errors' => 'The user does not have permissions to create a new conversation.'); } // TODO: Check if user has permissions to start a conversation with the specified recepients. $conversation_data['message'] = XenForo_Helper_String::autoLinkBbCode($conversation_data['message']); $writer = XenForo_DataWriter::create('XenForo_DataWriter_ConversationMaster'); $writer->setExtraData(XenForo_DataWriter_ConversationMaster::DATA_ACTION_USER, $user->data); $writer->setExtraData(XenForo_DataWriter_ConversationMaster::DATA_MESSAGE, $conversation_data['message']); $writer->set('user_id', $user->data['user_id']); $writer->set('username', $user->data['username']); $writer->set('title', $conversation_data['title']); $writer->set('open_invite', $conversation_data['open_invite']); $writer->set('conversation_open', $conversation_data['conversation_locked'] ? 0 : 1); $writer->addRecipientUserNames(explode(',', $conversation_data['recipients'])); // checks permissions $messageDw = $writer->getFirstMessageDw(); $messageDw->set('message', $conversation_data['message']); $writer->preSave(); if ($writer->hasErrors()) { // The post creation failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->save(); $conversation = $writer->getMergedData(); $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation')); $this->getModels()->getModel('conversation')->markConversationAsRead($conversation['conversation_id'], $user->data['user_id'], XenForo_Application::$time); return $conversation; } public function login($user_id, $username, $ip_address) { $session = XenForo_Session::startPublicSession(); $session->set('user_id', $user_id); $session->set('username', $username); $session->set('ip', XenForo_Helper_Ip::convertIpStringToBinary($ip_address)); //$session->set('userAgent', $user_agent); $session->saveSessionToSource($session->getSessionId(), false); return $session; } public function createConversationReply($user, $conversation_reply_data = array()) { if ($user == NULL) { // An user is required to create a new conversation. return array('error' => 13, 'errors' => 'User is required to create a conversation reply.'); } $conversation = $this->getConversation($conversation_reply_data['conversation_id'], $user); $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation')); if (!$this->getModels()->getModel('conversation')->canReplyToConversation($conversation, $null, $user->getData())) { // User does not have permission to reply to this conversation. return array('error' => 14, 'errors' => 'The user does not have permissions to reply to this conversation.'); } $conversation_reply_data['message'] = XenForo_Helper_String::autoLinkBbCode($conversation_reply_data['message']); $writer = XenForo_DataWriter::create('XenForo_DataWriter_ConversationMessage'); $writer->setExtraData(XenForo_DataWriter_ConversationMessage::DATA_MESSAGE_SENDER, $user->getData()); $writer->set('conversation_id', $conversation['conversation_id']); $writer->set('user_id', $user->data['user_id']); $writer->set('username', $user->data['username']); $writer->set('message', $conversation_reply_data['message']); $writer->preSave(); if ($writer->hasErrors()) { // The conversation reply creation failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->save(); $conversation_reply = $writer->getMergedData(); $this->getModels()->getModel('conversation')->markConversationAsRead($conversation['conversation_id'], $user->data['user_id'], XenForo_Application::$time, 0, FALSE); return $conversation_reply; } public function search($keywords, $order = 'asc', $type = NULL) { $keywords = strtolower(XenForo_Helper_String::censorString($keywords, null, '')); $this->getModels()->checkModel('search', XenForo_Model::create('XenForo_Model_Search')); $searcher = new XenForo_Search_Searcher($this->getModels()->getModel('search')); $xenforo_results = $searcher->searchGeneral($keywords, array(), $order); $results = array(); foreach ($xenforo_results as &$result) { if ($type !== NULL) { if (strtolower($result[0]) != strtolower($type) && !(strtolower($result[0]) == 'thread' && strtolower($type) == 'thread_title')) { continue; } } $result = array( 'type' => $result[0], 'data' => $result[1] ); switch ($result['type']) { case 'post': $result['data'] = $this->getPost($result['data']); break; case 'thread': $result['data'] = $this->getThread($result['data']); if ($type !== NULL && strtolower($type) == 'thread_title' && $titleFound = $result['data']['title'] != $keywords) { continue 2; } break; case 'resource_update': // TODO $result['data'] = array('resource_update_id' => $result['data']); break; } $results[] = $result; } return $results; } public function createPost($user, $post_data = array()) { if ($user == NULL) { // An user is required to create a new post. return array('error' => 13, 'errors' => 'User is required to create a post.'); } $fetchOptions = array('permissionCombinationId' => $user->data['permission_combination_id']); $thread = $this->getThread($post_data['thread_id']); $forum = $this->getForum($thread['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']); if (!$this->canViewThread($user, $thread, $permissions) || !$this->canReplyToThread($user, $thread, $forum, $permissions)) { // User does not have permission to post in this thread. return array('error' => 14, 'errors' => 'The user does not have permissions to post in this thread.'); } $input['message'] = XenForo_Helper_String::autoLinkBbCode($post_data['message']); $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post')); $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post'); $writer->set('user_id', $user->data['user_id']); $writer->set('username', $user->data['username']); $writer->set('message', $input['message']); $writer->set('message_state', $this->getModels()->getModel('post')->getPostInsertMessageState($thread, $forum)); $writer->set('thread_id', $thread['thread_id']); $writer->setExtraData(XenForo_DataWriter_DiscussionMessage_Post::DATA_FORUM, $forum); $writer->preSave(); if ($writer->hasErrors()) { // The post creation failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->save(); $post = $writer->getMergedData(); $this->getModels()->checkModel('thread_watch', XenForo_Model::create('XenForo_Model_ThreadWatch')); $this->getModels()->getModel('thread_watch')->setThreadWatchStateWithUserDefault($user->data['user_id'], $thread['thread_id'], $user->data['default_watch_state']); return $post; } public function createProfilePost($user, $profile_post_data = array()) { if ($user == NULL) { // An user is required to create a new post. return array('error' => 13, 'errors' => 'User is required to create a profile post.'); } $this->getModels()->checkModel('user_profile', XenForo_Model::create('XenForo_Model_UserProfile')); $profile_user = $profile_post_data['user_id']; $this->checkUserPermissions($profile_user, array('followingUserId' => $user->data['user_id'])); $this->checkUserPermissions($user, array('followingUserId' => $profile_user->data['user_id'])); if (!$this->getModels()->getModel('user_profile')->canPostOnProfile($profile_user->getData(), $null, $user->getData())) { return array('error' => 14, 'errors' => 'The user does not have permissions to create a new profile post'); } if ($user->data['user_id'] == $profile_post_data['user_id']) { $profile_post_id = $this->getModels()->getModel('user_profile')->updateStatus($profile_post_data['message'], XenForo_Application::$time, $user->getData()); } else { $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost')); $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_ProfilePost'); $writer->set('user_id', $user->data['user_id']); $writer->set('username', $user->data['username']); $writer->set('message', $profile_post_data['message']); $writer->set('profile_user_id', $profile_user->data['user_id']); $writer->set('message_state', $this->getModels()->getModel('profile_post')->getProfilePostInsertMessageState($profile_user->getData(), $user->getData())); $writer->setExtraData(XenForo_DataWriter_DiscussionMessage_ProfilePost::DATA_PROFILE_USER, $profile_user->getData()); $writer->preSave(); if ($writer->hasErrors()) { // The profile post creation failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->save(); $profile_post_id = $writer->get('profile_post_id'); } return $this->getProfilePost($profile_post_id); } public function createProfilePostComment($user, $profile_post_data = array()) { if ($user == NULL) { // An user is required to create a new post. return array('error' => 13, 'errors' => 'User is required to create a profile post comment.'); } $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost')); $profile_post = $this->getProfilePost($profile_post_data['profile_post_id']); $profile_user = $profile_post_data['profile_user_id']; $this->checkUserPermissions($profile_user, array('followingUserId' => $user->data['user_id'])); $this->checkUserPermissions($user, array('followingUserId' => $profile_user->data['user_id'])); if (!$this->getModels()->getModel('profile_post')->canCommentOnProfilePost($profile_post, $profile_user->getData(), $null, $user->getData())) { return array('error' => 14, 'errors' => 'The user does not have permissions to create a new profile post'); } $writer = XenForo_DataWriter::create('XenForo_DataWriter_ProfilePostComment'); $writer->setExtraData(XenForo_DataWriter_ProfilePostComment::DATA_PROFILE_USER, $profile_user->getData()); $writer->setExtraData(XenForo_DataWriter_ProfilePostComment::DATA_PROFILE_POST, $profile_post); $writer->bulkSet(array( 'profile_post_id' => $profile_post['profile_post_id'], 'user_id' => $user->data['user_id'], 'username' => $user->data['username'], 'message' => $profile_post_data['message'] )); $writer->preSave(); if ($writer->hasErrors()) { // The profile post comment creation failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->save(); return array_values($this->getModels()->getModel('profile_post')->getProfilePostCommentsByProfilePost($profile_post['profile_post_id'])); } public function createThread($user, $thread_data = array()) { // TODO: Add support for polls. if ($user == NULL) { // An user is required to create a new thread. return array('error' => 13, 'errors' => 'User is required to create a thread.'); } $forum = $this->getForum($thread_data['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']); // Check if user can view the forum, if not; it's most likely private or the user has not access to the forum. if (!$this->canViewNode($user, $forum, $permissions) || !$this->canPostThreadInForum($user, $forum, $permissions)) { // User does not have permission to post in this thread. return array('error' => 14, 'errors' => 'The user does not have permissions to create a new thread in this forum.'); } $input['title'] = $thread_data['title']; $input['message'] = XenForo_Helper_String::autoLinkBbCode($thread_data['message']); if (!empty($thread_data['prefix_id'])) { $input['prefix_id'] = $thread_data['prefix_id']; } $this->getModels()->checkModel('thread_prefix', XenForo_Model::create('XenForo_Model_ThreadPrefix')); if (!$this->getModels()->getModel('thread_prefix')->verifyPrefixIsUsable($input['prefix_id'], $thread_data['node_id'])) { $input['prefix_id'] = 0; // not usable, just blank it out } $writer = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread'); $writer->bulkSet(array( 'user_id' => $user->data['user_id'], 'username' => $user->data['username'], 'title' => $input['title'], 'prefix_id' => $input['prefix_id'], 'node_id' => $thread_data['node_id'] )); $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post')); $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum')); // discussion state - moderator permission required if (!empty($thread_data['discussion_state']) && $this->getModels()->getModel('forum')->canLockUnlockThreadInForum($forum, $null, $permissions, $user->getData())) { $writer->set('discussion_state', $thread_data['discussion_state']); } else { // discussion state changes instead of first message state $writer->set('discussion_state', $this->getModels()->getModel('post')->getPostInsertMessageState(array(), $forum)); } // discussion open state - moderator permission required if (!empty($thread_data['discussion_open']) && $this->getModels()->getModel('forum')->canLockUnlockThreadInForum($forum, $null, $permissions, $user->getData())) { $writer->set('discussion_open', $thread_data['discussion_open']); } // discussion sticky state - moderator permission required if (!empty($thread_data['sticky']) && $this->getModels()->getModel('forum')->canStickUnstickThreadInForum($forum, $null, $permissions, $user->getData())) { $writer->set('sticky', $thread_data['sticky']); } $postWriter = $writer->getFirstMessageDw(); $postWriter->set('message', $input['message']); $postWriter->setExtraData(XenForo_DataWriter_DiscussionMessage_Post::DATA_FORUM, $forum); $writer->setExtraData(XenForo_DataWriter_Discussion_Thread::DATA_FORUM, $forum); $writer->preSave(); if ($writer->hasErrors()) { // The thread creation failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->save(); $thread = $writer->getMergedData(); $this->getModels()->checkModel('thread_watch', XenForo_Model::create('XenForo_Model_ThreadWatch')); $this->getModels()->getModel('thread_watch')->setThreadWatchStateWithUserDefault($user->data['user_id'], $thread['thread_id'], $user->data['default_watch_state']); $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread')); $this->getModels()->getModel('thread')->markThreadRead($thread, $forum, XenForo_Application::$time, $user->getData()); return $thread; } public function deletePost($post_id, $reason = NULL, $hard_delete = FALSE, $user = NULL) { if ($hard_delete) { $delete_type = 'hard'; } else { $delete_type = 'soft'; } if ($reason !== NULL) { $options = array('reason' => $reason); } else { $options = array(); } $post = $this->getPost($post_id); if ($user !== NULL) { $fetchOptions = array('permissionCombinationId' => $user->data['permission_combination_id']); $thread = $this->getThread($post['thread_id'], $fetchOptions); $forum = $this->getForum($thread['node_id'], $fetchOptions); $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']); } else { $thread = $this->getThread($post['thread_id']); $forum = $this->getForum($thread['node_id']); } $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post')); if ($user !== NULL && (!$this->canViewThread($user, $thread, $permissions) || !$this->getModels()->getModel('post')->canDeletePost($post, $thread, $forum, $delete_type, $null, $permissions, $user->getData()))) { // User does not have permission to delete this post. return array('error' => 14, 'errors' => 'The user does not have permissions to delete this post.'); } $this->getModels()->getModel('post')->deletePost($post_id, $delete_type, $options, $forum); if ($delete_type == 'hard') { $post['message_state'] = 'hard_deleted'; } else { $post['message_state'] = 'deleted'; } return $post; } public function deleteUser($user) { if (!$user) { return array('error' => 3, 'errors' => 'The user array key was not set.'); } if (!$user->isRegistered()) { return array('error' => 4, 'errors' => 'User is not registered.'); } $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User')); // Check if user is super admin. if ($this->getModels()->getModel('user')->isUserSuperAdmin($user->data)) { // User is super admin, we do not allow deleting super admins, return error. return array('error' => 6, 'errors' => 'Deleting super admins is disabled.'); } $writer = XenForo_DataWriter::create('XenForo_DataWriter_User', XenForo_DataWriter::ERROR_EXCEPTION); $writer->setExistingData($user->data); $writer->preDelete(); if ($writer->hasErrors()) { // The delete failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } $writer->delete(); return array('success' => TRUE); } public function editPost($post, $user, $edit_data = array()) { unset($post['absolute_url']); unset($post['message_html']); if (!$user) { return array('error' => 3, 'errors' => 'The user array key was not set.'); } if (!$user->isRegistered()) { return array('error' => 4, 'errors' => 'User is not registered.'); } $fetchOptions = array('permissionCombinationId' => $user->data['permission_combination_id']); $thread = $this->getThread($post['thread_id']); $forum = $this->getForum($thread['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']); if (!$this->canViewThread($user, $thread, $permissions) || !$this->canReplyToThread($user, $thread, $forum, $permissions)) { // User does not have permission to post in this thread. return array('error' => 14, 'errors' => 'The user does not have permissions to post in this thread.'); } if (array_key_exists('message', $edit_data)) { $edit_data['message'] = XenForo_Helper_String::autoLinkBbCode($edit_data['message']); } // Init the diff array. $diff_array = array(); // Create the data writer object for registrations, and set the defaults. $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post'); // Set the existing data of the user before we submit the data. $writer->setExistingData($post['post_id']); // Bulkset the edited data. $writer->bulkSet($edit_data); // Pre save the data. $writer->preSave(); if ($writer->hasErrors()) { // The edit failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } // Save the user to the database. $writer->save(); // Get the user data. $post_data = $writer->getMergedData(); // Check the difference between the before and after data. $diff_array = array_merge(array_diff_assoc($post, $post_data), $diff_array); foreach ($diff_array as $diff_key => $diff_value) { if (array_key_exists($diff_key, $post_data)) { $diff_array[$diff_key] = $post_data[$diff_key]; } } if (count($diff_array) == 0) { // Nothing was changed, throw error. return array('error' => 9, 'errors' => 'No values were changed.'); } return $diff_array; } public function editThread($thread, $user, $edit_data = array()) { unset($thread['absolute_url']); if (!$user) { return array('error' => 3, 'errors' => 'The user array key was not set.'); } if (!$user->isRegistered()) { return array('error' => 4, 'errors' => 'User is not registered.'); } $this->getModels()->checkModel('thread_prefix', XenForo_Model::create('XenForo_Model_ThreadPrefix')); // Check if the thread model has initialized. $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum')); $forum = $this->getForum($thread['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']); if (array_key_exists('prefix_id', $edit_data) && !$this->getModels()->getModel('thread_prefix')->verifyPrefixIsUsable($edit_data['prefix_id'], $thread['node_id'])) { return array('error' => 0, 'errors' => 'Prefix ID is not usable.'); } // discussion open state - moderator permission required if (array_key_exists('discussion_open', $edit_data) && !empty($edit_data['discussion_open']) && !$this->getModels()->getModel('forum')->canLockUnlockThreadInForum($forum, $null, $permissions, $user->getData())) { return array('error' => 0, 'errors' => 'User does not have permission to open/close this thread.'); } // discussion sticky state - moderator permission required if (array_key_exists('sticky', $edit_data) && !empty($edit_data['sticky']) && !$this->getModels()->getModel('forum')->canStickUnstickThreadInForum($forum, $null, $permissions, $user->getData())) { return array('error' => 0, 'errors' => 'User does not have permission to change the sticky status of this thread.'); } // Init the diff array. $diff_array = array(); // Create the data writer object for registrations, and set the defaults. $writer = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread'); // Set the existing data of the user before we submit the data. $writer->setExistingData($thread['thread_id']); // Bulkset the edited data. $writer->bulkSet($edit_data); // Pre save the data. $writer->preSave(); if ($writer->hasErrors()) { // The edit failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } // Save the user to the database. $writer->save(); // Get the user data. $thread_data = $writer->getMergedData(); // Check the difference between the before and after data. $diff_array = array_merge(array_diff_assoc($thread, $thread_data), $diff_array); foreach ($diff_array as $diff_key => $diff_value) { if (array_key_exists($diff_key, $thread_data)) { $diff_array[$diff_key] = $thread_data[$diff_key]; } } if (count($diff_array) == 0) { // Nothing was changed, throw error. return array('error' => 9, 'errors' => 'No values were changed.'); } return $diff_array; } public function editUser($user, $edit_data = array()) { if (!$user) { return array('error' => 3, 'errors' => 'The user array key was not set.'); } if (!$user->isRegistered()) { return array('error' => 4, 'errors' => 'User is not registered.'); } if (empty($user->data['dob_day'])) { // We need the full profile of the user, let's re-grab the user and get the full profile. $user = $this->getUser($user->getID(), array('join' => XenForo_Model_User::FETCH_USER_FULL)); } $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User')); // Check if user is super admin. if ($this->getModels()->getModel('user')->isUserSuperAdmin($user->data)) { // User is super admin, we do not allow editing super admins, return error. return array('error' => 6, 'errors' => 'Editing super admins is disabled.'); } if (!empty($edit_data['password'])) { // Create a new variable for the password. $password = $edit_data['password']; // Unset the password from the user data array. unset($edit_data['password']); } // Init the diff array. $diff_array = array(); // Create the data writer object for registrations, and set the defaults. $writer = XenForo_DataWriter::create('XenForo_DataWriter_User'); // Set the existing data of the user before we submit the data. $writer->setExistingData($user->data); // Let the writer know that the edit is legit and made by an administrator. $writer->setOption(XenForo_DataWriter_User::OPTION_ADMIN_EDIT, TRUE); if (!empty($edit_data['group_id'])) { // Group ID is set. $writer->set('user_group_id', $edit_data['group_id']); // We need to unset the group id as we don't want it to be included into the bulk set. unset($edit_data['group_id']); } if (!empty($edit_data['remove_group_id'])) { // Group ID is set. #$writer->set('user_group_id', $edit_data['group_id']); // We need to unset the group id as we don't want it to be included into the bulk set. unset($edit_data['remove_group_id']); } if (!empty($edit_data['add_groups'])) { // Add group is set. // Check if there are any custom fields in the data array. if (!is_array($edit_data['add_groups']) || count($edit_data['add_groups']) == 0) { // The edit failed, return errors. return array('error' => 7, 'errors' => 'The add_groups parameter needs to be an array and have at least 1 item.'); } // Initialize some arrays. $groups = array(); $groups_exist = array(); // Check if there are more than one custom array. if (strpos($user->data['secondary_group_ids'], ',') !== FALSE) { // Value is an array, explode it. $groups = explode(',', $user->data['secondary_group_ids']); } else { // Value is not an array, just add the single group to the array. $groups[] = $user->data['secondary_group_ids']; } // Loop through the groups that are going to be added to check if the user already have the groups. foreach ($edit_data['add_groups'] as $group_id) { // Check if the user already is in the group. if (in_array($group_id, $groups)) { // User is already in the group, add the group ID to the group_exist array. $groups_exist[] = $group_id; } else { // User is not in the group, add the group ID to the new_groups array. $groups[] = $group_id; $diff_array['new_secondary_groups'][] = $group_id; } } // Check if the user is in one or more of the specified groups. if (count($groups_exist) > 0) { // The user was already in one or more groups, return error. return array('error' => 8, 'errors' => 'The user is already a member of the group ID\'s: (' . implode(',', $groups_exist) . ')'); } // Set the secondary group(s) of the user. $writer->setSecondaryGroups($groups); // We need to unset the group id as we don't want it to be included into the bulk set. unset($edit_data['add_groups']); } if (!empty($edit_data['remove_groups'])) { // Remove group is set. // Check if there are any custom fields in the data array. if (!is_array($edit_data['remove_groups']) || count($edit_data['remove_groups']) == 0) { // The edit failed, return errors. return array('error' => 11, 'errors' => 'The remove_groups parameter needs to be an array and have at least 1 item.'); } // Initialize some arrays. $groups = array(); $groups_not_exist = array(); // Check if there are more than one custom array. if (strpos($user->data['secondary_group_ids'], ',') !== FALSE) { // Value is an array, explode it. $groups = explode(',', $user->data['secondary_group_ids']); } else { // Value is not an array, just add the single group to the array. $groups[] = $user->data['secondary_group_ids']; } // Loop through the groups that are going to be added to check if the user already have the groups. foreach ($edit_data['remove_groups'] as $group_key => $group_id) { // Check if the user already is in the group. if (!in_array($group_id, $groups) && $user->data['user_group_id'] != $group_id) { // User is already in the group, add the group ID to the group_exist array. $groups_not_exist[] = $group_id; } else { // Check if user's primary group is the group ID. if (!empty($user->data['user_group_id']) && $user->data['user_group_id'] == $group_id) { // User's primary group ID was found in the remove_groups array, move the user to the default registration group. $writer->set('user_group_id', XenForo_Model_User::$defaultRegisteredGroupId); $diff_array['removed_group'] = $group_id; } else { // User is in the group, add the group ID to the remove_groups array. $diff_array['removed_secondary_groups'][] = $group_id; } // Unset the group id. unset($groups[$group_key]); } } // Check if the user is in one or more of the specified groups. if (count($groups_not_exist) > 0) { // The user was already in one or more groups, return error. return array('error' => 12, 'errors' => 'The user is not a member of group ID\'s: (' . implode(',', $groups_not_exist) . ')'); } // Set the secondary group(s) of the user. $writer->setSecondaryGroups($groups); // We need to unset the group id as we don't want it to be included into the bulk set. unset($edit_data['remove_groups']); } if (!empty($edit_data['secondary_group_ids'])) { // Secondary group ID's are set. $writer->setSecondaryGroups(unserialize($edit_data['secondary_group_ids'])); // We need to unset the secondary group id's as we don't want it to be included into the bulk set. unset($edit_data['secondary_group_ids']); } if (!empty($edit_data['custom_fields'])) { // Custom fields are set. // Check if there are any custom fields in the data array. if (count($edit_data['custom_fields']) > 0) { // There were one or more custom fields set, set them in the writer. $writer->setCustomFields($edit_data['custom_fields']); } // We need to unset the custom fields as we don't want it to be included into the bulk set. unset($edit_data['custom_fields']); } // Bulkset the edited data. $writer->bulkSet($edit_data); if (isset($password)) { // Set the password for the data writer. $writer->setPassword($password, $password); } // Set the data for the data writer. $writer->bulkSet($edit_data); // Pre save the data. $writer->preSave(); if ($writer->hasErrors()) { // The edit failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } // Save the user to the database. $writer->save(); // Get the user data. $user_data = $writer->getMergedData(); // Check the difference between the before and after data. $diff_array = array_merge(array_diff_assoc($user->data, $user_data), $diff_array); foreach ($diff_array as $diff_key => $diff_value) { if (isset($user_data[$diff_key])) { $diff_array[$diff_key] = $user_data[$diff_key]; } } if (isset($diff_array['secondary_group_ids'])) { unset($diff_array['secondary_group_ids']); } if (!empty($diff_array['custom_fields'])) { // Check the difference in the custom fields. $custom_fields_diff_array = array_diff_assoc($user->data['custom_fields'], unserialize($diff_array['custom_fields'])); unset($diff_array['custom_fields']); // Loop through the differences and add them to the diff array. foreach ($custom_fields_diff_array as $custom_fields_diff_key => $custom_fields_diff_value) { $diff_array['custom_fields'][$custom_fields_diff_key] = $custom_fields_diff_value; } } if (isset($password)) { // Password is changed, make sure we add it to the difference array. $diff_array['password'] = 'OK'; } if (count($diff_array) == 0) { // Nothing was changed, throw error. return array('error' => 9, 'errors' => 'No values were changed.'); } return $diff_array; } /** * Returns the Database model. */ public function getDatabase() { return $this->getModels()->getModel('database'); } /** * Returns the array of all the models. */ public function getModels() { return $this->models; } /** * Grabs the User class of the last registered user. */ public function getLatestUser() { return new User($this->getModels(), $this->getModels()->getUserModel()->getLatestUser()); } /** * Returns the total count of registered users on XenForo. */ public function getUserCount() { return $this->getModels()->getUserModel()->countTotalUsers(); } /** * Returns a list of addons in the Addon class. */ public function getAddons($type = 'all') { // TODO: add support to grab addon options. $type = strtolower($type); $allowed_types = array('all', 'enabled', 'disabled'); if (!in_array($type, $allowed_types)) { $type = 'all'; } $installed_addons = $this->getModels()->getModel('addon')->getAllAddOns(); $addons = array(); foreach ($installed_addons as $addon) { $temp_addon = new Addon($addon); if (($type == 'enabled' && $temp_addon->isEnabled()) || ($type == 'disabled' && !$temp_addon->isEnabled()) || $type == 'all') { $addons[] = $temp_addon; } } return $addons; } /** * Returns the Addon class of the $addon parameter. */ public function getAddon($addon) { return new Addon($this->getModels()->getModel('addon')->getAddOnById($addon)); } /** * Returns all the conversations of the user. */ public function getConversations($user, $conditions = array(), $fetchOptions = array()) { $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation')); return $this->getModels()->getModel('conversation')->getConversationsForUser($user->getID(), $conditions, $fetchOptions); } public function getConversation($conversation, $user, $fetchOptions = array()) { $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation')); return $this->getModels()->getModel('conversation')->getConversationForUser($conversation, $user->getData(), $fetchOptions); } public function getGroup($group) { // Get the group from the database. return $this->getDatabase()->fetchRow("SELECT * FROM `xf_user_group` WHERE `user_group_id` = " . $this->getDatabase()->quote($group) . " OR `title` = " . $this->getDatabase()->quote($group) . " OR `user_title` = " . $this->getDatabase()->quote($group)); } /** * Returns a list of resources. */ public function getResources($conditions = array(), $fetchOptions = array()) { $this->getModels()->checkModel('resource', XenForo_Model::create('XenResource_Model_Resource')); $this->getModels()->checkModel('resource_version', XenForo_Model::create('XenResource_Model_Version')); $this->getModels()->checkModel('attachment', XenForo_Model::create('XenForo_Model_Attachment')); $resources_list = $this->getModels()->getModel('resource')->getResources($conditions, $fetchOptions); $resources = array(); foreach ($resources_list as &$resource) { $resource_version = $this->getModels()->getModel('resource_version')->getVersionById( $resource['current_version_id'], array('join' => XenResource_Model_Version::FETCH_FILE) ); $resource['current_version_string'] = $resource_version['version_string']; if ($resource['is_fileless'] === 0) { $attachment_id = $resource_version['attachment_id']; $attachment = $this->getModels()->getModel('attachment')->getAttachmentById($attachment_id); $resource['current_file_hash'] = $attachment['file_hash']; } if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) { $resource['custom_resource_fields'] = $resource['custom_resource_fields'] == FALSE ? NULL : unserialize($resource['custom_resource_fields']); } $resources[] = new Resource($resource); } return $resources; } /** * Returns the Resource class of the $resource parameter. */ public function getResource($resource, $fetchOptions = array()) { $this->getModels()->checkModel('resource', XenForo_Model::create('XenResource_Model_Resource')); $this->getModels()->checkModel('resource_version', XenForo_Model::create('XenResource_Model_Version')); $this->getModels()->checkModel('attachment', XenForo_Model::create('XenForo_Model_Attachment')); $resource = $this->getModels()->getModel('resource')->getResourceById($resource, $fetchOptions); $resource_version = $this->getModels()->getModel('resource_version')->getVersionById( $resource['current_version_id'], array('join' => XenResource_Model_Version::FETCH_FILE) ); $resource['current_version_string'] = $resource_version['version_string']; if ($resource['is_fileless'] === 0) { $attachment_id = $resource_version['attachment_id']; $attachment = $this->getModels()->getModel('attachment')->getAttachmentById($attachment_id); $resource['current_file_hash'] = $attachment['file_hash']; } if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) { $resource['custom_resource_fields'] = $resource['custom_resource_fields'] == FALSE ? NULL : unserialize($resource['custom_resource_fields']); } return new Resource($resource); } /** * Returns the list of resource categories. */ public function getResourceCategories() { $this->getModels()->checkModel('resource_category', XenForo_Model::create('XenResource_Model_Category')); return $this->getModels()->getModel('resource_category')->getAllCategories(); } /** * TODO */ public function getStats($start = NULL, $end = NULL, $types = NULL) { $this->getModels()->checkModel('stats', XenForo_Model::create('XenForo_Model_Stats')); // TODO return $this->getModels()->getModel('stats')->getStatsData(time() - 5000, time()); } public function getStatsItem($item, $include_deleted = FALSE) { $this->getModels()->checkModel('database', XenForo_Application::get('db')); switch ($item) { case 'users': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_user'); case 'conversations': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_conversation_master'); case 'conversations_messages': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_conversation_message'); case 'posts': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_post' . ($include_deleted ? ' WHERE message_state != "deleted"' : '')); case 'threads': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_thread' . ($include_deleted ? ' WHERE discussion_state != "deleted"' : '')); case 'registrations_today': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_user WHERE register_date > UNIX_TIMESTAMP(CURDATE())'); case 'posts_today': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_post WHERE post_date > UNIX_TIMESTAMP(CURDATE()) AND position != 0' . ($include_deleted ? ' AND message_state != "deleted"' : '')); case 'threads_today': return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_thread WHERE post_date > UNIX_TIMESTAMP(CURDATE())' . ($include_deleted ? ' AND discussion_state != "deleted"' : '')); default: return NULL; } } /** * TODO */ public function checkUserPermissions(&$user, array $fetchOptions = array()) { if ($user !== NULL) { $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User')); if (!is_array($user) && !($user instanceof User)) { $user = $this->getUser($user, array_merge($fetchOptions, array('join' => XenForo_Model_User::FETCH_USER_PERMISSIONS))); if (empty($user->data['permissions'])) { // Check if the user data has the permissions set, set it if not. $user->data['permissions'] = XenForo_Permission::unserializePermissions($user->data['global_permission_cache']); // Unset the permissions serialized cache as we don't need it anymore. unset($user->data['global_permission_cache']); } } else { if (empty($user->data['global_permission_cache'])) { // Check if the user data has permissions cache set, grab it if not. $user = $this->getUser($user->getID(), array_merge($fetchOptions, array('join' => XenForo_Model_User::FETCH_USER_PERMISSIONS))); } if (empty($user->data['permissions'])) { // Check if the user data has the permissions set, set it if not. $user->data['permissions'] = XenForo_Permission::unserializePermissions($user->data['global_permission_cache']); // Unset the permissions serialized cache as we don't need it anymore. unset($user->data['global_permission_cache']); } } } } /** * TODO */ public function getUsersOnlineCount($user = NULL) { $this->getModels()->checkModel('session', XenForo_Model::create('XenForo_Model_Session')); if ($user !== NULL) { // User parameter is not null, make sure to follow privacy of the users. $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User')); // Check user permissions. $this->checkUserPermissions($user); // Check if the user can bypass user privacy. $bypass = $this->getModels()->getModel('user')->canBypassUserPrivacy($null, $user->getData()); $conditions = array( 'cutOff' => array('>', $this->getModels()->getModel('session')->getOnlineStatusTimeout()), 'getInvisible' => $bypass, 'getUnconfirmed' => $bypass, 'forceInclude' => ($bypass ? FALSE : $user->getID()) ); } else { // User parameter is null, ignore privacy and grab all the users. $conditions = array( 'cutOff' => array('>', $this->getModels()->getModel('session')->getOnlineStatusTimeout()) ); } // Return the count of online visitors (users + guests). return $this->getModels()->getModel('session')->countSessionActivityRecords($conditions); } /** * Returns the Node array of the $node_id parameter. */ public function getForum($node_id, $fetchOptions = array()) { $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum')); return $this->getModels()->getModel('forum')->getForumById($node_id, $fetchOptions); } /** * Returns the Link Forum array of the $node_id parameter. */ public function getLinkForum($node_id, $fetchOptions = array()) { $this->getModels()->checkModel('link_forum', XenForo_Model::create('XenForo_Model_LinkForum')); return $this->getModels()->getModel('link_forum')->getLinkForumById($node_id, $fetchOptions); } /** * Returns the Node array of the $node_id parameter. */ public function getNode($node_id, $fetchOptions = array()) { $this->getModels()->checkModel('node', XenForo_Model::create('XenForo_Model_Node')); $node = $this->getModels()->getModel('node')->getNodeById($node_id, $fetchOptions); if (!empty($node['node_type_id'])) { switch (strtolower($node['node_type_id'])) { case 'forum': return $this->getForum($node['node_id'], $fetchOptions); case 'linkforum': return $this->getLinkForum($node['node_id'], $fetchOptions); case 'page': return $this->getPage($node['node_id'], $fetchOptions); case 'category': default: return $node; } } return $node; } /** * Returns a list of nodes. */ public function getNodes($node_type = 'all', $fetchOptions = array('limit' => 10), $user = NULL) { $this->getModels()->checkModel('node', XenForo_Model::create('XenForo_Model_Node')); // Get the node list. $node_list = $this->getModels()->getModel('node')->getAllNodes(); // Check if the node type that is set exists. if ($node_type == NULL || !in_array($node_type, $this->getNodeTypes())) { $node_type = 'all'; } // Loop through the nodes to check if the user has permissions to view the thread. foreach ($node_list as $key => &$node) { if ($node_type != 'all' && strtolower($node['node_type_id']) != $node_type) { // Node type does not equal the requested node type, unset the node and continue the loop. unset($node_list[$key]); continue; } // Check if user is set. if ($user !== NULL) { // Get the node. $node = $this->getNode($node['node_id'], array_merge($fetchOptions, array('permissionCombinationId' => $user->data['permission_combination_id']))); $permissions = XenForo_Permission::unserializePermissions($node['node_permission_cache']); // User does not have permission to view this nodes, unset it and continue the loop. if (!$this->canViewNode($user, $node, $permissions)) { unset($node_list[$key]); continue; } // Unset the permissions values. unset($node_list[$key]['node_permission_cache']); } else { // Get the node. $node = $this->getNode($node['node_id'], $fetchOptions); } } return $node_list; } public function getDebugData() { $database_debug = XenForo_Debug::getDatabaseDebugInfo($this->getModels()->getModel('database')); unset($database_debug['queryHtml']); $included_files_debug = XenForo_Debug::getIncludedFilesDebugInfo(get_included_files()); unset($included_files_debug['includedFileHtml']); return array( 'time' => microtime(TRUE) - XenForo_Application::get('page_start_time'), 'database' => $database_debug, 'memory' => array( 'usage' => memory_get_usage(), 'peak' => memory_get_peak_usage() ), 'included_files' => $included_files_debug ); } /** * TODO */ public function getNodeTypes() { $this->getModels()->checkModel('node', XenForo_Model::create('XenForo_Model_Node')); return array_keys(array_change_key_case($this->getModels()->getModel('node')->getAllNodeTypes(), CASE_LOWER)); } /** * Returns the Page array of the $node_id parameter. */ public function getPage($node_id, $fetchOptions = array()) { $this->getModels()->checkModel('page', XenForo_Model::create('XenForo_Model_Page')); return $this->getModels()->getModel('page')->getPageById($node_id, $fetchOptions); } /** * TODO */ public function canViewNode($user, $node, $permissions = NULL) { // Check if the forum model has initialized. if (!empty($node['node_type_id'])) { if ($permissions == NULL) { // Let's grab the permissions. $node = $this->getNode($node['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); // Unserialize the permissions. $permissions = XenForo_Permission::unserializePermissions($node['node_permission_cache']); } switch (strtolower($node['node_type_id'])) { case 'category': $this->getModels()->checkModel('category', XenForo_Model::create('XenForo_Model_Category')); return $this->getModels()->getModel('category')->canViewCategory($node, $null, $permissions, $user->getData()); case 'forum': $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum')); return $this->getModels()->getModel('forum')->canViewForum($node, $null, $permissions, $user->getData()); case 'linkforum': $this->getModels()->checkModel('link_forum', XenForo_Model::create('XenForo_Model_LinkForum')); return $this->getModels()->getModel('link_forum')->canViewLinkForum($node, $null, $permissions, $user->getData()); case 'page': $this->getModels()->checkModel('page', XenForo_Model::create('XenForo_Model_Page')); return $this->getModels()->getModel('page')->canViewPage($node, $null, $permissions, $user->getData()); } } return FALSE; } /** * Returns the Post array of the $post_id parameter. */ public function getPost($post_id, $fetchOptions = array()) { $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post')); $post = $this->getModels()->getModel('post')->getPostById($post_id, $fetchOptions); if (!empty($fetchOptions['join'])) { // Unset the thread values. Post::stripThreadValues($post); } if ($post !== FALSE && $post !== NULL) { // Add HTML as well $formatter = XenForo_BbCode_Formatter_Base::create(); $parser = new XenForo_BbCode_Parser($formatter); $post['message_html'] = str_replace("\n", '', $parser->render($post['message'])); $post['absolute_url'] = self::getBoardURL('posts', $post['post_id']); } else { $post = NULL; } return $post; } /** * Returns a list of posts. */ public function getPosts($conditions = array(), $fetchOptions = array('limit' => 10), $user = NULL) { if (!empty($conditions['node_id']) || (!empty($fetchOptions['order']) && strtolower($fetchOptions['order']) == 'node_id')) { // We need to grab the thread info to get the node_id. $fetchOptions = array_merge($fetchOptions, array('join' => XenForo_Model_Post::FETCH_THREAD)); } $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post')); if ($user !== NULL) { // User is set, we need to include permissions. if (!isset($fetchOptions['join'])) { // WE need to grab the thread to get the node permissions. $fetchOptions = array_merge($fetchOptions, array('join' => XenForo_Model_Post::FETCH_THREAD)); } // User is set, we therefore have to grab the permissions to check if the user is allowed to view the post. $fetchOptions = array_merge($fetchOptions, array('permissionCombinationId' => $user->data['permission_combination_id'])); } // Prepare query conditions. $whereConditions = Post::preparePostConditions($this->getModels()->getModel('database'), $this->getModels()->getModel('post'), $conditions); $sqlClauses = $this->getModels()->getModel('post')->preparePostJoinOptions($fetchOptions); $limitOptions = $this->getModels()->getModel('post')->prepareLimitFetchOptions($fetchOptions); // Since the Post model of XenForo does not have order by implemented, we have to do it ourselves. if (!empty($fetchOptions['order'])) { $orderBySecondary = ''; switch ($fetchOptions['order']) { case 'post_id': case 'thread_id': case 'user_id': case 'username': case 'attach_count': case 'likes': $orderBy = 'post.' . $fetchOptions['order']; break; case 'node_id': $orderBy = 'thread.' . $fetchOptions['order']; break; case 'post_date': default: $orderBy = 'post.post_date'; } // Check if order direction is set. if (!isset($fetchOptions['orderDirection']) || $fetchOptions['orderDirection'] == 'desc') { $orderBy .= ' DESC'; } else { $orderBy .= ' ASC'; } $orderBy .= $orderBySecondary; } $sqlClauses['orderClause'] = (isset($orderBy) ? "ORDER BY $orderBy" : ''); // Execute the query and get the result. $post_list = $this->getModels()->getModel('post')->fetchAllKeyed($this->getModels()->getModel('post')->limitQueryResults( ' SELECT post.* ' . $sqlClauses['selectFields'] . ' FROM xf_post AS post ' . $sqlClauses['joinTables'] . ' WHERE ' . $whereConditions . ' ' . $sqlClauses['orderClause'] . ' ', $limitOptions['limit'], $limitOptions['offset'] ), 'post_id'); // Loop through the posts to unset some values that are not needed. foreach ($post_list as $key => &$post) { if ($user !== NULL) { // Check if the user has permissions to view the post. $permissions = XenForo_Permission::unserializePermissions($post['node_permission_cache']); if (!$this->getModels()->getModel('post')->canViewPost($post, array('node_id' => $post['node_id']), array(), $null, $permissions, $user->getData())) { // User does not have permission to view this post, unset it and continue the loop. unset($post_list[$key]); continue; } // Unset the permissions values. unset($post_list[$key]['node_permission_cache']); } if (isset($fetchOptions['join'])) { // Unset some not needed thread values. Post::stripThreadValues($post_list[$key]); } if ($post !== FALSE && $post !== NULL) { // Add HTML as well $formatter = XenForo_BbCode_Formatter_Base::create(); $parser = new XenForo_BbCode_Parser($formatter); $post['message_html'] = str_replace("\n", '', $parser->render($post['message'])); $post['absolute_url'] = self::getBoardURL('posts', $post['post_id']); } else { $post = NULL; } } return array_values($post_list); } /** * Check if user has permissions to view post. */ public function canViewPost($user, $post, $permissions = NULL) { // Check if the post model has initialized. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post')); if ($permissions == NULL) { // Let's grab the permissions. $post = $this->getPost($post['post_id'], array( 'permissionCombinationId' => $user->data['permission_combination_id'], 'join' => XenForo_Model_Post::FETCH_FORUM )); // Unserialize the permissions. $permissions = XenForo_Permission::unserializePermissions($post['node_permission_cache']); } return $this->getModels()->getModel('post')->canViewPost($post, array('node_id' => $post['node_id']), array(), $null, $permissions, $user->getData()); } public function canPostThreadInForum($user, $forum, $permissions = NULL) { // Does not take in count of private nodes. if (!empty($forum['node_type_id'])) { if ($permissions == NULL) { // Let's grab the permissions. $forum = $this->getForum($forum['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); // Unserialize the permissions. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']); } $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum')); return $this->getModels()->getModel('forum')->canPostThreadInForum($forum, $null, $permissions, $user->getData()); } return FALSE; } public function canReplyToThread($user, $thread, $forum, $permissions = NULL) { // Check if the thread model has initialized. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread')); if ($permissions == NULL) { // Let's grab the permissions. $thread = $this->getThread($thread['thread_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); // Unserialize the permissions. $permissions = XenForo_Permission::unserializePermissions($thread['node_permission_cache']); } return $this->getModels()->getModel('thread')->canReplyToThread($thread, $forum, $null, $permissions, $user->getData()); } /** * Returns the Post array of the $post_id parameter. */ public function getProfilePost($profile_post_id, $fetchOptions = array()) { $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost')); return $this->getModels()->getModel('profile_post')->getProfilePostById($profile_post_id, $fetchOptions); } /** * Returns a list of profile posts. */ public function getProfilePosts($conditions = array(), $fetchOptions = array('limit' => 10), $user = NULL) { $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost')); if ($user !== NULL) { // User is set, we need to include permissions. $this->checkUserPermissions($user); } // Default the sql condition. $sqlConditions = array(); if (count($conditions) > 0) { // We need to make our own check for these conditions as XenForo's functions doesn't fully support what we want. // Check if the author id is set. if (!empty($conditions['author_id'])) { $sqlConditions[] = "profile_post.user_id = " . $this->getModels()->getModel('database')->quote($conditions['author_id']); } // Check if the profile id is set. if (!empty($conditions['profile_id'])) { $sqlConditions[] = "profile_post.profile_user_id = " . $this->getModels()->getModel('database')->quote($conditions['profile_id']); } } // Use the model function to get conditions for clause from the sql conditions. $whereConditions = $this->getModels()->getModel('profile_post')->getConditionsForClause($sqlConditions); // Prepare query conditions. $sqlClauses = $this->getModels()->getModel('profile_post')->prepareProfilePostFetchOptions($fetchOptions); $limitOptions = $this->getModels()->getModel('profile_post')->prepareLimitFetchOptions($fetchOptions); // Since the profile post model of XenForo does not have order by implemented, we have to do it ourselves. if (!empty($fetchOptions['order'])) { $orderBySecondary = ''; switch ($fetchOptions['order']) { case 'profile_post_id': case 'profile_user_id': case 'user_id': case 'username': case 'attach_count': case 'likes': case 'comment_count': case 'first_comment_date': case 'last_comment_date': $orderBy = 'profile_post.' . $fetchOptions['order']; break; case 'post_date': default: $orderBy = 'profile_post.post_date'; } // Check if order direction is set. if (!isset($fetchOptions['orderDirection']) || $fetchOptions['orderDirection'] == 'desc') { $orderBy .= ' DESC'; } else { $orderBy .= ' ASC'; } $orderBy .= $orderBySecondary; } $sqlClauses['orderClause'] = (isset($orderBy) ? "ORDER BY $orderBy" : ''); // Execute the query and get the result. $profile_post_list = $this->getModels()->getModel('profile_post')->fetchAllKeyed($this->getModels()->getModel('profile_post')->limitQueryResults( ' SELECT profile_post.* ' . $sqlClauses['selectFields'] . ' FROM xf_profile_post AS profile_post ' . $sqlClauses['joinTables'] . ' WHERE ' . $whereConditions . ' ' . $sqlClauses['orderClause'] . ' ', $limitOptions['limit'], $limitOptions['offset'] ), 'profile_post_id'); if ($user !== NULL) { // Loop through the profile posts to check permissions foreach ($profile_post_list as $key => $profile_post) { // Check if the user has permissions to view the profile post. if (!$this->getModels()->getModel('profile_post')->canViewProfilePost($profile_post, array(), $null, $user->getData())) { // User does not have permission to view this profile post, unset it and continue the loop. unset($profile_post_list[$key]); } } } // Return the profile post list. return array_values($profile_post_list); } /** * Check if user has permissions to view post. */ public function canViewProfilePost($user, $profile_post, $permissions = NULL) { // Check if the profile post model has initialized. $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost')); // Check if the user object has the permissions data. $this->checkUserPermissions($user); // Return if the user has permissions to view the profile post. return $user !== NULL && $this->getModels()->getModel('profile_post')->canViewProfilePost($profile_post, array(), $null, $user->getData()); } /** * Returns the Thread array of the $thread_id parameter. */ public function getThread($thread_id, array $fetchOptions = array(), $user = NULL) { if (isset($fetchOptions['grab_content'])) { $grab_content = TRUE; unset($fetchOptions['grab_content']); } if (isset($fetchOptions['content_limit'])) { $content_limit = $fetchOptions['content_limit']; unset($fetchOptions['content_limit']); } else { $content_limit = 1; } $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread')); $thread = $this->getModels()->getModel('thread')->getThreadById($thread_id, $fetchOptions); if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) { $thread['custom_fields'] = $thread['custom_fields'] == FALSE ? NULL : unserialize($thread['custom_fields']); } if ($thread !== FALSE && $thread !== NULL) { if (isset($grab_content)) { $posts = $this->getPosts(array('thread_id' => $thread_id), array('limit' => $content_limit), $user); $thread['content'] = array('count' => count($posts), 'content' => $posts); unset($posts); } $thread['absolute_url'] = self::getBoardURL('threads', $thread['thread_id']); } else { $thread = NULL; } return $thread; } /** * Returns a list of threads. */ public function getThreads($conditions = array(), $fetchOptions = array('limit' => 10), $user = NULL) { $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread')); if (isset($fetchOptions['grab_content'])) { $grab_content = TRUE; unset($fetchOptions['grab_content']); } if (isset($fetchOptions['content_limit'])) { $content_limit = $fetchOptions['content_limit']; unset($fetchOptions['content_limit']); } else { $content_limit = 1; } if ($user !== NULL) { $thread_list = $this->getModels()->getModel('thread')->getThreads($conditions, array_merge($fetchOptions, array('permissionCombinationId' => $user->data['permission_combination_id']))); } else { $thread_list = $this->getModels()->getModel('thread')->getThreads($conditions, $fetchOptions); } // Loop through the threads to check if the user has permissions to view the thread. foreach ($thread_list as $key => &$thread) { if ($user !== NULL) { $permissions = XenForo_Permission::unserializePermissions($thread['node_permission_cache']); if (!$this->getModels()->getModel('thread')->canViewThread($thread, array(), $null, $permissions, $user->getData())) { // User does not have permission to view this thread, unset it and continue the loop. unset($thread_list[$key]); // Unset the permissions values. unset($thread_list[$key]['node_permission_cache']); continue; } else { // Unset the permissions values. unset($thread_list[$key]['node_permission_cache']); } } if ($thread !== FALSE && $thread !== NULL) { if (isset($grab_content)) { $posts = $this->getPosts(array('thread_id' => $thread['thread_id']), array('limit' => $content_limit), $user); $thread['content'] = array('count' => count($posts), 'content' => $posts); unset($posts); } if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) { $thread['custom_fields'] = $thread['custom_fields'] == FALSE ? NULL : unserialize($thread['custom_fields']); } $thread['absolute_url'] = self::getBoardURL('threads', $thread['thread_id']); } else { $thread = NULL; } } return array_values($thread_list); } /** * Returns the Thread array of the $thread_id parameter. */ public function canViewThread($user, $thread, $permissions = NULL) { // Check if the thread model has initialized. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread')); if ($permissions == NULL) { // Let's grab the permissions. $thread = $this->getThread($thread['thread_id'], array('permissionCombinationId' => $user->data['permission_combination_id'])); // Unserialize the permissions. $permissions = XenForo_Permission::unserializePermissions($thread['node_permission_cache']); } return $this->getModels()->getModel('thread')->canViewThread($thread, array(), $null, $permissions, $user->getData()); } public function getUsersByIp($ip) { $this->getModels()->checkModel('ip', XenForo_Model::create('XenForo_Model_Ip')); return $this->getModels()->getModel('ip')->getUsersByIp($ip); } /** * Returns the User class of the $input parameter. * * The $input parameter can be an user ID, username or e-mail. * Returns FALSE if $input is NULL. */ public function getUser($input, $fetchOptions = array()) { if (!empty($fetchOptions['custom_field'])) { $results = $this->getDatabase()->fetchRow("SELECT `user_id` FROM `xf_user_field_value` WHERE `field_id` = " . $this->getDatabase()->quote($fetchOptions['custom_field']) . " AND `field_value` = " . $this->getDatabase()->quote($input)); if (!empty($results['user_id'])) { $input = $results['user_id']; } } if ($input == FALSE || $input == NULL) { return FALSE; } else if (is_numeric($input)) { // $input is a number, grab the user by an ID. $user = new User($this->models, $this->models->getUserModel()->getUserById($input, $fetchOptions)); if (!$user->isRegistered()) { // The user ID was not found, grabbing the user by the username instead. $user = new User($this->models, $this->models->getUserModel()->getUserByName($input, $fetchOptions)); } } else if ($this->models->getUserModel()->couldBeEmail($input)) { // $input is an e-mail, return the user of the e-mail. $user = new User($this->models, $this->models->getUserModel()->getUserByEmail($input, $fetchOptions)); } else { // $input is an username, return the user of the username. $user = new User($this->models, $this->models->getUserModel()->getUserByName($input, $fetchOptions)); } if ($user->isRegistered()) { $this->getModels()->checkModel('user_field', XenForo_Model::create('XenForo_Model_UserField')); $user->data['custom_fields'] = $this->getModels()->getModel('user_field')->getUserFieldValues($user->getID()); } return $user; } public function getUserUpgrade($upgrade_id) { $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade')); return $this->getModels()->getModel('user_upgrade')->getUserUpgradeById($upgrade_id); } public function getUserUpgrades($user = NULL) { $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade')); if ($user !== NULL) { $user_upgrades = $this->getModels()->getModel('user_upgrade')->getActiveUserUpgradeRecordsForUser($user->getID()); foreach ($user_upgrades as &$user_upgrade) { $user_upgrade['extra'] = unserialize($user_upgrade['extra']); } return $user_upgrades; } return $this->getModels()->getModel('user_upgrade')->getAllUserUpgrades(); } public function getUserUpgradeRecord($record_id) { $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade')); $upgrade_record = $this->getModels()->getModel('user_upgrade')->getActiveUserUpgradeRecordById($record_id); if ($upgrade_record !== FALSE) { $upgrade_record['extra'] = unserialize($upgrade_record['extra']); } return $upgrade_record; } public function upgradeUser($user, array $upgrade, $allow_insert_unpurchasable = FALSE, $end_date = NULL) { $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade')); return $this->getModels()->getModel('user_upgrade')->upgradeUser($user->getID(), $upgrade, $allow_insert_unpurchasable, $end_date); } public function downgradeUserUpgrade($record) { $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade')); return $this->getModels()->getModel('user_upgrade')->downgradeUserUpgrade($record); } public function hasModel($model) { if (XenForo_Application::autoload($model)) { $model = @XenForo_Model::create($model); return is_a($model, 'XenForo_Model'); } return FALSE; } public function hasAddon($addon_id) { $has = FALSE; $addons = $this->getAddons(); foreach ($addons as $addon) { if (strtolower($addon->getID()) == strtolower($addon_id)) { $has = TRUE; break; } } return $has; } /** * TODO */ public function register($user_data) { if (empty($user_data['username'])) { // Username was empty, return error. return array('error' => 10, 'errors' => 'Missing required parameter: username'); } else if (empty($user_data['password'])) { // Password was empty, return error. return array('error' => 10, 'errors' => 'Missing required parameter: password'); } else if (empty($user_data['email'])) { // Email was empty, return error. return array('error' => 10, 'errors' => 'Missing required parameter: email'); } // Create a new variable for the password. $password = $user_data['password']; // Unset the password from the user data array. unset($user_data['password']); if (!empty($user_data['ip_address'])) { // Create a new variable for the ip address. $ip_address = $user_data['ip_address']; // Unset the ip address from the user data array. unset($user_data['ip_address']); } // Get the default options from XenForo. $options = XenForo_Application::get('options'); // Create the data writer object for registrations, and set the defaults. $writer = XenForo_DataWriter::create('XenForo_DataWriter_User'); if ($options->registrationDefaults) { // Set the default registration options if it's set in the XenForo options. $writer->bulkSet($options->registrationDefaults, array('ignoreInvalidFields' => TRUE)); } if (!empty($user_data['group_id'])) { // Group ID is set. $writer->set('user_group_id', $user_data['group_id']); // We need to unset the group id as we don't want it to be included into the bulk set. unset($user_data['group_id']); } else { // Group ID is not set, default back to default. $writer->set('user_group_id', XenForo_Model_User::$defaultRegisteredGroupId); } if (!empty($user_data['user_state'])) { // User state is set. $writer->set('user_state', $user_data['user_state']); } else { // User state is not set, default back to default. $writer->advanceRegistrationUserState(); } if (!empty($user_data['language_id'])) { // Language ID is set. $writer->set('language_id', $user_data['language_id']); } else { // Language ID is not set, default back to default. $writer->set('language_id', $options->defaultLanguageId); } if (!empty($user_data['custom_fields'])) { // Custom fields are set. // Check if there are any custom fields in the data array. if (count($user_data['custom_fields']) > 0) { // There were one or more custom fields set, set them in the writer. $writer->setCustomFields($user_data['custom_fields']); } // We need to unset the custom fields as we don't want it to be included into the bulk set. unset($user_data['custom_fields']); } if (!empty($user_data['add_groups'])) { // Add group is set. // Check if there are any custom fields in the data array. if (!is_array($user_data['add_groups']) || count($user_data['add_groups']) == 0) { // The edit failed, return errors. return array('error' => 7, 'errors' => 'The add_groups parameter needs to be an array and have at least 1 item.'); } // Set the secondary group(s) of the user. $writer->setSecondaryGroups($user_data['add_groups']); // We need to unset the group id as we don't want it to be included into the bulk set. unset($user_data['add_groups']); } // Check if Gravatar is enabled, set the gravatar if it is and there's a gravatar for the email. if ($options->gravatarEnable && XenForo_Model_Avatar::gravatarExists($data['email'])) { $writer->set('gravatar', $user_data['email']); } // Set the data for the data writer. $writer->bulkSet($user_data); // Set the password for the data writer. $writer->setPassword($password, $password); // Pre save the data. $writer->preSave(); if ($writer->hasErrors()) { // The registration failed, return errors. return array('error' => TRUE, 'errors' => $writer->getErrors()); } // Save the user to the database. $writer->save(); // Get the User as a variable: $user = $writer->getMergedData(); // Check if IP is set. if (!empty($user_data['ip_address'])) { // Log the IP of the user that registered. XenForo_Model_Ip::log($user['user_id'], 'user', $user['user_id'], 'register', $ip_address); } // Send email if the user state was specified. if ($user['user_state'] == 'email_confirm') { $this->getModels()->checkModel('user_confirmation', XenForo_Model::create('XenForo_Model_UserConfirmation')); $this->getModels()->getModel('user_confirmation')->sendEmailConfirmation($user); } return $user; } } /** * This class contains all the required models of XenForo. */ class Models { private $models = array(); /** * Returns TRUE if the model exists, FALSE if not. */ public function hasModel($model_name) { return isset($this->models[$model_name]) && $this->models[$model_name] !== NULL; } /** * Checks if the model exists, adds it to the array if not. */ public function checkModel($model_name, $model) { if (!$this->hasModel($model_name)) { $this->setModel($model_name, $model); } } /** * Returns the array of all the models. */ public function getModels() { return $this->models; } /** * Returns the model defined by the parameter $model. */ public function getModel($model) { return $this->models[$model]; } /** * Sets the model of the parameter $model. */ public function setModel($name, $model) { $this->models[$name] = $model; } /** * Sets the user model. */ public function setUserModel($userModel) { $this->models['userModel'] = $userModel; } /** * Returns the user model. */ public function getUserModel() { return $this->models['userModel']; } /** * Sets the alert model. */ public function setAlertModel($alertModel) { $this->models['alertModel'] = $alertModel; } /** * Returns the alert model. */ public function getAlertModel() { return $this->models['alertModel']; } /** * Sets the userfield model. */ public function setUserFieldModel($userFieldModel) { $this->models['userFieldModel'] = $userFieldModel; } /** * Returns the userfield model. */ public function getUserFieldModel() { return $this->models['userFieldModel']; } /** * Sets the avatar model. */ public function setAvatarModel($avatarModel) { $this->models['avatarModel'] = $avatarModel; } /** * Returns the avatar model. */ public function getAvatarModel() { return $this->models['avatarModel']; } /** * Returns the database model. */ public function getDatabase() { return $this->getModel('database'); } } class Post { public static function stripThreadValues(&$post) { unset($post['reply_count']); unset($post['view_count']); unset($post['sticky']); unset($post['discussion_state']); unset($post['discussion_open']); unset($post['discussion_type']); unset($post['first_post_id']); unset($post['first_post_likes']); unset($post['last_post_date']); unset($post['last_post_id']); unset($post['last_post_user_id']); unset($post['last_post_username']); unset($post['prefix_id']); unset($post['thread_user_id']); unset($post['thread_username']); unset($post['thread_post_date']); } public static function preparePostConditions($db, $model, array $conditions) { $sqlConditions = array(); if (!empty($conditions['forum_id']) && empty($conditions['node_id'])) { $conditions['node_id'] = $conditions['forum_id']; } if (!empty($conditions['node_id'])) { if (is_array($conditions['node_id'])) { $sqlConditions[] = 'thread.node_id IN (' . $db->quote($conditions['node_id']) . ')'; } else { $sqlConditions[] = 'thread.node_id = ' . $db->quote($conditions['node_id']); } } if (!empty($conditions['thread_id'])) { if (is_array($conditions['thread_id'])) { $sqlConditions[] = 'post.thread_id IN (' . $db->quote($conditions['thread_id']) . ')'; } else { $sqlConditions[] = 'post.thread_id = ' . $db->quote($conditions['thread_id']); } } if (!empty($conditions['prefix_id'])) { if (is_array($conditions['prefix_id'])) { $sqlConditions[] = 'thread.prefix_id IN (' . $db->quote($conditions['prefix_id']) . ')'; } else { $sqlConditions[] = 'thread.prefix_id = ' . $db->quote($conditions['prefix_id']); } } if (!empty($conditions['post_date']) && is_array($conditions['post_date'])) { list($operator, $cutOff) = $conditions['post_date']; $model->assertValidCutOffOperator($operator); $sqlConditions[] = "post.post_date $operator " . $db->quote($cutOff); } // thread starter if (isset($conditions['user_id'])) { $sqlConditions[] = 'post.user_id = ' . $db->quote($conditions['user_id']); } return $model->getConditionsForClause($sqlConditions); } } /** * This class contains all the functions and all the relevant data of a XenForo resource. */ class Resource { private $data; /** * Default constructor. */ public function __construct($data) { $this->data = $data; } /** * Returns an array with that conists of limited data. */ public static function getLimitedData($resource) { return array('id' => $resource->getID(), 'title' => $resource->getTitle(), 'author_id' => $resource->getAuthorUserID(), 'author_username' => $resource->getAuthorUsername(), 'state' => $resource->getState(), 'creation_date' => $resource->getCreationDate(), 'category_id' => $resource->getCategoryID(), 'version_id' => $resource->getCurrentVersionID(), 'version_string' => $resource->getCurrentVersionString(), 'file_hash' => $resource->getCurrentFileHash(), 'description_id' => $resource->getDescriptionUpdateID(), 'description' => $resource->getDescription(), 'thread_id' => $resource->getDiscussionThreadID(), 'external_url' => $resource->getExternalURL(), 'price' => $resource->getPrice(), 'currency' => $resource->getCurrency(), 'times_downloaded' => $resource->getTimesDownloaded(), 'times_rated' => $resource->getTimesRated(), 'rating_sum' => $resource->getRatingSum(), 'rating_avg' => $resource->getAverageRating(), 'rating_weighted' => $resource->getWeightedRating(), 'times_updated' => $resource->getTimesUpdated(), 'times_reviewed' => $resource->getTimesReviewed(), 'last_update' => $resource->getLastUpdateDate(), 'custom_fields' => $resource->getCustomFields() ); } /** * Returns an array which contains all the data of the resource. */ public function getData() { return $this->data; } /** * Returns TRUE if the resource is valid, returns FALSE if not. */ public function isValid() { return $this->data !== NULL && is_array($this->data) && isset($this->data['resource_id']) && $this->data['resource_id'] !== NULL; } public function getCustomFields() { return array_key_exists('custom_resource_fields', $this->data) ? $this->data['custom_resource_fields'] : NULL; } /** * Returns the ID of the resource. */ public function getID() { return $this->data['resource_id']; } /** * Returns the title of the resource. */ public function getTitle() { return $this->data['title']; } /** * Returns the tag line of the resource. */ public function getTagLine() { return $this->data['tag_line']; } /** * Returns the ID of the author. */ public function getAuthorUserID() { return $this->data['user_id']; } /** * Returns the username of the author. */ public function getAuthorUsername() { return $this->data['username']; } /** * Returns the state of the resource. * TODO */ public function getState() { return $this->data['resource_state']; } /** * Returns the creation date of the resource. */ public function getCreationDate() { return $this->data['resource_date']; } /** * Returns the category ID of the resource. */ public function getCategoryID() { return $this->data['resource_category_id']; } /** * Returns the current version ID of the resource. */ public function getCurrentVersionID() { return $this->data['current_version_id']; } /** * Returns the current version string of the resource. */ public function getCurrentVersionString() { return $this->data['current_version_string']; } /** * Returns the current file hash (MD5) of the resource. */ public function getCurrentFileHash() { return $this->data['current_file_hash']; } /** * Returns the current description update ID of the resource. */ public function getDescriptionUpdateID() { return $this->data['description_update_id']; } /** * Returns the current description of the resource. */ public function getDescription() { return $this->data['description']; } /** * Returns the discussion thread ID of the resource. */ public function getDiscussionThreadID() { return $this->data['discussion_thread_id']; } /** * Returns the external URL of the resource. */ public function getExternalURL() { return $this->data['external_url']; } /** * Returns TRUE if the resource is fileless, FALSE if not. */ public function isFileless() { return $this->data['is_fileless'] == 1; } /** * Returns the external purchase URL of the resource if it has any. */ public function getExternalPurchaseURL() { return $this->data['external_purchase_url']; } /** * Returns the price of the resource. */ public function getPrice() { return $this->data['price']; } /** * Returns the currency of the price of the resource. */ public function getCurrency() { return $this->data['currency']; } /** * Returns the amount of times the resource has been downloaded. */ public function getTimesDownloaded() { return $this->data['download_count']; } /** * Returns the amount of times the resource has been rated. */ public function getTimesRated() { return $this->data['rating_count']; } /** * Returns the sum of the ratings. */ public function getRatingSum() { return $this->data['rating_sum']; } /** * Returns the average rating of the resource. */ public function getAverageRating() { return $this->data['rating_avg']; } /** * Returns the weighted rating of the resource. */ public function getWeightedRating() { return $this->data['rating_weighted']; } /** * Returns the amount of times the resource has been updated. */ public function getTimesUpdated() { return $this->data['update_count']; } /** * Returns the amount of times the resource has been reviewed. */ public function getTimesReviewed() { return $this->data['review_count']; } /** * Returns the last update date of the resource. */ public function getLastUpdateDate() { return $this->data['last_update']; } /** * Returns the alternative support URL of the resource. */ public function getAlternativeSupportURL() { return $this->data['alt_support_url']; } /** * Returns TRUE if the resource had first visible. */ public function hadFirstVisible() { return $this->data['had_first_visible'] == 1; } } /** * This class contains all the functions and all the relevant data of a XenForo addon. */ class Addon { private $data; /** * Default constructor. */ public function __construct($data) { $this->data = $data; } /** * Returns an array with that conists of limited data. */ public static function getLimitedData($addon) { return array('id' => $addon->getID(), 'title' => $addon->getTitle(), 'version' => $addon->getVersionString(), 'enabled' => $addon->isEnabled(), 'url' => $addon->getURL()); } /** * Returns an array which contains all the data of the addon. */ public function getData() { return $this->data; } /** * Returns TRUE if the addon is installed, returns FALSE if not. */ public function isInstalled() { return $this->data !== NULL && is_array($this->data) && isset($this->data['addon_id']) && $this->data['addon_id'] !== NULL; } /** * Returns TRUE if the addon is enabled, returns FALSE if not. */ public function isEnabled() { return $this->data['active'] == 1; } /** * Returns the ID of the addon. */ public function getID() { return $this->data['addon_id']; } /** * Returns the title of the addon. */ public function getTitle() { return $this->data['title']; } /** * Returns the version string of the addon. */ public function getVersionString() { return $this->data['version_string']; } /** * Returns the version ID of the addon. */ public function getVersionID() { return $this->data['version_id']; } /** * Returns the URL of the addon. */ public function getURL() { return $this->data['url']; } /** * Returns the install callback class of the addon. */ public function getInstallCallbackClass() { return $this->data['install_callback_class']; } /** * Returns the install callback method of the addon. */ public function getInstallCallbackMethod() { return $this->data['install_callback_method']; } /** * Returns the uninstall callback class of the addon. */ public function getUninstallCallbackClass() { return $this->data['uninstall_callback_class']; } /** * Returns the uninstall callback method of the addon. */ public function getUninstallCallbackMethod() { return $this->data['uninstall_callback_class']; } } /** * This class contains all the functions and all the relevant data of a XenForo user. */ class User { public $data; private $models, $registered = FALSE; /** * Default constructor. */ public function __construct($models, $data) { $this->models = $models; $this->data = $data; if (!empty($data)) { $this->registered = TRUE; } } /** * Returns an array which contains all the data of the user. */ public function getData() { return $this->data; } /** * Returns all the alerts and relevant information regarding the alerts. */ public function getAlerts($type = 'fetchRecent') { /* * Options are: * - fetchPopupItems: Fetch alerts viewed in the last options:alertsPopupExpiryHours hours. * - fetchRecent: Fetch alerts viewed in the last options:alertExpiryDays days. * - fetchAll: Fetch alerts regardless of their view_date. * * For more information, see /library/XenForo/Model/Alert.php. */ $types = array('fetchPopupItems', 'fetchRecent', 'fetchAll'); if (!in_array($type, $types)) { $type = 'fetchRecent'; } return $this->models->getAlertModel()->getAlertsForUser($this->getID(), $type); } /** * Returns the ID of the user. */ public function getID() { return $this->data['user_id']; } /** * Returns the username of the user. */ public function getUsername() { return $this->data['username']; } /** * Returns the email of the user. */ public function getEmail() { return $this->data['email']; } /** * Returns the avatar URL of the user. */ public function getAvatar($size) { $avatarUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . (dirname($_SERVER['REQUEST_URI']) != '/' ? '/' : ''); if ($this->data['gravatar']) { return XenForo_Template_Helper_Core::getAvatarUrl($this->data, $size); } else if (!empty($this->data['avatar_date'])) { return $avatarUrl . XenForo_Template_Helper_Core::getAvatarUrl($this->data, $size, 'custom'); } else { return $avatarUrl . XenForo_Template_Helper_Core::getAvatarUrl($this->data, $size, 'default'); } } /** * Returns if the user is registered or not. */ public function isRegistered() { return $this->registered; } /** * Returns TRUE if the user is a global moderator. */ public function isModerator() { return $this->data['is_moderator'] == 1; } /** * Returns TRUE if the user an administrator. */ public function isAdmin() { return $this->data['is_admin'] == 1; } /** * Returns TRUE if the user is banned. */ public function isBanned() { return $this->data['is_banned'] == 1; } /** * Returns the authentication record of the user. */ public function getAuthenticationRecord() { return $this->models->getUserModel()->getUserAuthenticationRecordByUserId($this->data['user_id']); } /** * Verifies the password of the user. */ public function validateAuthentication($password) { if (strlen($password) == 64) { $record = $this->getAuthenticationRecord(); $ddata = unserialize($record['data']); return $ddata['hash'] == $password; } else { return $this->models->getUserModel()->validateAuthentication($this->data['username'], $password); } } /** * Returns the amount of unread alerts. */ public function getUnreadAlertsCount() { return $this->models->getUserModel()->getUnreadAlertsCount($this->getID()); } /** * Returns the permission cache, if any. */ public function getPermissionCache() { return $this->data['global_permission_cache']; } }