Guest User

Untitled

a guest
May 26th, 2019
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 262.25 KB | None | 0 0
  1. <?php
  2. /*
  3. * This file is part of XenAPI <http://www.xenapi.net/>.
  4. *
  5. * XenAPI is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * XenAPI is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. // To change the API key, replace the REPLACE_THIS_WITH_AN_API_KEY with your desired API key.
  20. $restAPI = new RestAPI('APIKEY');
  21.  
  22. # DO NOT CHANGE ANYTHING BELOW THIS LINE UNLESS
  23. # YOU REALLY KNOW WHAT ARE YOU DOING
  24.  
  25. // Process the request
  26. if ($restAPI->getAPIKey() !== NULL && $restAPI->isDefaultAPIKey()) {
  27. // API is set but not changed from the default API key.
  28. $restAPI->throwError(17);
  29. } else if ($restAPI->getAPIKey() !== NULL && !$restAPI->hasRequest('hash') && !$restAPI->isPublicAction()) {
  30. // Hash argument is required and was not found, throw error.
  31. $restAPI->throwError(3, 'hash');
  32. } else if (!$restAPI->getHash() && !$restAPI->isPublicAction()) {
  33. // Hash argument is empty or not set, throw error.
  34. $restAPI->throwError(1, 'hash');
  35. } else if (!$restAPI->isAuthenticated() && !$restAPI->isPublicAction()) {
  36. // Hash is not valid and action is not public, throw error.
  37. $restAPI->throwError(6, $restAPI->getHash(), 'hash');
  38. } else if (!$restAPI->hasRequest('action')) {
  39. // Action argument was not found, throw error.
  40. $restAPI->throwError(3, 'action');
  41. } else if (!$restAPI->getAction()) {
  42. // Action argument is empty or not set, throw error.
  43. $restAPI->throwError(1, 'action');
  44. } else if (!$restAPI->isSupportedAction()) {
  45. // Action is not supported, throw error.
  46. $restAPI->throwError(2, $restAPI->getAction());
  47. } else if (!$restAPI->isPermitted()) {
  48. // User does not have permission to use this action, throw error.
  49. if ($restAPI->hasRequest('value') && $restAPI->isUserAction()) {
  50. $restAPI->throwError(9, $restAPI->getAction());
  51. } else {
  52. $restAPI->throwError(10, $restAPI->getAction());
  53. }
  54. }
  55. // Process the request.
  56. $restAPI->processRequest();
  57.  
  58. class RestAPI {
  59. const VERSION = '1.4.2';
  60. const DEFAULT_APIKEY = 'REPLACE_THIS_WITH_AN_API_KEY';
  61. const GENERAL_ERROR = 0x201;
  62. const USER_ERROR = 0x202;
  63. const THREAD_ERROR = 0x203;
  64. const POST_ERROR = 0x204;
  65. /**
  66. * Contains all the actions in an array, each action is 'action' => 'permission_name'
  67. * 'action' is the name of the action in lowercase.
  68. * 'permission_name' is the permission requirement of the action, see description under.
  69. *
  70. * Permission names and meaning:
  71. * - public: A hash is not required to use this action, it can be used without
  72. * without being 'authenticated'.
  73. * - authenticated: The action requires the user to be authenticated to use the action
  74. * with a 'value' argument.
  75. * - moderator: The action requires the user to be a moderator to use the action
  76. * with a 'value' argument.
  77. * - administrator: The action requires the user to be an administrator to use the action
  78. * with a 'value' argument.
  79. * - private: User is only allowed to use the action on himself/herself.
  80. * Example: If user tries to use 'getAlerts' with a 'value' argument,
  81. * an error will be thrown.
  82. * - api_key: An API key is required to perform this action.
  83. *
  84. * NOTE: Permissions are ignored when the API key is used as a hash, permissions are only
  85. * used when the user is using the 'username:hash' format for the 'hash' argument.
  86. */
  87. private $actions = array(
  88. 'authenticate' => 'public',
  89. 'createalert' => 'api_key',
  90. 'createconversation' => 'authenticated',
  91. 'createconversationreply' => 'authenticated',
  92. 'createpost' => 'authenticated',
  93. 'createprofilepost' => 'authenticated',
  94. 'createprofilepostcomment' => 'authenticated',
  95. 'createthread' => 'authenticated',
  96. 'deletepost' => 'authenticated',
  97. 'deleteuser' => 'authenticated',
  98. 'downgradeuser' => 'api_key',
  99. 'editpost' => 'authenticated',
  100. 'editthread' => 'authenticated',
  101. 'edituser' => 'api_key',
  102. 'getactions' => 'public',
  103. 'getaddon' => 'administrator',
  104. 'getaddons' => 'administrator',
  105. 'getalerts' => 'private',
  106. 'getavatar' => 'public',
  107. 'getconversation' => 'private',
  108. 'getconversations' => 'private',
  109. 'getgroup' => 'public',
  110. 'getnode' => 'public',
  111. 'getnodes' => 'public',
  112. 'getpost' => 'public',
  113. 'getposts' => 'public',
  114. 'getprofilepost' => 'authenticated',
  115. 'getprofileposts' => 'authenticated',
  116. 'getresource' => 'administrator',
  117. 'getresources' => 'administrator',
  118. 'getresourcecategories' => 'administrator',
  119. 'getstats' => 'public',
  120. 'getthread' => 'public',
  121. 'getthreads' => 'public',
  122. 'getuser' => 'authenticated',
  123. 'getusers' => 'public',
  124. 'getuserupgrade' => 'api_key',
  125. 'getuserupgrades' => 'api_key',
  126. 'login' => 'public',
  127. 'logout' => 'public',
  128. 'register' => 'api_key',
  129. 'search' => 'public',
  130. 'upgradeuser' => 'api_key'
  131. );
  132.  
  133. // Array of actions that are user specific and require an username, ID or email for the 'value' parameter.
  134. private $user_actions = array('getalerts', 'getavatar', 'getconversation', 'getconversations', 'createprofilepost', 'getuser');
  135.  
  136. // List of general errors, this is where the 'throwError' function gets the messages from.
  137. private $general_errors = array(
  138. 0 => 'Unknown error',
  139. 1 => 'Argument: "{ERROR}", is empty/missing a value',
  140. 2 => '"{ERROR}", is not a supported action',
  141. 3 => 'Missing argument: "{ERROR}"',
  142. 4 => 'No {ERROR} found with the argument: "{ERROR2}"',
  143. 5 => 'Authentication error: "{ERROR}"',
  144. 6 => '"{ERROR}" is not a valid {ERROR2}',
  145. 7 => 'Something went wrong when "{ERROR}": "{ERROR2}"',
  146. 8 => 'The request had no values set, available fields are: "({ERROR})"',
  147. 9 => 'You are not permitted to use the "{ERROR}" action on others (remove the value argument)',
  148. 10 => 'You do not have permission to use the "{ERROR}" action',
  149. 11 => '"{ERROR}" is a supported action but there is no code for it yet',
  150. 12 => '"{ERROR}" is a unknown request method',
  151. 13 => '"{ERROR}" is not an installed addon',
  152. 14 => '"{ERROR}" is not an author of any resources',
  153. 15 => 'Could not find a resource with ID "{ERROR}"',
  154. 16 => 'Could not find a required model to perform this request: "{ERROR}"',
  155. 17 => 'The API key has not been changed, make sure you use another API key before using this API',
  156. 18 => '"{ERROR} is a unknown permission name, the request was terminated.',
  157. 19 => 'Could not find a {ERROR} with ID "{ERROR2}"',
  158. 20 => '{ERROR} not have permissions to view {ERROR2}',
  159. 21 => 'The "{ERROR}" argument has to be a number',
  160. 22 => 'The argument for "order_by", "{ERROR}", was not found in the list available order by list: "({ERROR2})"',
  161. 23 => 'The argument for "node_type", "{ERROR}", was not found in the list available node type list: "({ERROR2})"',
  162. 24 => 'The argument for "discussion_state", "{ERROR}", was not found in the list available discussion state list: "({ERROR2})"'
  163. );
  164.  
  165. // Specific errors related to user actions.
  166. private $user_errors = array(
  167. 0 => 'Unknown user error',
  168. 1 => 'Field was not recognised',
  169. 2 => 'Group not found',
  170. 3 => 'User data array was missing',
  171. 4 => 'The specified user is not registered',
  172. 5 => 'Invalid custom field array',
  173. 6 => 'Editing super admins is disabled',
  174. 7 => 'The add_groups parameter needs to be an array and have at least 1 item',
  175. 8 => 'The user is already a member of the group(s)',
  176. 9 => 'No values were changed',
  177. 10 => 'Missing required a required parameter',
  178. 11 => 'The remove_groups parameter needs to be an array and have at least 1 item',
  179. 12 => 'The user is not a member of the group(s)',
  180. 13 => 'An user is required to create a post/thread',
  181. 14 => 'The user does not have permissions to post in this thread',
  182. 30 => 'Missing required registration fields',
  183. 31 => 'Password invalid',
  184. 32 => 'Name length is too short',
  185. 33 => 'Name length is too long',
  186. 34 => 'Name contains disallowed words',
  187. 35 => 'Name does not follow the required format',
  188. 36 => 'Name contains censored words',
  189. 37 => 'Name contains CTRL characters',
  190. 38 => 'Name contains comma',
  191. 39 => 'Name resembles an email',
  192. 40 => 'User already exists',
  193. 41 => 'Invalid email',
  194. 42 => 'Email already used',
  195. 43 => 'Email banned by administrator',
  196. 44 => 'Invalid timezone',
  197. 45 => 'Custom title contains censored words',
  198. 46 => 'Custom title contains disallowed words',
  199. 47 => 'Invalid date of birth',
  200. 48 => 'Cannot delete your own account',
  201. 49 => 'Field contained an invalid value'
  202. );
  203.  
  204. private $xenAPI, $method, $data = array(), $hash = FALSE, $apikey = FALSE;
  205.  
  206. /**
  207. * Default constructor for the RestAPI class.
  208. * The data gets set here depending on what kind of request method is being used.
  209. */
  210. public function __construct($api_key = NULL) {
  211. $this->method = strtolower($_SERVER['REQUEST_METHOD']);
  212. switch ($this->method) {
  213. case 'get':
  214. $this->data = $_GET;
  215. break;
  216. case 'post':
  217. $this->data = $_POST;
  218. break;
  219. case 'put':
  220. case 'delete':
  221. parse_str(file_get_contents('php://input'), $put_vars);
  222. $this->data = $put_vars;
  223. break;
  224. default:
  225. $this->throwError(12, $this->method);
  226. }
  227. $this->xenAPI = new XenAPI();
  228.  
  229. // Set the API key.
  230. $this->apikey = $api_key;
  231.  
  232. // Lowercase the key data, ignores the case of the arguments.
  233. $this->data = array_change_key_case($this->data);
  234. if ($this->hasRequest('hash')) {
  235. // Sets the hash variable if the hash argument is set.
  236. $this->hash = $this->getRequest('hash');
  237. }
  238. // Check if grab_as by argument is set.
  239. if ($this->hasRequest('grab_as') && $this->hasAPIKey()) {
  240. if (!$this->getRequest('grab_as')) {
  241. // Throw error if the 'grab_as' argument is set but empty.
  242. $this->throwError(1, 'grab_as');
  243. }
  244. // Create a user object with the 'grab_as' argument.
  245. $this->grab_as = $this->xenAPI->getUser($this->getRequest('grab_as'));
  246. if (!$this->grab_as->isRegistered()) {
  247. // Throw error if the 'grab_as' user is not registered.
  248. $this->throwError(4, 'user', $this->getRequest('grab_as'));
  249. }
  250. }
  251. // Check if order by argument is set.
  252. if ($this->hasRequest('order_by')) {
  253. if (!$this->getRequest('order_by')) {
  254. // Throw error if the 'order_by' argument is set but empty.
  255. $this->throwError(1, 'order_by');
  256. }
  257. $this->order_by = $this->getRequest('order_by');
  258. }
  259. // Check if order argument is set.
  260. if ($this->hasRequest('order')) {
  261. if (!$this->getRequest('order')) {
  262. // Throw error if the 'order' argument is set but empty.
  263. $this->throwError(1, 'order');
  264. }
  265. $this->order = strtolower($this->getRequest('order'));
  266. if ($this->order == 'd' || $this->order == 'desc' || $this->order == 'descending') {
  267. // Order is descending (10-0).
  268. $this->order = 'desc';
  269. } else if ($this->order == 'a' || $this->order == 'asc' || $this->order == 'ascending') {
  270. // Order is ascending (0-10).
  271. $this->order = 'asc';
  272. } else {
  273. // Order is unknown, default to descending (10-0).
  274. $this->order = 'desc';
  275. }
  276. } else {
  277. // Order is not set, default to descending (10-0).
  278. $this->order = 'desc';
  279. }
  280. // Set the limit.
  281. $this->setLimit(100);
  282. }
  283.  
  284. /**
  285. * Returns the XenAPI, returns NULL if the XenAPI was not set.
  286. */
  287. public function getXenAPI() {
  288. return $this->xenAPI;
  289. }
  290.  
  291. public function isDefaultAPIKey() {
  292. return $this->getAPIKey() == self::DEFAULT_APIKEY;
  293. }
  294.  
  295. /**
  296. * Returns the API key, returns FALSE if an API key was not set.
  297. */
  298. public function getAPIKey() {
  299. return $this->apikey;
  300. }
  301.  
  302. /**
  303. * Sets the API key.
  304. */
  305. public function setAPIKey($apikey) {
  306. $this->apikey = $apikey;
  307. }
  308.  
  309. /**
  310. * Return the hash, returns FALSE if the hash was not set.
  311. */
  312. public function getHash() {
  313. return $this->hash;
  314. }
  315.  
  316. /**
  317. * TODO
  318. */
  319. public function setLimit($default) {
  320. // Check if limit argument is set.
  321. if ($this->hasRequest('limit')) {
  322. if (!$this->getRequest('limit') && (is_numeric($this->getRequest('limit')) && $this->getRequest('limit') != 0)) {
  323. // Throw error if the 'limit' argument is set but empty.
  324. $this->throwError(1, 'limit');
  325. } else if (!is_numeric($this->getRequest('limit'))) {
  326. // Throw error if the 'limit' argument is set but not a number.
  327. $this->throwError(21, 'limit');
  328. }
  329. $this->limit = $this->getRequest('limit');
  330. } else {
  331. // Limit is not set, default to $default variable.
  332. $this->limit = $default;
  333. }
  334. }
  335.  
  336. private function stripUserData($user) {
  337. /*
  338. * Run through an additional permission check if the request is
  339. * not using an API key, unset some variables depending on the
  340. * user level.
  341. */
  342. $data = $user->getData();
  343. if (!$this->hasAPIKey()) {
  344. // Unset variables since the API key isn't used.
  345. if (isset($data['style_id'])) {
  346. unset($data['style_id']);
  347. }
  348. if (isset($data['display_style_group_id'])) {
  349. unset($data['display_style_group_id']);
  350. }
  351. if (isset($data['permission_combination_id'])) {
  352. unset($data['permission_combination_id']);
  353. }
  354. if (!$this->getUser()->isAdmin()) {
  355. // Unset variables if user is not an admin.
  356. if (isset($data['is_banned'])) {
  357. unset($data['is_banned']);
  358. }
  359. }
  360. if (!$this->getUser()->isModerator() && $this->getUser()->getID() != $user->getID()) {
  361. // Unset variables if user is not a moderator.
  362. if (isset($data['user_state'])) {
  363. unset($data['user_state']);
  364. }
  365. if (isset($data['visible'])) {
  366. unset($data['visible']);
  367. }
  368. if (isset($data['email'])) {
  369. unset($data['email']);
  370. }
  371. if (isset($data['custom_fields'])) {
  372. unset($data['custom_fields']);
  373. }
  374. }
  375. if ($this->getUser()->getID() != $user->getID()) {
  376. // Unset variables if user does not equal the requested user by the 'value' argument.
  377. if (isset($data['language_id'])) {
  378. unset($data['language_id']);
  379. }
  380. if (isset($data['message_count'])) {
  381. unset($data['message_count']);
  382. }
  383. if (isset($data['conversations_unread'])) {
  384. unset($data['conversations_unread']);
  385. }
  386. if (isset($data['alerts_unread'])) {
  387. unset($data['alerts_unread']);
  388. }
  389. if (isset($data['upgrades'])) {
  390. unset($data['upgrades']);
  391. }
  392. }
  393. }
  394. return $data;
  395. }
  396.  
  397. /**
  398. * Checks if the request is authenticated.
  399. * Returns TRUE if the hash equals the API key.
  400. * Returns TRUE if the hash equals the user hash.
  401. * Returns FALSE if none of the above are TRUE.
  402. */
  403. public function isAuthenticated() {
  404. if ($this->getHash()) {
  405. // Hash argument is set, continue.
  406. if ($this->getHash() == $this->getAPIKey()) {
  407. // The hash equals the API key, return TRUE.
  408. return TRUE;
  409. }
  410. if (strpos($this->getHash(), ':') !== FALSE) {
  411. // The hash contains : (username:hash), split it into an array.
  412. $array = explode(':', $this->getHash());
  413. // Get the user and check if the user is valid (registered).
  414. $user = $this->xenAPI->getUser($array[0]);
  415. if ($user->isRegistered()) {
  416. // User is registered, get the hash from the authentication record.
  417. $record = $user->getAuthenticationRecord();
  418. $ddata = unserialize($record['data']);
  419. $decoded = base64_decode($array[1], TRUE);
  420. if ($ddata['hash'] == $array[1] || ($decoded !== FALSE && $ddata['hash'] == $decoded)) {
  421. // The hash in the authentication record equals the hash in the 'hash' argument.
  422. return TRUE;
  423. }
  424. }
  425. }
  426. }
  427. return FALSE;
  428. }
  429.  
  430. /**
  431. * Checks if the request is permitted.
  432. * Returns TRUE if API key is set and valid or the action's permission is public.
  433. */
  434. public function isPermitted() {
  435. $permission = $this->getActionPermission();
  436. // Check if the request is authenticated and it's an user hash (and not an API key).
  437. if ($this->isAuthenticated() && $this->getUser()) {
  438. switch ($permission) {
  439. case 'public':
  440. return TRUE;
  441. case 'authenticated':
  442. return TRUE;
  443. case 'moderator':
  444. return $this->getUser()->isModerator();
  445. case 'administrator':
  446. return $this->getUser()->isAdmin();
  447. case 'private':
  448. // Check if the 'value' argument is set.
  449. if ($this->hasRequest('value') && $this->getRequest('value')) {
  450. /**
  451. * Returns TRUE if the 'value' argument equals the username of the user hash.
  452. * In other words, the request is not permitted if 'value' != username.
  453. */
  454. return $this->getUser()->getUsername() == $this->getRequest('value');
  455. }
  456. // The value argument is not, request is permitted, return TRUE.
  457. return TRUE;
  458. case 'api_key':
  459. return $this->hasAPIKey();
  460. default:
  461. $this->throwError(10, $this->getAction());
  462. }
  463. }
  464. // Returns TRUE if permission of the action is public or the request has a valid API key.
  465. return $permission == 'public' || $this->hasAPIKey();
  466. }
  467.  
  468. public function getCustomArray($input_data) {
  469. // Custom fields are set.
  470. $custom_array_data = array();
  471.  
  472. // Check if there are more than one custom array.
  473. if (strpos($input_data, ',') !== FALSE) {
  474. // There are more than one custom array set.
  475. $custom_arrays = explode(',', $input_data);
  476.  
  477. // Loop through the custom fields.
  478. foreach ($custom_arrays as $custom_array) {
  479. // Check if custom array string contains = symbol, ignore if not.
  480. if (strpos($custom_array, '=') !== FALSE) {
  481. // Custom array string contains = symbol, explode it.
  482. $custom_array_list = explode('=', $custom_array);
  483.  
  484. // Add the custom item data to the array.
  485. $custom_array_data[$custom_array_list[0]] = $custom_array_list[1];
  486. }
  487. }
  488. } else if (strpos($input_data, '=') !== FALSE) {
  489. // Custom array string contains = symbol, explode it.
  490. $custom_array_list = explode('=', $input_data);
  491.  
  492. // Add the custom item data to the array.
  493. $custom_array_data[$custom_array_list[0]] = $custom_array_list[1];
  494. }
  495.  
  496. // Return the array(s).
  497. return $custom_array_data;
  498. }
  499.  
  500. /**
  501. * Returns TRUE if the request has an API key that is valid, returns FALSE if not.
  502. */
  503. public function hasAPIKey() {
  504. if ($this->getHash()) {
  505. return $this->getHash() == $this->getAPIKey();
  506. }
  507. return FALSE;
  508. }
  509.  
  510. /**
  511. * Returns the User class of the username if the hash is set and is an userhash.
  512. * Returns FALSE if the hash is not an userhash.
  513. */
  514. public function getUser() {
  515. if (isset($this->user) && $this->user !== NULL) {
  516. return $this->user;
  517. } else if (isset($this->grab_as) && $this->grab_as !== NULL) {
  518. return $this->grab_as;
  519. } else if (strpos($this->getHash(), ':') !== FALSE) {
  520. $array = explode(':', $this->getHash());
  521. $this->user = $this->xenAPI->getUser($array[0]);
  522. return $this->user;
  523. }
  524. return NULL;
  525. }
  526.  
  527. /**
  528. *
  529. */
  530. public function checkOrderBy($order_by_array) {
  531. if ($this->hasRequest('order_by')) {
  532. if (!$this->getRequest('order_by')) {
  533. // Throw error if the 'order_by' argument is set but empty.
  534. $this->throwError(1, 'order_by');
  535. }
  536. if (!in_array(strtolower($this->getRequest('order_by')), $order_by_array)) {
  537. // Throw error if the 'order_by' argument is set but could not be found in list of allowed order_by.
  538. $this->throwError(22, $this->getRequest('order_by'), implode(', ', $order_by_array));
  539. }
  540. return strtolower($this->getRequest('order_by'));
  541. }
  542. return FALSE;
  543. }
  544.  
  545. /**
  546. * Returns the method (get, post, put, delete).
  547. */
  548. public function getMethod() {
  549. return $this->method;
  550. }
  551.  
  552. /**
  553. * Returns the action name.
  554. */
  555. public function getAction() {
  556. return $this->getRequest('action');
  557. }
  558.  
  559. /**
  560. * Returns the permission name of the action.
  561. */
  562. public function getActionPermission() {
  563. return (isset($this->data['action']) && isset($this->actions[strtolower($this->getAction())]))
  564. ? strtolower($this->actions[strtolower($this->getAction())])
  565. : NULL;
  566. }
  567.  
  568. /**
  569. * Returns TRUE if the '$key' is set a argument, returns FALSE if not.
  570. */
  571. public function hasRequest($key) {
  572. return isset($this->data[strtolower($key)]);
  573. }
  574.  
  575. /**
  576. * Gets the data of the '$key', returns FALSE if the '$key' argument was not set.
  577. */
  578. public function getRequest($key) {
  579. if ($this->hasRequest($key)) {
  580. return $this->data[strtolower($key)];
  581. } else {
  582. return FALSE;
  583. }
  584. }
  585.  
  586. /**
  587. * Returns the array of all the arguments in the request.
  588. */
  589. public function getData() {
  590. return $this->data;
  591. }
  592.  
  593. /**
  594. * Returns TRUE if the action is supported, FALSE if not.
  595. */
  596. public function isSupportedAction() {
  597. return isset($this->data['action']) && array_key_exists(strtolower($this->data['action']), $this->actions);
  598. }
  599.  
  600. /**
  601. * Returns TRUE if the action is a public action (does not require a hash), FALSE if not.
  602. */
  603. public function isPublicAction() {
  604. return isset($this->data['action']) && isset($this->actions[strtolower($this->data['action'])]) && strtolower($this->actions[strtolower($this->data['action'])]) == 'public';
  605. }
  606.  
  607. /**
  608. * Returns TRUE if the action is a user action (the 'value' parameter has to be an username/id/email), FALSE if not.
  609. */
  610. public function isUserAction() {
  611. return isset($this->data['action']) && in_array(strtolower($this->data['action']), $this->user_actions);
  612. }
  613.  
  614. /**
  615. * TODO
  616. */
  617. public function checkRequestParameter($parameter, $required = TRUE) {
  618. if ($required && !$this->hasRequest($parameter)) {
  619. // The '$parameter' argument has not been set, throw error.
  620. $this->throwError(3, $parameter);
  621. } else if ($this->hasRequest($parameter) && $this->getRequest($parameter) === FALSE) {
  622. // Throw error if the '$parameter' argument is set but empty.
  623. $this->throwError(1, $parameter);
  624. }
  625. return TRUE;
  626. }
  627.  
  628. /**
  629. * TODO
  630. */
  631. public function checkRequestParameters(array $parameters, $required = TRUE) {
  632. foreach ($parameters as $parameter) {
  633. $this->checkRequestParameter($parameter, $required);
  634. }
  635. return TRUE;
  636. }
  637.  
  638. /**
  639. * TODO
  640. */
  641. public function getUserErrorID($phrase_name) {
  642. switch ($phrase_name) {
  643. case 'please_enter_value_for_all_required_fields':
  644. return 30;
  645. case 'please_enter_valid_password':
  646. return 31;
  647. case 'please_enter_name_that_is_at_least_x_characters_long':
  648. return 32;
  649. case 'please_enter_name_that_is_at_most_x_characters_long':
  650. return 33;
  651. case 'please_enter_another_name_disallowed_words':
  652. return 34;
  653. case 'please_enter_another_name_required_format':
  654. return 35;
  655. case 'please_enter_name_that_does_not_contain_any_censored_words':
  656. return 36;
  657. case 'please_enter_name_without_using_control_characters':
  658. return 37;
  659. case 'please_enter_name_that_does_not_contain_comma':
  660. return 38;
  661. case 'please_enter_name_that_does_not_resemble_an_email_address':
  662. return 39;
  663. case 'usernames_must_be_unique':
  664. return 40;
  665. case 'please_enter_valid_email':
  666. return 41;
  667. case 'email_addresses_must_be_unique':
  668. return 42;
  669. case 'email_address_you_entered_has_been_banned_by_administrator':
  670. return 43;
  671. case 'please_select_valid_time_zone':
  672. return 44;
  673. case 'please_enter_custom_title_that_does_not_contain_any_censored_words':
  674. return 45;
  675. case 'please_enter_another_custom_title_disallowed_words':
  676. return 46;
  677. case 'please_enter_valid_date_of_birth':
  678. return 47;
  679. case 'you_cannot_delete_your_own_account':
  680. return 48;
  681. case 'please_enter_valid_value':
  682. return 49;
  683. default:
  684. return 0;
  685. }
  686. }
  687.  
  688. /**
  689. * Gets the error message and replaces {ERROR} with the $extra parameter.
  690. */
  691. public function getError($error, $extra = NULL, $extra2 = NULL, $error_type = self::GENERAL_ERROR) {
  692. if ($error_type == NULL) {
  693. $error_type = self::GENERAL_ERROR;
  694. }
  695. if ($error_type == self::GENERAL_ERROR) {
  696. if (!array_key_exists($error, $this->general_errors)) {
  697. $error = 0;
  698. }
  699. $error_string = $this->general_errors[$error];
  700. } else if ($error_type == self::USER_ERROR) {
  701. if (!array_key_exists($error, $this->user_errors)) {
  702. $error = 0;
  703. }
  704. $error_string = $this->user_errors[$error];
  705. }
  706. if ($extra !== NULL) {
  707. $error_string = str_replace('{ERROR}', $extra, $error_string);
  708. }
  709. if ($extra2 !== NULL) {
  710. $error_string = str_replace('{ERROR2}', $extra2, $error_string);
  711. }
  712. return array('id' => $error, 'message' => $error_string);
  713. }
  714.  
  715. /**
  716. * Throw the error message.
  717. */
  718. public function throwError($error, $extra = NULL, $extra2 = NULL) {
  719. if ($error == self::USER_ERROR || $error == self::THREAD_ERROR || $error == self::POST_ERROR) {
  720. if ($error == self::USER_ERROR) {
  721. $error_key = 'user';
  722. } else if ($error == self::THREAD_ERROR) {
  723. $error_key = 'thread';
  724. } else if ($error == self::POST_ERROR) {
  725. $error_key = 'post';
  726. }
  727. if ($extra2 == NULL) {
  728. $extra2 = 'performing a ' . $error_key . ' action';
  729. }
  730. $user_error = $this->getError($extra['error_id'], NULL, NULL, self::USER_ERROR);
  731. $general_error = $this->getError(7, $extra2, $user_error['message']);
  732. $error_response = array(
  733. 'error' => $general_error['id'],
  734. 'message' => $general_error['message'],
  735. $error_key . '_error_id' => $user_error['id'],
  736. $error_key . '_error_field' => $extra['error_field'],
  737. $error_key . '_error_key' => $extra['error_key'],
  738. $error_key . '_error_phrase' => $extra['error_phrase']
  739. );
  740. } else {
  741. if (is_array($extra)) {
  742. $extra = implode(', ', $extra);
  743. }
  744. if (is_array($extra2)) {
  745. $extra2 = implode(', ', $extra2);
  746. }
  747. $error = $this->getError($error, $extra, $extra2, $error_type);
  748. $error_response = array('error' => $error['id'], 'message' => $error['message']);
  749. }
  750. // Throw a 400 error.
  751. header('HTTP/1.1 400 API error', TRUE, 400);
  752.  
  753. // Send error.
  754. $this->sendResponse($error_response);
  755. }
  756.  
  757. private function handleUserError($user_results, $error_key, $error_message) {
  758. if (!empty($user_results['error'])) {
  759. // Contains errors, process errors.
  760. if (is_array($user_results['errors'])) {
  761. // The error message was an array, loop through the messages.
  762. $error_keys = array();
  763. foreach ($user_results['errors'] as $error_field => $error) {
  764. if (!($error instanceof XenForo_Phrase)) {
  765. $post_error = array(
  766. 'error_id' => 1,
  767. 'error_key' => 'field_not_recognised',
  768. 'error_field' => $error_field,
  769. 'error_phrase' => $error
  770. );
  771. $this->throwError(self::USER_ERROR, $post_error, $error_message);
  772. }
  773.  
  774. // Let's init the error array.
  775. $post_error = array(
  776. 'error_id' => $this->getUserErrorID($error->getPhraseName()),
  777. 'error_key' => $error->getPhraseName(),
  778. 'error_field' => $error_field,
  779. 'error_phrase' => $error->render()
  780. );
  781.  
  782. $this->throwError(self::USER_ERROR, $post_error, $error_message);
  783. }
  784. } else {
  785. $post_error = array(
  786. 'error_id' => $user_results['error'],
  787. 'error_key' => 'general_user_' . $error_key,
  788. 'error_phrase' => $user_results['errors']
  789. );
  790. $this->throwError(self::USER_ERROR, $post_error, $error_message);
  791. // Throw error message.
  792. }
  793. } else {
  794. // Reesult was successful, return results.
  795. $this->sendResponse($user_results);
  796. }
  797. }
  798.  
  799. /**
  800. * Processes the REST request.
  801. */
  802. public function processRequest() {
  803. // Check if the action is an user action.
  804. if ($this->isUserAction()) {
  805. if ($this->hasRequest('value')) {
  806. if (!$this->getRequest('value')) {
  807. // Throw error if the 'value' argument is set but empty.
  808. $this->throwError(1, 'value');
  809. }
  810. // Create a user variable with the 'value' argument.
  811. $user = $this->xenAPI->getUser($this->getRequest('value'));
  812. if (!$user->isRegistered()) {
  813. // Throw error if the 'value' user is not registered.
  814. $this->throwError(4, 'user', $this->getRequest('value'));
  815. }
  816. } else if ($this->hasRequest('hash')) {
  817. // The 'value' argument was not set, check if hash is an API key.
  818. if ($this->hasAPIKey() && !isset($this->grab_as)) {
  819. /**
  820. * The 'hash' argument is an API key, and the 'value' argument
  821. * is required but not set, throw error.
  822. */
  823. $this->throwError(3, 'value');
  824. }
  825. // Get the user from the hash.
  826. $user = $this->getUser();
  827. } else {
  828. // Nor the 'value' argument or the 'hash' argument has been set, throw error.
  829. $this->throwError(3, 'value');
  830. }
  831. if ($this->hasRequest('with_upgrades')) {
  832. $user_upgrades = $this->getXenAPI()->getUserUpgrades($user);
  833.  
  834. if (!$user_upgrades && $this->hasRequest('user')) {
  835. $this->throwError(4, 'user upgrades', $this->getRequest('user'));
  836. }
  837. $user->data['upgrades'] = $user_upgrades;
  838. }
  839. }
  840.  
  841. switch (strtolower($this->getAction())) {
  842. case 'authenticate':
  843. /**
  844. * Authenticates the user and returns the hash that the user has to use for future requests.
  845. *
  846. * EXAMPLE:
  847. * - api.php?action=authenticate&username=USERNAME&password=PASSWORD
  848. */
  849. if (!$this->hasRequest('username')) {
  850. // The 'username' argument has not been set, throw error.
  851. $this->throwError(3, 'username');
  852. } else if (!$this->getRequest('username')) {
  853. // Throw error if the 'username' argument is set but empty.
  854. $this->throwError(1, 'username');
  855. } else if (!$this->hasRequest('password')) {
  856. // The 'password' argument has not been set, throw error.
  857. $this->throwError(3, 'password');
  858. } else if (!$this->getRequest('password')) {
  859. // Throw error if the 'password' argument is set but empty.
  860. $this->throwError(1, 'password');
  861. }
  862. // Get the user object.
  863. $user = $this->xenAPI->getUser($this->getRequest('username'));
  864. if (!$user->isRegistered()) {
  865. // Requested user was not registered, throw error.
  866. $this->throwError(4, 'user', $this->getRequest('username'));
  867. } else {
  868. // Requested user was registered, check authentication.
  869. if ($user->validateAuthentication($this->getRequest('password'))) {
  870. // Authentication was valid, grab the user's authentication record.
  871. $record = $user->getAuthenticationRecord();
  872. $ddata = unserialize($record['data']);
  873. // Send the hash in responsel.
  874. $this->sendResponse(array('hash' => base64_encode($ddata['hash'])));
  875. } else {
  876. // The username or password was wrong, throw error.
  877. $this->throwError(5, 'Invalid username or password!');
  878. }
  879. }
  880. case 'createalert':
  881. if (!$this->hasRequest('user')) {
  882. // The 'user' argument has not been set, throw error.
  883. $this->throwError(3, 'user');
  884. } else if (!$this->getRequest('user')) {
  885. // Throw error if the 'user' argument is set but empty.
  886. $this->throwError(1, 'user');
  887. } else if (!$this->hasRequest('cause_user')) {
  888. // The 'cause_user' argument has not been set, throw error.
  889. $this->throwError(3, 'cause_user');
  890. } else if (!$this->getRequest('cause_user')) {
  891. // Throw error if the 'cause_user' argument is set but empty.
  892. $this->throwError(1, 'cause_user');
  893. } else if (!$this->hasRequest('content_type')) {
  894. // The 'content_type' argument has not been set, throw error.
  895. $this->throwError(3, 'content_type');
  896. } else if (!$this->getRequest('content_type')) {
  897. // Throw error if the 'content_type' argument is set but empty.
  898. $this->throwError(1, 'content_type');
  899. } else if (!$this->hasRequest('content_id')) {
  900. // The 'content_id' argument has not been set, throw error.
  901. $this->throwError(3, 'content_id');
  902. } else if (!$this->getRequest('content_id')) {
  903. // Throw error if the 'content_id' argument is set but empty.
  904. $this->throwError(1, 'content_id');
  905. } else if (!$this->hasRequest('alert_action')) {
  906. // The 'alert_action' argument has not been set, throw error.
  907. $this->throwError(3, 'alert_action');
  908. } else if (!$this->getRequest('alert_action')) {
  909. // Throw error if the 'alert_action' argument is set but empty.
  910. $this->throwError(1, 'alert_action');
  911. }
  912.  
  913. $alert_user = $this->getXenAPI()->getUser($this->getRequest('user'));
  914. if (!$alert_user->isRegistered()) {
  915. // Requested user was not registered, throw error.
  916. $this->throwError(4, 'user', $this->getRequest('user'));
  917. }
  918.  
  919. $cause_user = $this->getXenAPI()->getUser($this->getRequest('cause_user'));
  920. if (!$cause_user->isRegistered()) {
  921. // Requested user was not registered, throw error.
  922. $this->throwError(4, 'cause_user', $this->getRequest('cause_user'));
  923. }
  924.  
  925. $alert_data = array(
  926. 'content_type' => $this->getRequest('content_type'),
  927. 'content_id' => $this->getRequest('content_id'),
  928. 'action' => $this->getRequest('alert_action')
  929. );
  930.  
  931. // Create the thread object.
  932. $alert_results = $this->xenAPI->createAlert($alert_user, $cause_user, $alert_data);
  933.  
  934. // Alert was successful, return results.
  935. $this->sendResponse($alert_results);
  936.  
  937. case 'createconversation':
  938. /**
  939. * TODO
  940. *
  941. * EXAMPLE:
  942. * - api.php
  943. */
  944. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  945. // The 'grab_as' argument has not been set, throw error.
  946. $this->throwError(3, 'grab_as');
  947. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  948. // Throw error if the 'grab_as' argument is set but empty.
  949. $this->throwError(1, 'grab_as');
  950. }
  951.  
  952. $conversation_data = array();
  953.  
  954. // Array of required parameters.
  955. $required_parameters = array('recipients', 'title', 'message');
  956.  
  957. // Array of additional parameters.
  958. $additional_parameters = array('open_invite', 'conversation_locked');
  959.  
  960. foreach ($required_parameters as $required_parameter) {
  961. // Check if the required parameter is set and not empty.
  962. $this->checkRequestParameter($required_parameter);
  963.  
  964. // Set the request value.
  965. $conversation_data[$required_parameter] = $this->getRequest($required_parameter);
  966. }
  967.  
  968. if (strpos($this->getRequest('recipients'), ',') !== FALSE) {
  969. $recipient_array = explode(',', $this->getRequest('recipients'));
  970. foreach ($recipient_array as $recipient) {
  971. $user = $this->getXenAPI()->getUser($recipient);
  972. if (!$user->isRegistered()) {
  973. // Requested user was not registered, throw error.
  974. $this->throwError(4, 'user', $recipient);
  975. }
  976. }
  977. } else {
  978. $user = $this->getXenAPI()->getUser($this->getRequest('recipients'));
  979. if (!$user->isRegistered()) {
  980. // Requested user was not registered, throw error.
  981. $this->throwError(4, 'user', $this->getRequest('recipients'));
  982. }
  983. }
  984.  
  985. foreach ($additional_parameters as $additional_parameter) {
  986. if ($this->hasRequest($additional_parameter)) {
  987. // Set the request value.
  988. $conversation_data[$additional_parameter] = TRUE;
  989. }
  990. }
  991.  
  992. // Create the conversation object.
  993. $conversation_results = $this->xenAPI->createConversation($this->getUser(), $conversation_data);
  994.  
  995. $this->handleUserError($conversation_results, 'conversation_creation_error', 'creating a new conversation');
  996. case 'createconversationreply':
  997. /**
  998. * TODO
  999. *
  1000. * EXAMPLE:
  1001. * - api.php
  1002. */
  1003. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  1004. // The 'grab_as' argument has not been set, throw error.
  1005. $this->throwError(3, 'grab_as');
  1006. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  1007. // Throw error if the 'grab_as' argument is set but empty.
  1008. $this->throwError(1, 'grab_as');
  1009. }
  1010.  
  1011. $conversation_reply_data = array();
  1012.  
  1013. // Array of required parameters.
  1014. $required_parameters = array('conversation_id', 'message');
  1015.  
  1016. foreach ($required_parameters as $required_parameter) {
  1017. // Check if the required parameter is set and not empty.
  1018. $this->checkRequestParameter($required_parameter);
  1019.  
  1020. // Set the request value.
  1021. $conversation_reply_data[$required_parameter] = $this->getRequest($required_parameter);
  1022. }
  1023.  
  1024. // Try to grab the thread from XenForo.
  1025. $conversation = $this->getXenAPI()->getConversation($this->getRequest('conversation_id'), $this->getUser());
  1026. if ($conversation == NULL) {
  1027. // Could not find the conversation, throw error.
  1028. $this->throwError(19, 'conversation', $this->getRequest('conversation_id'));
  1029. }
  1030.  
  1031. // Create the conversation reply object.
  1032. $conversation_reply_results = $this->xenAPI->createConversationReply($this->getUser(), $conversation_reply_data);
  1033.  
  1034. $this->handleUserError($conversation_reply_results, 'conversation_reply_creation_error', 'creating a new conversation reply');
  1035. case 'createpost':
  1036. /**
  1037. * TODO
  1038. *
  1039. * EXAMPLE:
  1040. * - api.php
  1041. */
  1042. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  1043. // The 'grab_as' argument has not been set, throw error.
  1044. $this->throwError(3, 'grab_as');
  1045. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  1046. // Throw error if the 'grab_as' argument is set but empty.
  1047. $this->throwError(1, 'grab_as');
  1048. }
  1049.  
  1050. if (!$this->hasRequest('thread_id')) {
  1051. // The 'thread_id' argument has not been set, throw error.
  1052. $this->throwError(3, 'thread_id');
  1053. } else if (!$this->getRequest('thread_id')) {
  1054. // Throw error if the 'thread_id' argument is set but empty.
  1055. $this->throwError(1, 'thread_id');
  1056. }
  1057.  
  1058. // Try to grab the thread from XenForo.
  1059. $thread = $this->getXenAPI()->getThread($this->getRequest('thread_id'), array(), $this->getUser());
  1060. if ($thread === NULL) {
  1061. // Could not find the thread, throw error.
  1062. $this->throwError(19, 'thread', $this->getRequest('thread_id'));
  1063. }
  1064.  
  1065. if (!$this->hasRequest('message')) {
  1066. // The 'message' argument has not been set, throw error.
  1067. $this->throwError(3, 'message');
  1068. } else if (!$this->getRequest('message')) {
  1069. // Throw error if the 'message' argument is set but empty.
  1070. $this->throwError(1, 'message');
  1071. }
  1072.  
  1073. $post_data = array(
  1074. 'thread_id' => $thread['thread_id'],
  1075. 'message' => $this->getRequest('message')
  1076. );
  1077.  
  1078. // Create the post object.
  1079. $post_results = $this->xenAPI->createPost($this->getUser(), $post_data);
  1080.  
  1081. $this->handleUserError($post_results, 'post_creation_error', 'creating a new post');
  1082. case 'createprofilepost':
  1083. /**
  1084. * TODO
  1085. *
  1086. * EXAMPLE:
  1087. * - api.php
  1088. */
  1089. // Array of required parameters.
  1090. $required_parameters = array('message');
  1091.  
  1092. foreach ($required_parameters as $required_parameter) {
  1093. // Check if the required parameter is set and not empty.
  1094. $this->checkRequestParameter($required_parameter);
  1095. }
  1096.  
  1097. if ($this->hasRequest('user')) {
  1098. if (!$this->getRequest('user')) {
  1099. // Throw error if the 'user' argument is set but empty.
  1100. $this->throwError(1, 'user');
  1101. }
  1102. $profile_user = $this->getXenAPI()->getUser($this->getRequest('user'));
  1103. if (!$user->isRegistered()) {
  1104. // Requested user was not registered, throw error.
  1105. $this->throwError(4, 'user', $this->getRequest('user'));
  1106. }
  1107. } else {
  1108. $profile_user = $user;
  1109. }
  1110.  
  1111. $profile_post_data = array(
  1112. 'user_id' => $profile_user->data['user_id'],
  1113. 'message' => $this->getRequest('message')
  1114. );
  1115.  
  1116. // Create the post object.
  1117. $profile_post_results = $this->xenAPI->createProfilePost($user, $profile_post_data);
  1118.  
  1119. $this->handleUserError($profile_post_results, 'profile_post_creation_error', 'creating a new profile post');
  1120. case 'createprofilepostcomment':
  1121. /**
  1122. * TODO
  1123. *
  1124. * EXAMPLE:
  1125. * - api.php
  1126. */
  1127. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  1128. // The 'grab_as' argument has not been set, throw error.
  1129. $this->throwError(3, 'grab_as');
  1130. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  1131. // Throw error if the 'grab_as' argument is set but empty.
  1132. $this->throwError(1, 'grab_as');
  1133. }
  1134.  
  1135. // Array of required parameters.
  1136. $required_parameters = array('profile_post_id', 'message');
  1137.  
  1138. foreach ($required_parameters as $required_parameter) {
  1139. // Check if the required parameter is set and not empty.
  1140. $this->checkRequestParameter($required_parameter);
  1141. }
  1142.  
  1143. // Try to grab the node from XenForo.
  1144. $profile_post = $this->getXenAPI()->getProfilePost($this->getRequest('profile_post_id'), array(), $this->getUser());
  1145. if ($profile_post == NULL) {
  1146. // Could not find the node, throw error.
  1147. $this->throwError(19, 'profile post', $this->getRequest('profile_post_id'));
  1148. }
  1149.  
  1150. $profile_post_comment_data = array(
  1151. 'profile_post_id' => $profile_post['profile_post_id'],
  1152. 'profile_user_id' => $profile_post['profile_user_id'],
  1153. 'message' => $this->getRequest('message')
  1154. );
  1155.  
  1156. // Create the post object.
  1157. $profile_post_comment_results = $this->xenAPI->createProfilePostComment($this->getUser(), $profile_post_comment_data);
  1158.  
  1159. $this->handleUserError($profile_post_comment_results, 'profile_post_comment_creation_error', 'creating a new profile post comment');
  1160. case 'createthread':
  1161. /**
  1162. * TODO
  1163. *
  1164. * EXAMPLE:
  1165. * - api.php
  1166. */
  1167. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  1168. // The 'grab_as' argument has not been set, throw error.
  1169. $this->throwError(3, 'grab_as');
  1170. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  1171. // Throw error if the 'grab_as' argument is set but empty.
  1172. $this->throwError(1, 'grab_as');
  1173. }
  1174.  
  1175. if (!$this->hasRequest('node_id')) {
  1176. // The 'node_id' argument has not been set, throw error.
  1177. $this->throwError(3, 'node_id');
  1178. } else if (!$this->getRequest('node_id')) {
  1179. // Throw error if the 'node_id' argument is set but empty.
  1180. $this->throwError(1, 'node_id');
  1181. }
  1182.  
  1183. // Try to grab the node from XenForo.
  1184. $node = $this->getXenAPI()->getNode($this->getRequest('node_id'), array(), $this->getUser());
  1185. if ($node == NULL) {
  1186. // Could not find the node, throw error.
  1187. $this->throwError(19, 'node', $this->getRequest('node_id'));
  1188. }
  1189.  
  1190. if (!$this->hasRequest('title')) {
  1191. // The 'title' argument has not been set, throw error.
  1192. $this->throwError(3, 'title');
  1193. } else if (!$this->getRequest('title')) {
  1194. // Throw error if the 'title' argument is set but empty.
  1195. $this->throwError(1, 'title');
  1196. }
  1197.  
  1198. if (!$this->hasRequest('message')) {
  1199. // The 'message' argument has not been set, throw error.
  1200. $this->throwError(3, 'message');
  1201. } else if (!$this->getRequest('message')) {
  1202. // Throw error if the 'message' argument is set but empty.
  1203. $this->throwError(1, 'message');
  1204. }
  1205.  
  1206. $thread_data = array();
  1207.  
  1208. // Array of additional parameters.
  1209. $additional_parameters = array('prefix_id', 'discussion_open', 'discussion_state', 'sticky');
  1210.  
  1211. foreach ($additional_parameters as $additional_parameter) {
  1212. // Check if the additional parameter is set and not empty.
  1213. $this->checkRequestParameter($additional_parameter, FALSE);
  1214.  
  1215. if ($this->getRequest($additional_parameter)) {
  1216. // Set the request value.
  1217. $thread_data[$additional_parameter] = $this->getRequest($additional_parameter);
  1218. }
  1219. }
  1220.  
  1221. // Check if the discussion state that is set exists.
  1222. if (isset($thread_data['discussion_state']) && !in_array($thread_data['discussion_state'], ['visible', 'moderated', 'deleted'])) {
  1223. // Discussion state could not be found in the discussion state list, throw error.
  1224. $this->throwError(24, $this->getRequest('discussion_state'), implode(', ', ['visible', 'moderated', 'deleted']));
  1225. }
  1226.  
  1227. $thread_data += array(
  1228. 'node_id' => $node['node_id'],
  1229. 'title' => $this->getRequest('title'),
  1230. 'message' => $this->getRequest('message')
  1231. );
  1232.  
  1233. // Create the thread object.
  1234. $thread_results = $this->xenAPI->createThread($this->getUser(), $thread_data);
  1235.  
  1236. $this->handleUserError($thread_results, 'thread_creation_error', 'creating a new thread');
  1237. case 'deletepost':
  1238. /**
  1239. * TODO
  1240. *
  1241. * EXAMPLE:
  1242. * - api.php
  1243. */
  1244. if (!$this->hasRequest('post_id')) {
  1245. // The 'post_id' argument has not been set, throw error.
  1246. $this->throwError(3, 'post_id');
  1247. } else if (!$this->getRequest('post_id')) {
  1248. // Throw error if the 'post_id' argument is set but empty.
  1249. $this->throwError(1, 'post_id');
  1250. }
  1251.  
  1252. if ($this->hasRequest('reason')) {
  1253. if (!$this->getRequest('reason')) {
  1254. // Throw error if the 'reason' argument is set but empty.
  1255. $this->throwError(1, 'reason');
  1256. }
  1257. $reason = $this->getRequest('reason');
  1258. } else {
  1259. $reason = NULL;
  1260. }
  1261.  
  1262. // Try to grab the post from XenForo.
  1263. $post = $this->getXenAPI()->getPost($this->getRequest('post_id'), array(), $this->getUser());
  1264. if ($post == NULL) {
  1265. // Could not find the post, throw error.
  1266. $this->throwError(19, 'post', $this->getRequest('post_id'));
  1267. }
  1268.  
  1269. $delete_results = $this->xenAPI->deletePost($this->getRequest('post_id'), $reason, $this->hasRequest('hard_delete'), $this->getUser());
  1270.  
  1271. $this->handleUserError($delete_results, 'post_deletion_error', 'deleting post');
  1272. case 'deleteuser':
  1273. /**
  1274. * TODO
  1275. *
  1276. * EXAMPLE:
  1277. * - api.php
  1278. */
  1279. if ($this->hasRequest('value')) {
  1280. if (!$this->getRequest('value')) {
  1281. // Throw error if the 'value' argument is set but empty.
  1282. $this->throwError(1, 'value');
  1283. }
  1284. $user = $this->getRequest('value');
  1285. } else if ($this->hasAPIKey()) {
  1286. if (!$this->hasRequest('value')) {
  1287. // The 'value' argument has not been set, throw error.
  1288. $this->throwError(3, 'value');
  1289. } else if (!$this->getRequest('value')) {
  1290. // Throw error if the 'value' argument is set but empty.
  1291. $this->throwError(1, 'value');
  1292. }
  1293. $user = $this->getRequest('value');
  1294. } else {
  1295. $user = NULL;
  1296. }
  1297.  
  1298. //if ($this->hasAPIKey() || $this->getUser()->isAdmin()) {
  1299.  
  1300. if ($this->hasRequest('reason')) {
  1301. if (!$this->getRequest('reason')) {
  1302. // Throw error if the 'reason' argument is set but empty.
  1303. $this->throwError(1, 'reason');
  1304. }
  1305. $reason = $this->getRequest('reason');
  1306. } else {
  1307. $reason = NULL;
  1308. }
  1309.  
  1310. // Try to grab the user from XenForo.
  1311. $user = $this->getXenAPI()->getUser($user);
  1312. if (!$user->isRegistered()) {
  1313. // Requested user was not registered, throw error.
  1314. $this->throwError(4, 'user', $this->getRequest('value'));
  1315. }
  1316.  
  1317. $delete_results = $this->getXenAPI()->deleteUser($user);
  1318.  
  1319. $this->handleUserError($delete_results, 'user_deletion_error', 'deleting user');
  1320. case 'editpost':
  1321. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  1322. // The 'grab_as' argument has not been set, throw error.
  1323. $this->throwError(3, 'grab_as');
  1324. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  1325. // Throw error if the 'grab_as' argument is set but empty.
  1326. $this->throwError(1, 'grab_as');
  1327. }
  1328.  
  1329. if (!$this->hasRequest('post_id')) {
  1330. // The 'post_id' argument has not been set, throw error.
  1331. $this->throwError(3, 'post_id');
  1332. } else if (!$this->getRequest('post_id')) {
  1333. // Throw error if the 'post_id' argument is set but empty.
  1334. $this->throwError(1, 'post_id');
  1335. }
  1336.  
  1337. $post = $this->getXenAPI()->getPost($this->getRequest('post_id'), array(), $this->getUser());
  1338. if ($post === NULL) {
  1339. // Could not find the post, throw error.
  1340. $this->throwError(19, 'post', $this->getRequest('post_id'));
  1341. } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) {
  1342. if (isset($this->grab_as)) {
  1343. // Post was found but the 'grab_as' user is not permitted to view the post.
  1344. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post');
  1345. } else {
  1346. // Post was found but the user is not permitted to view the post.
  1347. $this->throwError(20, 'You do', 'this post');
  1348. }
  1349. } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) {
  1350. // Post was found but the 'grab_as' user is not permitted to view the thread.
  1351. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post');
  1352. }
  1353.  
  1354. // List of fields that are accepted to be edited.
  1355. $edit_fields = array('thread_id', 'message');
  1356.  
  1357. // List of fields that the request should ignore.
  1358. $ignore_fields = array('hash', 'action', 'grab_as');
  1359.  
  1360. // Let's check which fields are set.
  1361. foreach ($this->data as $data_key => $data_item) {
  1362. if (!in_array($data_key, $ignore_fields) && in_array($data_key, $edit_fields) && $this->checkRequestParameter($data_key, FALSE)) {
  1363. $edit_data[$data_key] = $data_item;
  1364. }
  1365. }
  1366.  
  1367. if (count($edit_data) == 0) {
  1368. // There are no fields set, throw error.
  1369. $this->throwError(8, $edit_fields);
  1370. } else if (array_key_exists('thread_id', $edit_data)) {
  1371. $thread = $this->getXenAPI()->getThread($edit_data['thread_id'], array(), $this->getUser());
  1372. if ($thread == NULL) {
  1373. // Could not find the thread, throw error.
  1374. $this->throwError(19, 'thread', $edit_data['thread_id']);
  1375. }
  1376. }
  1377.  
  1378. // Get edit results.
  1379. $edit_results = $this->getXenAPI()->editPost($post, $this->getUser(), $edit_data);
  1380.  
  1381. if (empty($edit_results['error'])) {
  1382. // Edit was successful, return results.
  1383. $this->sendResponse($edit_results);
  1384. } else {
  1385. // The registration failed, process errors.
  1386. if (is_array($edit_results['errors'])) {
  1387. // The error message was an array, loop through the messages.
  1388. $error_keys = array();
  1389. foreach ($edit_results['errors'] as $error_field => $error) {
  1390. if (!($error instanceof XenForo_Phrase)) {
  1391. $edit_error = array(
  1392. 'error_id' => 1,
  1393. 'error_key' => 'field_not_recognised',
  1394. 'error_field' => $error_field,
  1395. 'error_phrase' => $error
  1396. );
  1397. // Throw error message.
  1398. $this->throwError(self::POST_ERROR, $edit_error, 'editing a post');
  1399.  
  1400. }
  1401.  
  1402. // Let's init the edit error array.
  1403. $edit_error = array(
  1404. 'error_id' => $this->getUserErrorID($error->getPhraseName()),
  1405. 'error_key' => $error->getPhraseName(),
  1406. 'error_field' => $error_field,
  1407. 'error_phrase' => $error->render()
  1408. );
  1409.  
  1410. // Throw error message.
  1411. $this->throwError(self::POST_ERROR, $edit_error, 'editing a post');
  1412. }
  1413. } else {
  1414. $edit_error = array(
  1415. 'error_id' => $edit_results['error'],
  1416. 'error_key' => 'general_post_edit_error',
  1417. 'error_phrase' => $edit_results['errors']
  1418. );
  1419. // Throw error message.
  1420. $this->throwError(self::POST_ERROR, $edit_error, 'editing a post');
  1421. }
  1422. }
  1423. case 'editthread':
  1424. if ($this->hasAPIKey() && !$this->hasRequest('grab_as')) {
  1425. // The 'grab_as' argument has not been set, throw error.
  1426. $this->throwError(3, 'grab_as');
  1427. } else if ($this->hasAPIKey() && !$this->getRequest('grab_as')) {
  1428. // Throw error if the 'grab_as' argument is set but empty.
  1429. $this->throwError(1, 'grab_as');
  1430. }
  1431.  
  1432. if (!$this->hasRequest('thread_id')) {
  1433. // The 'thread_id' argument has not been set, throw error.
  1434. $this->throwError(3, 'thread_id');
  1435. } else if (!$this->getRequest('thread_id')) {
  1436. // Throw error if the 'thread_id' argument is set but empty.
  1437. $this->throwError(1, 'thread_id');
  1438. }
  1439.  
  1440. $thread = $this->getXenAPI()->getThread($this->getRequest('thread_id'), array(), $this->getUser());
  1441. if ($thread === NULL) {
  1442. // Could not find the thread, throw error.
  1443. $this->throwError(19, 'thread', $this->getRequest('thread_id'));
  1444. } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) {
  1445. if (isset($this->grab_as)) {
  1446. // Thread was found but the 'grab_as' user is not permitted to view the thread.
  1447. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread');
  1448. } else {
  1449. // Thread was found but the user is not permitted to view the thread.
  1450. $this->throwError(20, 'You do', 'this thread');
  1451. }
  1452. } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) {
  1453. // Thread was found but the 'grab_as' user is not permitted to view the thread.
  1454. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread');
  1455. }
  1456.  
  1457. // List of fields that are accepted to be edited.
  1458. $edit_fields = array('node_id', 'title', 'prefix_id', 'discussion_open', 'sticky'); // TODO: add support for message editing
  1459.  
  1460. // List of fields that the request should ignore.
  1461. $ignore_fields = array('hash', 'action', 'grab_as');
  1462.  
  1463. // Let's check which fields are set.
  1464. foreach ($this->data as $data_key => $data_item) {
  1465. if (!in_array($data_key, $ignore_fields) && in_array($data_key, $edit_fields) && $this->checkRequestParameter($data_key, FALSE)) {
  1466. $edit_data[$data_key] = $data_item;
  1467. }
  1468. }
  1469.  
  1470. if (count($edit_data) == 0) {
  1471. // There are no fields set, throw error.
  1472. $this->throwError(8, $edit_fields);
  1473. } else if (array_key_exists('node_id', $edit_data)) {
  1474. $node = $this->getXenAPI()->getNode($edit_data['node_id'], array(), $this->getUser());
  1475. if ($node == NULL) {
  1476. // Could not find the node, throw error.
  1477. $this->throwError(19, 'node', $edit_data['node_id']);
  1478. }
  1479. }
  1480.  
  1481. // Get edit results.
  1482. $edit_results = $this->getXenAPI()->editThread($thread, $this->getUser(), $edit_data);
  1483.  
  1484. if (empty($edit_results['error'])) {
  1485. // Edit was successful, return results.
  1486. $this->sendResponse($edit_results);
  1487. } else {
  1488. // The registration failed, process errors.
  1489. if (is_array($edit_results['errors'])) {
  1490. // The error message was an array, loop through the messages.
  1491. $error_keys = array();
  1492. foreach ($edit_results['errors'] as $error_field => $error) {
  1493. if (!($error instanceof XenForo_Phrase)) {
  1494. $edit_error = array(
  1495. 'error_id' => 1,
  1496. 'error_key' => 'field_not_recognised',
  1497. 'error_field' => $error_field,
  1498. 'error_phrase' => $error
  1499. );
  1500. // Throw error message.
  1501. $this->throwError(self::THREAD_ERROR, $edit_error, 'editing a thread');
  1502.  
  1503. }
  1504.  
  1505. // Let's init the edit error array.
  1506. $edit_error = array(
  1507. 'error_id' => $this->getUserErrorID($error->getPhraseName()),
  1508. 'error_key' => $error->getPhraseName(),
  1509. 'error_field' => $error_field,
  1510. 'error_phrase' => $error->render()
  1511. );
  1512.  
  1513. // Throw error message.
  1514. $this->throwError(self::THREAD_ERROR, $edit_error, 'editing a thread');
  1515. }
  1516. } else {
  1517. $edit_error = array(
  1518. 'error_id' => $edit_results['error'],
  1519. 'error_key' => 'general_thread_edit_error',
  1520. 'error_phrase' => $edit_results['errors']
  1521. );
  1522. // Throw error message.
  1523. $this->throwError(self::THREAD_ERROR, $edit_error, 'editing a thread');
  1524. }
  1525. }
  1526. case 'edituser':
  1527. /**
  1528. * Edits the user.
  1529. */
  1530. if (!$this->hasRequest('user')) {
  1531. // The 'user' argument has not been set, throw error.
  1532. $this->throwError(3, 'user');
  1533. } else if (!$this->getRequest('user')) {
  1534. // Throw error if the 'user' argument is set but empty.
  1535. $this->throwError(1, 'user');
  1536. }
  1537. if ($this->hasRequest('custom_field_identifier')) {
  1538. if (!$this->getRequest('custom_field_identifier')) {
  1539. // Throw error if the 'custom_field_identifier' argument is set but empty.
  1540. $this->throwError(1, 'custom_field_identifier');
  1541. }
  1542. $user = $this->getXenAPI()->getUser($this->getRequest('user'), array('custom_field' => $this->getRequest('custom_field_identifier')));
  1543. } else {
  1544. // Get the user object.
  1545. $user = $this->getXenAPI()->getUser($this->getRequest('user'));
  1546. }
  1547. if (!$user->isRegistered()) {
  1548. // Requested user was not registered, throw error.
  1549. $this->throwError(4, 'user', $this->getRequest('user'));
  1550. }
  1551.  
  1552. // Init the edit array.
  1553. $edit_data = array();
  1554.  
  1555. if ($this->hasRequest('group')) {
  1556. // Request has value.
  1557. if (!$this->getRequest('group')) {
  1558. // Throw error if the 'group' argument is set but empty.
  1559. $this->throwError(1, 'group');
  1560. }
  1561. $group = $this->getXenAPI()->getGroup($this->getRequest('group'));
  1562. if (!$group) {
  1563. $edit_error = array(
  1564. 'error_id' => 2,
  1565. 'error_key' => 'group_not_found',
  1566. 'error_field' => 'group',
  1567. 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest('group') . '"'
  1568. );
  1569. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1570. }
  1571. // Set the group id of the edit.
  1572. $edit_data['group_id'] = $group['user_group_id'];
  1573. }
  1574.  
  1575. $group_fields = array('add_groups', 'remove_groups');
  1576. foreach ($group_fields as $group_field) {
  1577. if (!$this->hasRequest($group_field)) {
  1578. continue;
  1579. }
  1580. // Request has value.
  1581. if (!$this->getRequest($group_field)) {
  1582. // Throw error if the $group_field argument is set but empty.
  1583. $this->throwError(1, $group_field);
  1584. }
  1585. // Initialize the array.
  1586. $edit_data[$group_field] = array();
  1587.  
  1588. // Check if value is an array.
  1589. if (strpos($this->getRequest($group_field), ',') !== FALSE) {
  1590. // Value is an array, explode it.
  1591. $groups = explode(',', $this->getRequest($group_field));
  1592.  
  1593. // Loop through the group values.
  1594. foreach ($groups as $group_value) {
  1595. // Grab the group from the group value.
  1596. $group = $this->getXenAPI()->getGroup($group_value);
  1597.  
  1598. // Check if group was found.
  1599. if (!$group) {
  1600. // Group was not found, throw error.
  1601. $edit_error = array(
  1602. 'error_id' => 2,
  1603. 'error_key' => 'group_not_found',
  1604. 'error_field' => $group_field,
  1605. 'error_phrase' => 'Could not find group with parameter "' . $group_value . '" in array "' . $this->getRequest('add_group') . '"'
  1606. );
  1607. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1608. }
  1609. // Add the group_id to the the add_group array.
  1610. $edit_data[$group_field][] = $group['user_group_id'];
  1611. }
  1612. } else {
  1613. // Grab the group from the group value.
  1614. $group = $this->getXenAPI()->getGroup($this->getRequest($group_field));
  1615.  
  1616. // Check if group was found.
  1617. if (!$group) {
  1618. // Group was not found, throw error.
  1619. $edit_error = array(
  1620. 'error_id' => 2,
  1621. 'error_key' => 'group_not_found',
  1622. 'error_field' => $group_field,
  1623. 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest($group_field) . '"'
  1624. );
  1625. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1626. }
  1627. // Add the group_id to the the add_groups array.
  1628. $edit_data[$group_field][] = $group['user_group_id'];
  1629. }
  1630. }
  1631.  
  1632.  
  1633. if ($this->hasRequest('custom_fields')) {
  1634. // Request has value.
  1635. if (!$this->getRequest('custom_fields')) {
  1636. // Throw error if the 'custom_fields' argument is set but empty.
  1637. $this->throwError(1, 'custom_fields');
  1638. }
  1639. $custom_fields = $this->getCustomArray($this->getRequest('custom_fields'));
  1640.  
  1641. // Check if we found any valid custom fields, throw error if not.
  1642. if (count($custom_fields) == 0) {
  1643. // The custom fields array was empty, throw error.
  1644. $edit_error = array(
  1645. 'error_id' => 5,
  1646. 'error_key' => 'invalid_custom_fields',
  1647. 'error_field' => 'custom_fields',
  1648. 'error_phrase' => 'The custom fields values were invalid, valid values are: '
  1649. . 'custom_fields=custom_field1=custom_value1,custom_field2=custom_value2 '
  1650. . 'but got: "' . $this->getRequest('custom_fields') . '" instead'
  1651. );
  1652. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1653. }
  1654. $edit_data['custom_fields'] = $custom_fields;
  1655. }
  1656.  
  1657. // List of fields that are accepted to be edited.
  1658. $edit_fields = array('username', 'password', 'email', 'gender', 'custom_title', 'style_id', 'timezone', 'visible', 'dob_day', 'dob_month', 'dob_year', 'user_state', 'trophy_points');
  1659.  
  1660. // List of fields that the request should ignore.
  1661. $ignore_fields = array('hash', 'action', 'user');
  1662.  
  1663. // Let's check which fields are set.
  1664. foreach ($this->data as $data_key => $data_item) {
  1665. if (!in_array($data_key, $ignore_fields) && in_array($data_key, $edit_fields) && $this->checkRequestParameter($data_key, FALSE)) {
  1666. $edit_data[$data_key] = $data_item;
  1667. }
  1668. }
  1669.  
  1670. if (count($edit_data) == 0) {
  1671. // There are no fields set, throw error.
  1672. $this->throwError(8, $edit_fields);
  1673. }
  1674.  
  1675. // Get edit results.
  1676. $edit_results = $this->getXenAPI()->editUser($user, $edit_data);
  1677.  
  1678. if (!empty($edit_results['error'])) {
  1679. // The registration failed, process errors.
  1680. if (is_array($edit_results['errors'])) {
  1681. // The error message was an array, loop through the messages.
  1682. $error_keys = array();
  1683. foreach ($edit_results['errors'] as $error_field => $error) {
  1684. if (!($error instanceof XenForo_Phrase)) {
  1685. $edit_error = array(
  1686. 'error_id' => 1,
  1687. 'error_key' => 'field_not_recognised',
  1688. 'error_field' => $error_field,
  1689. 'error_phrase' => $error
  1690. );
  1691. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1692. }
  1693.  
  1694. // Let's init the edit error array.
  1695. $edit_error = array(
  1696. 'error_id' => $this->getUserErrorID($error->getPhraseName()),
  1697. 'error_key' => $error->getPhraseName(),
  1698. 'error_field' => $error_field,
  1699. 'error_phrase' => $error->render()
  1700. );
  1701.  
  1702. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1703. }
  1704. } else {
  1705. $edit_error = array(
  1706. 'error_id' => $edit_results['error'],
  1707. 'error_key' => 'general_user_edit_error',
  1708. 'error_phrase' => $edit_results['errors']
  1709. );
  1710. $this->throwError(self::USER_ERROR, $edit_error, 'editing an user');
  1711. // Throw error message.
  1712. }
  1713. } else {
  1714. // Edit was successful, return results.
  1715. $this->sendResponse($edit_results);
  1716. }
  1717. case 'getactions':
  1718. /**
  1719. * Returns the actions and their permission levels.
  1720. *
  1721. * EXAMPLE:
  1722. * - api.php?action=getActions
  1723. */
  1724. /*
  1725.  
  1726. // TODO: Only show actions depending on what permission level the user is.
  1727. $temp = array();
  1728. foreach ($this->actions as $action => $permission) {
  1729. $temp[$action] = $permission;
  1730. }
  1731. */
  1732. // Send the response.
  1733. $this->sendResponse($this->actions);
  1734. case 'getaddon':
  1735. /**
  1736. * Returns the addon information depending on the 'value' argument.
  1737. *
  1738. * NOTE: Only addon ID's can be used for the 'value' parameter.
  1739. * Addon ID's can be found by using the 'getAddons' action.
  1740. *
  1741. * EXAMPLE:
  1742. * - api.php?action=getAddon&value=PostRating&hash=USERNAME:HASH
  1743. * - api.php?action=getAddon&value=PostRating&hash=API_KEY
  1744. */
  1745. if (!$this->hasRequest('value')) {
  1746. // The 'value' argument has not been set, throw error.
  1747. $this->throwError(3, 'value');
  1748. } else if (!$this->getRequest('value')) {
  1749. // Throw error if the 'value' argument is set but empty.
  1750. $this->throwError(1, 'value');
  1751. }
  1752. $string = $this->getRequest('value');
  1753. // Try to grab the addon from XenForo.
  1754. $addon = $this->getXenAPI()->getAddon($string);
  1755. if (!$addon->isInstalled()) {
  1756. // Could not find the addon, throw error.
  1757. $this->throwError(13, $string);
  1758. } else {
  1759. // Addon was found, send response.
  1760. $this->sendResponse(Addon::getLimitedData($addon));
  1761. }
  1762. case 'getaddons':
  1763. /**
  1764. * Returns a list of addons, if a type is not specified or not supported,
  1765. * default (all) is used instead.
  1766. *
  1767. * Options for the 'type' argument are:
  1768. * - all: This is default, and will return all the addons, ignoring if they are installed or not.
  1769. * - enabled: Fetches all the addons that are enabled, ignoring the disabled ones.
  1770. * - disabled: Fetches all the addons that are disabled, ignoring the enabled ones.
  1771. *
  1772. * For more information, see /library/XenForo/Model/Alert.php.
  1773. *
  1774. * EXAMPLES:
  1775. * - api.php?action=getAddons&hash=USERNAME:HASH
  1776. * - api.php?action=getAddons&hash=API_KEY
  1777. * - api.php?action=getAddons&type=enabled&hash=USERNAME:HASH
  1778. * - api.php?action=getAddons&type=enabled&hash=API_KEY
  1779. */
  1780. /*
  1781. * Check if the request has the 'type' argument set,
  1782. * if it doesn't it uses the default (all).
  1783. */
  1784. if ($this->hasRequest('type')) {
  1785. if (!$this->getRequest('type')) {
  1786. // Throw error if the 'type' argument is set but empty.
  1787. $this->throwError(1, 'type');
  1788. }
  1789. // Use the value from the 'type' argument to get the alerts.
  1790. $installed_addons = $this->xenAPI->getAddons($this->getRequest('type'));
  1791. } else {
  1792. // Use the default type to get the alerts.
  1793. $installed_addons = $this->xenAPI->getAddons();
  1794. }
  1795. // Create an array for the addons.
  1796. $addons = array();
  1797. // Loop through all the addons and strip out any information that we don't need.
  1798. foreach ($installed_addons as $addon) {
  1799. $addons[] = Addon::getLimitedData($addon);
  1800. }
  1801. // Send the response.
  1802. $this->sendResponse(array('count' => count($addons), 'addons' => $addons));
  1803. case 'getalerts':
  1804. /**
  1805. * Grabs the alerts from the specified user, if type is not specified,
  1806. * default (recent alerts) is used instead.
  1807. *
  1808. * NOTE: The 'value' argument will only work for the user itself and
  1809. * not on others users unless the permission argument for the
  1810. * 'getalerts' action is changed (default permission: private).
  1811. *
  1812. * Options for the 'type' argument are:
  1813. * - fetchPopupItems: Fetch alerts viewed in the last options:alertsPopupExpiryHours hours.
  1814. * - fetchRecent: Fetch alerts viewed in the last options:alertExpiryDays days.
  1815. * - fetchAll: Fetch alerts regardless of their view_date.
  1816. *
  1817. * For more information, see /library/XenForo/Model/Alert.php.
  1818. *
  1819. * EXAMPLES:
  1820. * - api.php?action=getAlerts&hash=USERNAME:HASH
  1821. * - api.php?action=getAlerts&type=fetchAll&hash=USERNAME:HASH
  1822. * - api.php?action=getAlerts&value=USERNAME&hash=USERNAME:HASH
  1823. * - api.php?action=getAlerts&value=USERNAME&type=fetchAll&hash=USERNAME:HASH
  1824. * - api.php?action=getAlerts&value=USERNAME&hash=API_KEY
  1825. * - api.php?action=getAlerts&value=USERNAME&type=fetchAll&hash=API_KEY
  1826. */
  1827. /*
  1828. * Check if the request has the 'type' argument set,
  1829. * if it doesn't it uses the default (fetchRecent).
  1830. */
  1831. if ($this->hasRequest('type')) {
  1832. if (!$this->getRequest('type')) {
  1833. // Throw error if the 'type' argument is set but empty.
  1834. $this->throwError(1, 'type');
  1835. }
  1836. // Use the value from the 'type' argument to get the alerts.
  1837. $data = $user->getAlerts($this->getRequest('type'));
  1838. } else {
  1839. // Use the default type to get the alerts.
  1840. $data = $user->getAlerts();
  1841. }
  1842. // Send the response.
  1843. $this->sendResponse($data);
  1844. case 'getavatar':
  1845. /**
  1846. * Returns the avatar of the requested user.
  1847. *
  1848. * Options for the 'size' argument are:
  1849. * - s (Small)
  1850. * - m (Medium)
  1851. * - l (Large)
  1852. *
  1853. * NOTE: The default avatar size is 'Medium'.
  1854. *
  1855. * EXAMPLES:
  1856. * - api.php?action=getAvatar&hash=USERNAME:HASH
  1857. * - api.php?action=getAvatar&size=M&hash=USERNAME:HASH
  1858. * - api.php?action=getAvatar&value=USERNAME&hash=USERNAME:HASH
  1859. * - api.php?action=getAvatar&value=USERNAME&size=M&hash=USERNAME:HASH
  1860. * - api.php?action=getAvatar&value=USERNAME&hash=API_KEY
  1861. * - api.php?action=getAvatar&value=USERNAME&size=M&hash=API_KEY
  1862. */
  1863. if ($this->hasRequest('size')) {
  1864. if (!$this->getRequest('size')) {
  1865. // Throw error if the 'size' argument is set but empty.
  1866. $this->throwError(1, 'size');
  1867. }
  1868. // Use the value from the 'size' argument.
  1869. $size = strtolower($this->getRequest('size'));
  1870. if (!in_array($size, array('s', 'm', 'l'))) {
  1871. /**
  1872. * The value from the 'size' argument was not valid,
  1873. * use default size (medium) instead.
  1874. */
  1875. $size = 'm';
  1876. }
  1877. } else {
  1878. // No specific size was requested, use default size (medium):
  1879. $size = 'm';
  1880. }
  1881. // Send the response.
  1882. $this->sendResponse(array('avatar' => $user->getAvatar($size)));
  1883. case 'getconversation':
  1884. if (!$this->hasRequest('conversation_id')) {
  1885. // The 'conversation_id' argument has not been set, throw error.
  1886. $this->throwError(3, 'conversation_id');
  1887. } else if (!$this->getRequest('conversation_id')) {
  1888. // Throw error if the 'conversation_id' argument is set but empty.
  1889. $this->throwError(1, 'conversation_id');
  1890. }
  1891.  
  1892. // Try to grab the thread from XenForo.
  1893. $conversation = $this->getXenAPI()->getConversation($this->getRequest('conversation_id'), $user, array('join' => XenForo_Model_Conversation::FETCH_FIRST_MESSAGE));
  1894. if ($conversation == NULL) {
  1895. // Could not find the conversation, throw error.
  1896. $this->throwError(19, 'conversation', $this->getRequest('conversation_id'));
  1897. }
  1898.  
  1899. // Send the response.
  1900. $this->sendResponse($conversation);
  1901. case 'getgroup':
  1902. /**
  1903. * Returns the group information depending on the 'value' argument.
  1904. *
  1905. * NOTE: Only group titles, user titles and group ID's can be used for the 'value' parameter.
  1906. *
  1907. * EXAMPLE:
  1908. * - api.php?action=getGroup&value=1
  1909. * - api.php?action=getGroup&value=Guest
  1910. */
  1911. if (!$this->hasRequest('value')) {
  1912. // The 'value' argument has not been set, throw error.
  1913. $this->throwError(3, 'value');
  1914. } else if (!$this->getRequest('value')) {
  1915. // Throw error if the 'value' argument is set but empty.
  1916. $this->throwError(1, 'value');
  1917. }
  1918. $string = $this->getRequest('value');
  1919.  
  1920. // Get the group from XenForo.
  1921. $group = $this->getXenAPI()->getGroup($string);
  1922.  
  1923. if (!$group) {
  1924. // Could not find any groups, throw error.
  1925. $this->throwError(4, 'group', $string);
  1926. } else {
  1927. // Group was found, send response.
  1928. $this->sendResponse($group);
  1929. }
  1930. case 'getconversations':
  1931. /**
  1932. * Grabs the conversations from the specified user.
  1933. *
  1934. * NOTE: The 'value' argument will only work for the user itself and
  1935. * not on others users unless the permission argument for the
  1936. * 'getconversations' action is changed (default permission: private).
  1937. *
  1938. * EXAMPLES:
  1939. * - api.php?action=getConversations&hash=USERNAME:HASH
  1940. * - api.php?action=getConversations&value=USERNAME&hash=USERNAME:HASH
  1941. * - api.php?action=getConversations&value=USERNAME&hash=API_KEY
  1942. */
  1943. // Init variables.
  1944. $conditions = array();
  1945. $this->setLimit(10);
  1946. $fetch_options = array('limit' => $this->limit, 'join' => XenForo_Model_Conversation::FETCH_FIRST_MESSAGE);
  1947.  
  1948. // Grab the conversations.
  1949. $conversations = $this->getXenAPI()->getConversations($user, $conditions, $fetch_options);
  1950.  
  1951. // Send the response.
  1952. $this->sendResponse(array('count' => count($conversations), 'conversations' => $conversations));
  1953. case 'getgroup':
  1954. /**
  1955. * Returns the group information depending on the 'value' argument.
  1956. *
  1957. * NOTE: Only group titles, user titles and group ID's can be used for the 'value' parameter.
  1958. *
  1959. * EXAMPLE:
  1960. * - api.php?action=getGroup&value=1
  1961. * - api.php?action=getGroup&value=Guest
  1962. */
  1963. if (!$this->hasRequest('value')) {
  1964. // The 'value' argument has not been set, throw error.
  1965. $this->throwError(3, 'value');
  1966. } else if (!$this->getRequest('value')) {
  1967. // Throw error if the 'value' argument is set but empty.
  1968. $this->throwError(1, 'value');
  1969. }
  1970. $string = $this->getRequest('value');
  1971.  
  1972. // Get the group from XenForo.
  1973. $group = $this->getXenAPI()->getGroup($string);
  1974.  
  1975. if (!$group) {
  1976. // Could not find any groups, throw error.
  1977. $this->throwError(4, 'group', $string);
  1978. } else {
  1979. // Group was found, send response.
  1980. $this->sendResponse($group);
  1981. }
  1982. case 'getnode':
  1983. /**
  1984. * Returns the node information depending on the 'value' argument.
  1985. *
  1986. * NOTE: Only node ID's can be used for the 'value' parameter.
  1987. * Node ID's can be found by using the 'getNodes' action.
  1988. *
  1989. * The user needs permission to see the thread if the request is
  1990. * using a user hash and not an API key.
  1991. *
  1992. * EXAMPLE:
  1993. * - api.php?action=getNode&value=4&hash=USERNAME:HASH
  1994. * - api.php?action=getNode&value=4&hash=API_KEY
  1995. */
  1996. if (!$this->hasRequest('value')) {
  1997. // The 'value' argument has not been set, throw error.
  1998. $this->throwError(3, 'value');
  1999. } else if (!$this->getRequest('value')) {
  2000. // Throw error if the 'value' argument is set but empty.
  2001. $this->throwError(1, 'value');
  2002. }
  2003. $string = $this->getRequest('value');
  2004. // Try to grab the node from XenForo.
  2005. $node = $this->getXenAPI()->getNode($string);
  2006. if ($node == NULL) {
  2007. // Could not find the node, throw error.
  2008. $this->throwError(19, 'node', $string);
  2009. } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewNode($this->getUser(), $node)) {
  2010. if (isset($this->grab_as)) {
  2011. // Thread was found but the 'grab_as' user is not permitted to view the node.
  2012. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this node');
  2013. } else {
  2014. // Thread was found but the user is not permitted to view the node.
  2015. $this->throwError(20, 'You do', 'this node');
  2016. }
  2017. } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewNode($this->getUser(), $node)) {
  2018. // Thread was found but the 'grab_as' user is not permitted to view the node.
  2019. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this node');
  2020. } else {
  2021. // Thread was found, and the request was permitted.
  2022. $this->sendResponse($node);
  2023. }
  2024. case 'getnodes':
  2025. /**
  2026. * Returns a list of nodes.
  2027. *
  2028. * EXAMPLES:
  2029. * - api.php?action=getNodes&hash=USERNAME:HASH
  2030. * - api.php?action=getNodes&hash=API_KEY
  2031. */
  2032. // Init variables.
  2033. $this->setLimit(10);
  2034. $fetch_options = array('limit' => $this->limit);
  2035.  
  2036. // Check if request has node_type.
  2037. if ($this->hasRequest('node_type')) {
  2038. if (!$this->getRequest('node_type')) {
  2039. // Throw error if the 'node_type' argument is set but empty.
  2040. $this->throwError(1, 'node_type');
  2041. }
  2042.  
  2043. // Set the node_type.
  2044. $node_type = strtolower($this->getRequest('node_type'));
  2045.  
  2046. // Check if the node type that is set exists.
  2047. if (!in_array($node_type, $this->getXenAPI()->getNodeTypes()) && $node_type != 'all') {
  2048. // Node type could not be found in the node type list, throw error.
  2049. $this->throwError(23, $this->getRequest('node_type'), implode(', ', $this->getXenAPI()->getNodeTypes()));
  2050. }
  2051. } else {
  2052. $node_type = 'all';
  2053. }
  2054.  
  2055. // Get the nodes.
  2056. $nodes = $this->getXenAPI()->getNodes($node_type, $fetch_options, $this->getUser());
  2057.  
  2058. // Send the response.
  2059. $this->sendResponse(array('count' => count($nodes), 'nodes' => $nodes));
  2060. case 'getpost':
  2061. /**
  2062. * Returns the post information depending on the 'value' argument.
  2063. *
  2064. * NOTE: Only post ID's can be used for the 'value' parameter.
  2065. * Post ID's can be found by using the 'getPosts' action.
  2066. *
  2067. * The user needs permission to see the thread if the request is
  2068. * using a user hash and not an API key.
  2069. *
  2070. * EXAMPLE:
  2071. * - api.php?action=getPost&value=820&hash=USERNAME:HASH
  2072. * - api.php?action=getPost&value=820&hash=API_KEY
  2073. */
  2074. if (!$this->hasRequest('value')) {
  2075. // The 'value' argument has not been set, throw error.
  2076. $this->throwError(3, 'value');
  2077. } else if (!$this->getRequest('value')) {
  2078. // Throw error if the 'value' argument is set but empty.
  2079. $this->throwError(1, 'value');
  2080. }
  2081. $string = $this->getRequest('value');
  2082. // Try to grab the post from XenForo.
  2083. $post = $this->getXenAPI()->getPost($string, array('join' => XenForo_Model_Post::FETCH_FORUM));
  2084. if ($post == NULL) {
  2085. // Could not find the post, throw error.
  2086. $this->throwError(19, 'post', $string);
  2087. } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) {
  2088. if (isset($this->grab_as)) {
  2089. // Post was found but the 'grab_as' user is not permitted to view the post.
  2090. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post');
  2091. } else {
  2092. // Post was found but the user is not permitted to view the post.
  2093. $this->throwError(20, 'You do', 'this post');
  2094. }
  2095. } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewPost($this->getUser(), $post)) {
  2096. // Post was found but the 'grab_as' user is not permitted to view the post.
  2097. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this post');
  2098. } else {
  2099. // Post was found, and the request was permitted.
  2100. $this->sendResponse($post);
  2101. }
  2102. case 'getposts':
  2103. /**
  2104. * Returns a list of posts.
  2105. *
  2106. * NOTE: Only usernames and user ID's can be used for the 'author' parameter.
  2107. *
  2108. * EXAMPLES:
  2109. * - api.php?action=getPosts&hash=USERNAME:HASH
  2110. * - api.php?action=getPosts&hash=API_KEY
  2111. * - api.php?action=getPosts&author=Contex&hash=USERNAME:HASH
  2112. * - api.php?action=getPosts&author=1&hash=API_KEY
  2113. */
  2114. // Init variables.
  2115. $conditions = array();
  2116. $this->setLimit(10);
  2117. $fetch_options = array('limit' => $this->limit);
  2118.  
  2119. // Check if request has author.
  2120. if ($this->hasRequest('author')) {
  2121. if (!$this->getRequest('author')) {
  2122. // Throw error if the 'author' argument is set but empty.
  2123. $this->throwError(1, 'author');
  2124. }
  2125. // Grab the user object of the author.
  2126. $user = $this->xenAPI->getUser($this->getRequest('author'));
  2127. if (!$user->isRegistered()) {
  2128. // Throw error if the 'author' user is not registered.
  2129. $this->throwError(4, 'user', $this->getRequest('author'));
  2130. }
  2131. // Add the user ID to the query conditions.
  2132. $conditions['user_id'] = $user->getID();
  2133. unset($user);
  2134. }
  2135.  
  2136. // Check if request has node id.
  2137. if ($this->hasRequest('node_id')) {
  2138. if (!$this->getRequest('node_id') && (is_numeric($this->getRequest('node_id')) && $this->getRequest('node_id') != 0)) {
  2139. // Throw error if the 'node_id' argument is set but empty.
  2140. $this->throwError(1, 'node_id');
  2141. } else if (!is_numeric($this->getRequest('node_id'))) {
  2142. // Throw error if the 'node_id' argument is set but not a number.
  2143. $this->throwError(21, 'node_id');
  2144. }
  2145. if (!$this->xenAPI->getNode($this->getRequest('node_id'))) {
  2146. // Could not find any nodes, throw error.
  2147. $this->throwError(4, 'node', $this->getRequest('node_id'));
  2148. }
  2149. // Add the node ID to the query conditions.
  2150. $conditions['node_id'] = $this->getRequest('node_id');
  2151. }
  2152.  
  2153. // Check if request has thread id.
  2154. if ($this->hasRequest('thread_id')) {
  2155. if (!$this->getRequest('thread_id') && (is_numeric($this->getRequest('thread_id')) && $this->getRequest('thread_id') != 0)) {
  2156. // Throw error if the 'thread_id' argument is set but empty.
  2157. $this->throwError(1, 'thread_id');
  2158. } else if (!is_numeric($this->getRequest('thread_id'))) {
  2159. // Throw error if the 'thread_id' argument is set but not a number.
  2160. $this->throwError(21, 'thread_id');
  2161. }
  2162. if (!$this->xenAPI->getThread($this->getRequest('thread_id'))) {
  2163. // Could not find any threads, throw error.
  2164. $this->throwError(4, 'thread_id', $this->getRequest('thread_id'));
  2165. }
  2166. // Add the node ID to the query conditions.
  2167. $conditions['thread_id'] = $this->getRequest('thread_id');
  2168. }
  2169.  
  2170. // Check if the order by argument is set.
  2171. $order_by_field = $this->checkOrderBy(array('post_id', 'thread_id', 'user_id', 'username', 'post_date', 'attach_count', 'likes', 'node_id'));
  2172.  
  2173. // Add the order by options to the fetch options.
  2174. if ($this->hasRequest('order_by')) {
  2175. $fetch_options['order'] = $order_by_field;
  2176. $fetch_options['orderDirection'] = $this->order;
  2177. }
  2178.  
  2179. // Get the posts.
  2180. $posts = $this->getXenAPI()->getPosts($conditions, $fetch_options, $this->getUser());
  2181.  
  2182. // Send the response.
  2183. $this->sendResponse(array('count' => count($posts), 'posts' => $posts));
  2184. case 'getprofilepost':
  2185. /**
  2186. * Returns the profile post information depending on the 'value' argument.
  2187. *
  2188. * NOTE: Only profile post ID's can be used for the 'value' parameter.
  2189. * Profile post ID's can be found by using the 'getProfilePosts' action.
  2190. *
  2191. * The user needs permission to see the profile post if the request is
  2192. * using a user hash and not an API key.
  2193. *
  2194. * EXAMPLE:
  2195. * - api.php?action=getProfilePost&value=820&hash=USERNAME:HASH
  2196. * - api.php?action=getProfilePost&value=820&hash=API_KEY
  2197. */
  2198. if (!$this->hasRequest('value')) {
  2199. // The 'value' argument has not been set, throw error.
  2200. $this->throwError(3, 'value');
  2201. } else if (!$this->getRequest('value')) {
  2202. // Throw error if the 'value' argument is set but empty.
  2203. $this->throwError(1, 'value');
  2204. }
  2205. $string = $this->getRequest('value');
  2206. // Try to grab the profile post from XenForo.
  2207. $profile_post = $this->getXenAPI()->getProfilePost($string);
  2208. if ($profile_post == NULL) {
  2209. // Could not find the profile post, throw error.
  2210. $this->throwError(19, 'profile post', $string);
  2211. } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewProfilePost($this->getUser(), $profile_post)) {
  2212. if (isset($this->grab_as)) {
  2213. // Thread was found but the 'grab_as' user is not permitted to view the thread.
  2214. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this profile post');
  2215. } else {
  2216. // Thread was found but the user is not permitted to view the profile post.
  2217. $this->throwError(20, 'You do', 'this profile post');
  2218. }
  2219. } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewProfilePost($this->getUser(), $profile_post)) {
  2220. // Thread was found but the 'grab_as' user is not permitted to view the profile post.
  2221. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this profile post');
  2222. } else {
  2223. // Post was found, and the request was permitted.
  2224. $this->sendResponse($profile_post);
  2225. }
  2226. case 'getprofileposts':
  2227. /**
  2228. * Returns a list of profile posts.
  2229. *
  2230. * NOTE: Only usernames and user ID's can be used for the 'author' parameter.
  2231. *
  2232. * EXAMPLES:
  2233. * - api.php?action=getProfilePosts&hash=USERNAME:HASH
  2234. * - api.php?action=getProfilePosts&hash=API_KEY
  2235. * - api.php?action=getProfilePosts&author=Contex&hash=USERNAME:HASH
  2236. * - api.php?action=getProfilePosts&author=1&hash=API_KEY
  2237. */
  2238. // Init variables.
  2239. $conditions = array();
  2240. $this->setLimit(10);
  2241. $fetch_options = array('limit' => $this->limit);
  2242.  
  2243. // Check if request has author.
  2244. if ($this->hasRequest('author')) {
  2245. if (!$this->getRequest('author')) {
  2246. // Throw error if the 'author' argument is set but empty.
  2247. $this->throwError(1, 'author');
  2248. }
  2249. // Grab the user object of the author.
  2250. $user = $this->xenAPI->getUser($this->getRequest('author'));
  2251. if (!$user->isRegistered()) {
  2252. // Throw error if the 'author' user is not registered.
  2253. $this->throwError(4, 'user', $this->getRequest('author'));
  2254. }
  2255. // Add the user ID to the query conditions.
  2256. $conditions['author_id'] = $user->getID();
  2257. unset($user);
  2258. }
  2259.  
  2260. // Check if request has profile user.
  2261. if ($this->hasRequest('profile')) {
  2262. if (!$this->getRequest('profile')) {
  2263. // Throw error if the 'profile' argument is set but empty.
  2264. $this->throwError(1, 'profile');
  2265. }
  2266. // Grab the user object of the profile.
  2267. $user = $this->xenAPI->getUser($this->getRequest('profile'));
  2268. if (!$user->isRegistered()) {
  2269. // Throw error if the 'author' user is not registered.
  2270. $this->throwError(4, 'user', $this->getRequest('profile'));
  2271. }
  2272. // Add the user ID to the query conditions.
  2273. $conditions['profile_id'] = $user->getID();
  2274. unset($user);
  2275. }
  2276.  
  2277. // Check if the order by argument is set.
  2278. $order_by_field = $this->checkOrderBy(array('profile_post_id', 'profile_user_id', 'user_id', 'username', 'post_date',
  2279. 'attach_count', 'likes', 'comment_count', 'first_comment_date',
  2280. 'last_comment_date'));
  2281.  
  2282. // Add the order by options to the fetch options.
  2283. if ($this->hasRequest('order_by')) {
  2284. $fetch_options['order'] = $order_by_field;
  2285. $fetch_options['orderDirection'] = $this->order;
  2286. }
  2287.  
  2288. // Get the profile posts.
  2289. $profile_posts = $this->getXenAPI()->getProfilePosts($conditions, $fetch_options, $this->getUser());
  2290.  
  2291. // Send the response.
  2292. $this->sendResponse(array('count' => count($profile_posts), 'profile_posts' => $profile_posts));
  2293. case 'getresource':
  2294. /**
  2295. * Returns the resource information depending on the 'value' argument.
  2296. *
  2297. * NOTE: Only resource ID's can be used for the 'value' parameter.
  2298. * Resource ID's can be found by using the 'getResources' action.
  2299. *
  2300. * EXAMPLE:
  2301. * - api.php?action=getResource&value=1&hash=USERNAME:HASH
  2302. * - api.php?action=getResource&value=1&hash=API_KEY
  2303. */
  2304. /*
  2305. * Check the resource addon is installed
  2306. */
  2307. if (!$this->getXenAPI()->getModels()->hasModel('resource')) {
  2308. $this->throwError(16, 'resource');
  2309. }
  2310. $fetchOptions = array();
  2311. /*
  2312. * Check if the request has the 'grab_description' argument set.
  2313. */
  2314. if ($this->hasRequest('grab_description')) {
  2315. // Grab resources with description
  2316. $fetchOptions['join'] = XenResource_Model_Resource::FETCH_DESCRIPTION;
  2317. }
  2318. if (!$this->hasRequest('value')) {
  2319. // The 'value' argument has not been set, throw error.
  2320. $this->throwError(3, 'value');
  2321. } else if (!$this->getRequest('value')) {
  2322. // Throw error if the 'value' argument is set but empty.
  2323. $this->throwError(1, 'value');
  2324. }
  2325. $string = $this->getRequest('value');
  2326. // Try to grab the addon from XenForo.
  2327. $resource = $this->getXenAPI()->getResource($string, $fetchOptions);
  2328. if (!$resource->isValid()) {
  2329. // Could not find the resource, throw error.
  2330. $this->throwError(15, $string);
  2331. } else {
  2332. // Resource was found, send response.
  2333. $this->sendResponse(Resource::getLimitedData($resource));
  2334. }
  2335. case 'getresources':
  2336. /**
  2337. * Returns a list of resources, either all the resources,
  2338. * or just the resources created by an author.
  2339. *
  2340. * NOTE: Only usernames and user ID's can be used for the 'author' parameter.
  2341. * NOTE: Only resource category ID's can be used for the 'category_id' parameter.
  2342. *
  2343. * EXAMPLES:
  2344. * - api.php?action=getResources&hash=USERNAME:HASH
  2345. * - api.php?action=getResources&hash=API_KEY
  2346. * - api.php?action=getResources&author=Contex&hash=USERNAME:HASH
  2347. * - api.php?action=getResources&author=1&hash=API_KEY
  2348. * - api.php?action=getResources&author=Contex&category_id=1&hash=USERNAME:HASH
  2349. * - api.php?action=getResources&author=1&category_id=2&hash=API_KEY
  2350. */
  2351. /*
  2352. * Check the resource addon is installed
  2353. */
  2354. if (!$this->getXenAPI()->getModels()->hasModel('resource')) {
  2355. $this->throwError(16, 'resource');
  2356. }
  2357. $conditions = array();
  2358. $fetchOptions = array();
  2359. /*
  2360. * Check if the request has the 'grab_description' argument set.
  2361. */
  2362. if ($this->hasRequest('grab_description')) {
  2363. // Grab resources with description
  2364. $fetchOptions['join'] = XenResource_Model_Resource::FETCH_DESCRIPTION;
  2365. }
  2366. /*
  2367. * Check if the request has the 'category_id' argument set.
  2368. */
  2369. if ($this->hasRequest('category_id')) {
  2370. if (!$this->getRequest('category_id')) {
  2371. // Throw error if the 'category_id' argument is set but empty.
  2372. $this->throwError(1, 'category_id');
  2373. }
  2374. // Use the value from the 'category_id' argument to set the variables.
  2375. $conditions['resource_category_id'] = $this->getRequest('category_id');
  2376.  
  2377. }
  2378. /*
  2379. * Check if the request has the 'author' argument set,
  2380. * if it doesn't it uses the default (all).
  2381. */
  2382. if ($this->hasRequest('author')) {
  2383. if (!$this->getRequest('author')) {
  2384. // Throw error if the 'author' argument is set but empty.
  2385. $this->throwError(1, 'author');
  2386. }
  2387.  
  2388. // Create a user variable with the 'author' argument.
  2389. $user = $this->xenAPI->getUser($this->getRequest('author'));
  2390. if (!$user->isRegistered()) {
  2391. // Throw error if the 'author' user is not registered.
  2392. $this->throwError(4, 'user', $this->getRequest('author'));
  2393. }
  2394.  
  2395. // Use the value from the 'author' argument to set the variables.
  2396. $conditions['user_id'] = $user->getID();
  2397. }
  2398.  
  2399. $resources_list = $this->getXenAPI()->getResources($conditions, $fetchOptions);
  2400.  
  2401. // Create an array for the resources.
  2402. $resources = array();
  2403. // Loop through all the resources and strip out any information that we don't need.
  2404. foreach ($resources_list as $resource) {
  2405. $resources[] = Resource::getLimitedData($resource);
  2406. }
  2407. // Send the response.
  2408. $this->sendResponse(array('count' => count($resources), 'resources' => $resources));
  2409. case 'getresourcecategories':
  2410. /**
  2411. * Returns a list of resource categories
  2412. *
  2413. * EXAMPLES:
  2414. * - api.php?action=getResourceCategories&hash=USERNAME:HASH
  2415. * - api.php?action=getResourceCategories&hash=API_KEY
  2416. */
  2417. /*
  2418. * Check the resource addon is installed
  2419. */
  2420. if (!$this->getXenAPI()->getModels()->hasModel('resource')) {
  2421. $this->throwError(16, 'resource');
  2422. }
  2423.  
  2424. // Grab the resource categories.
  2425. $resource_categories = $this->getXenAPI()->getResourceCategories();
  2426.  
  2427. // Send the response.
  2428. $this->sendResponse(array('count' => count($resource_categories), 'categories' => $resource_categories));
  2429. case 'getstats':
  2430. /**
  2431. * Returns a summary of stats.
  2432. *
  2433. * NOTE: "include_deleted" will count the deleted posts/threads as well
  2434. *
  2435. * EXAMPLE:
  2436. * - api.php?action=getStats
  2437. * - api.php?action=getStats&include_deleted
  2438. */
  2439. $latest_user = $this->xenAPI->getLatestUser();
  2440. if (!$this->hasRequest('include_deleted')) {
  2441. $include_deleted = TRUE;
  2442. } else {
  2443. $include_deleted = FALSE;
  2444. }
  2445. $this->sendResponse(array(
  2446. 'threads' => $this->xenAPI->getStatsItem('threads', $include_deleted),
  2447. 'posts' => $this->xenAPI->getStatsItem('posts', $include_deleted),
  2448. 'conversations' => $this->xenAPI->getStatsItem('conversations', $include_deleted),
  2449. 'conversations_messages' => $this->xenAPI->getStatsItem('conversations_messages', $include_deleted),
  2450. 'members' => $this->xenAPI->getStatsItem('users', $include_deleted),
  2451. 'latest_member' => array('user_id' => $latest_user->getID(), 'username' => $latest_user->getUsername()),
  2452. 'registrations_today' => $this->xenAPI->getStatsItem('registrations_today', $include_deleted),
  2453. 'threads_today' => $this->xenAPI->getStatsItem('threads_today', $include_deleted),
  2454. 'posts_today' => $this->xenAPI->getStatsItem('posts_today', $include_deleted),
  2455. 'users_online' => $this->xenAPI->getUsersOnlineCount($this->getUser())
  2456. ));
  2457. case 'getthread':
  2458. /**
  2459. * Returns the thread information depending on the 'value' argument.
  2460. *
  2461. * NOTE: Only thread ID's can be used for the 'value' parameter.
  2462. * Thread ID's can be found by using the 'getThreads' action.
  2463. *
  2464. * The user needs permission to see the thread if the request is
  2465. * using a user hash and not an API key.
  2466. *
  2467. * EXAMPLE:
  2468. * - api.php?action=getThread&value=820&hash=USERNAME:HASH
  2469. * - api.php?action=getThread&value=820&hash=API_KEY
  2470. */
  2471. $fetchOptions = array();
  2472. if (!$this->hasRequest('value')) {
  2473. // The 'value' argument has not been set, throw error.
  2474. $this->throwError(3, 'value');
  2475. } else if (!$this->getRequest('value')) {
  2476. // Throw error if the 'value' argument is set but empty.
  2477. $this->throwError(1, 'value');
  2478. }
  2479. $string = $this->getRequest('value');
  2480.  
  2481. // Check if request has grab_content.
  2482. if ($this->hasRequest('grab_content')) {
  2483. $fetchOptions['grab_content'] = TRUE;
  2484.  
  2485. // Check if request has content_limit.
  2486. if ($this->hasRequest('content_limit')) {
  2487. if (!$this->getRequest('content_limit') && (is_numeric($this->getRequest('content_limit')) && $this->getRequest('content_limit') != 0)) {
  2488. // Throw error if the 'content_limit' argument is set but empty.
  2489. $this->throwError(1, 'content_limit');
  2490. } else if (!is_numeric($this->getRequest('content_limit'))) {
  2491. // Throw error if the 'content_limit' argument is set but not a number.
  2492. $this->throwError(21, 'content_limit');
  2493. }
  2494. $fetchOptions['content_limit'] = $this->getRequest('content_limit');
  2495. }
  2496. }
  2497.  
  2498. // Try to grab the thread from XenForo.
  2499. $thread = $this->getXenAPI()->getThread($string, $fetchOptions, $this->getUser());
  2500. if ($thread === NULL) {
  2501. // Could not find the thread, throw error.
  2502. $this->throwError(19, 'thread', $string);
  2503. } else if (!$this->hasAPIKey() && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) {
  2504. if (isset($this->grab_as)) {
  2505. // Thread was found but the 'grab_as' user is not permitted to view the thread.
  2506. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread');
  2507. } else {
  2508. // Thread was found but the user is not permitted to view the thread.
  2509. $this->throwError(20, 'You do', 'this thread');
  2510. }
  2511. } else if ($this->hasAPIKey() && isset($this->grab_as) && !$this->getXenAPI()->canViewThread($this->getUser(), $thread)) {
  2512. // Thread was found but the 'grab_as' user is not permitted to view the thread.
  2513. $this->throwError(20, $this->getUser()->getUsername() . ' does', 'this thread');
  2514. } else {
  2515. // Thread was found, and the request was permitted.
  2516. $this->sendResponse($thread);
  2517. }
  2518. case 'getthreads':
  2519. /**
  2520. * Returns a list of threads.
  2521. *
  2522. * NOTE: Only usernames and user ID's can be used for the 'author' parameter.
  2523. *
  2524. * EXAMPLES:
  2525. * - api.php?action=getThreads&hash=USERNAME:HASH
  2526. * - api.php?action=getThreads&hash=API_KEY
  2527. * - api.php?action=getThreads&author=Contex&hash=USERNAME:HASH
  2528. * - api.php?action=getThreads&author=1&hash=API_KEY
  2529. */
  2530. // Init variables.
  2531. $conditions = array();
  2532. $this->setLimit(10);
  2533. $fetch_options = array('limit' => $this->limit);
  2534.  
  2535. // Check if request has discussion_state.
  2536. if ($this->hasRequest('discussion_state')) {
  2537. if (!$this->getRequest('discussion_state')) {
  2538. // Throw error if the 'discussion_state ' argument is set but empty.
  2539. $this->throwError(1, 'discussion_state');
  2540. }
  2541. // Add the discussion state to the query conditions.
  2542. $conditions['discussion_state'] = $this->getRequest('discussion_state');
  2543. }
  2544.  
  2545. // Check if request has author.
  2546. if ($this->hasRequest('author')) {
  2547. if (!$this->getRequest('author')) {
  2548. // Throw error if the 'author' argument is set but empty.
  2549. $this->throwError(1, 'author');
  2550. }
  2551. // Grab the user object of the author.
  2552. $user = $this->xenAPI->getUser($this->getRequest('author'));
  2553. if (!$user->isRegistered()) {
  2554. // Throw error if the 'author' user is not registered.
  2555. $this->throwError(4, 'user', $this->getRequest('author'));
  2556. }
  2557. // Add the user ID to the query conditions.
  2558. $conditions['user_id'] = $user->getID();
  2559. unset($user);
  2560. }
  2561.  
  2562. // Check if request has author.
  2563. if ($this->hasRequest('node_id')) {
  2564. if (!$this->getRequest('node_id') && (is_numeric($this->getRequest('node_id')) && $this->getRequest('node_id') != 0)) {
  2565. // Throw error if the 'node_id' argument is set but empty.
  2566. $this->throwError(1, 'node_id');
  2567. } else if (!is_numeric($this->getRequest('node_id'))) {
  2568. // Throw error if the 'limit' argument is set but not a number.
  2569. $this->throwError(21, 'node_id');
  2570. }
  2571. if (!$this->xenAPI->getNode($this->getRequest('node_id'))) {
  2572. // Could not find any nodes, throw error.
  2573. $this->throwError(4, 'node', $this->getRequest('node_id'));
  2574. }
  2575. // Add the node ID to the query conditions.
  2576. $conditions['node_id'] = $this->getRequest('node_id');
  2577. }
  2578.  
  2579. // Check if request has grab_content.
  2580. if ($this->hasRequest('grab_content')) {
  2581. $fetch_options['grab_content'] = TRUE;
  2582.  
  2583. // Check if request has content_limit.
  2584. if ($this->hasRequest('content_limit')) {
  2585. if (!$this->getRequest('content_limit') && (is_numeric($this->getRequest('content_limit')) && $this->getRequest('content_limit') != 0)) {
  2586. // Throw error if the 'content_limit' argument is set but empty.
  2587. $this->throwError(1, 'content_limit');
  2588. } else if (!is_numeric($this->getRequest('content_limit'))) {
  2589. // Throw error if the 'content_limit' argument is set but not a number.
  2590. $this->throwError(21, 'content_limit');
  2591. }
  2592. $fetch_options['content_limit'] = $this->getRequest('content_limit');
  2593. }
  2594. }
  2595.  
  2596.  
  2597. // Check if the order by argument is set.
  2598. $order_by_field = $this->checkOrderBy(array('title', 'post_date', 'view_count', 'reply_count', 'first_post_likes', 'last_post_date'));
  2599.  
  2600. // Add the order by options to the fetch options.
  2601. if ($this->hasRequest('order_by')) {
  2602. $fetch_options['order'] = $order_by_field;
  2603. $fetch_options['orderDirection'] = $this->order;
  2604. }
  2605.  
  2606. // Get the threads.
  2607. $threads = $this->getXenAPI()->getThreads($conditions, $fetch_options, $this->getUser());
  2608.  
  2609. // Send the response.
  2610. $this->sendResponse(array('count' => count($threads), 'threads' => $threads));
  2611. case 'getuser':
  2612. /**
  2613. * Grabs and returns an user object.
  2614. *
  2615. * EXAMPLES:
  2616. * - api.php?action=getUser&hash=USERNAME:HASH
  2617. * - api.php?action=getUser&value=USERNAME&hash=USERNAME:HASH
  2618. * - api.php?action=getUser&value=USERNAME&hash=API_KEY
  2619. */
  2620.  
  2621. // Send the response.
  2622. $this->sendResponse($this->stripUserData($user));
  2623. case 'getusers':
  2624. /**
  2625. * Searches through the usernames depending on the input.
  2626. *
  2627. * NOTE: Asterisk (*) can be used as a wildcard.
  2628. *
  2629. * EXAMPLE:
  2630. * - api.php?action=getUsers&value=Contex
  2631. * - api.php?action=getUsers&value=Cont*
  2632. * - api.php?action=getUsers&value=C*
  2633. */
  2634.  
  2635. if ($this->hasRequest('value') && strpos($this->getRequest('value', ',')) !== false) {
  2636. $userIds = explode(',', $this->getRequest('value'));
  2637. $results = [];
  2638. foreach ($userIds as $userId) {
  2639. $user = $this->getXenAPI()->getUser($userId);
  2640. if (!$user->isRegistered()) {
  2641. // Requested user was not registered, throw error.
  2642. $this->throwError(4, 'user', $userId);
  2643. }
  2644. $results[] = $this->stripUserData($user); # TODO: only return user_id & username?
  2645. }
  2646. } else if ($this->hasAPIKey() && $this->hasRequest('value') && !filter_var($this->getRequest('value'), FILTER_VALIDATE_IP) === false) {
  2647. $ip = $this->getRequest('value');
  2648. $users = $this->getXenAPI()->getUsersByIp($ip);
  2649. $results = [];
  2650. foreach ($users as $user) {
  2651. $results[] = [
  2652. 'user_id' => $user['user_id'],
  2653. 'username' => $user['username'],
  2654. 'log_date' => $user['log_date']
  2655. ];
  2656. }
  2657. } else {
  2658. if ($this->hasRequest('value')) {
  2659. // Request has value.
  2660. if (!$this->getRequest('value')) {
  2661. // Throw error if the 'value' argument is set but empty.
  2662. $this->throwError(1, 'value');
  2663. }
  2664. // Replace the wildcard with '%' for the SQL query.
  2665. $string = str_replace('*', '%', $this->getRequest('value'));
  2666. } else if (!$this->hasRequest('order_by')) {
  2667. // Nor the 'value' argument or the 'order_by' argument has been set, throw error.
  2668. $this->throwError(3, 'value');
  2669. }
  2670.  
  2671. // Check if the order by argument is set.
  2672. $order_by_field = $this->checkOrderBy(array('user_id', 'message_count', 'conversations_unread', 'register_date', 'last_activity', 'trophy_points', 'alerts_unread', 'like_count'));
  2673.  
  2674. // Perform the SQL query and grab all the usernames and user id's.
  2675. // Perform the SQL query and grab all the usernames and user id's.
  2676. $results = $this->xenAPI->getDatabase()->fetchAll("SELECT `user_id`, `username`"
  2677. . ($this->hasRequest('order_by') ? ", " . $this->xenAPI->getDatabase()->quote($order_by_field) : '')
  2678. . " FROM `xf_user`" . ($this->hasRequest('value') ? " WHERE `username` LIKE " . $this->xenAPI->getDatabase()->quote($string) : '')
  2679. . ($this->hasRequest('order_by') ? " ORDER BY `$order_by_field` " . $this->order : '')
  2680. . (($this->limit > 0) ? ' LIMIT ' . $this->xenAPI->getDatabase()->quote($this->limit) : ''));
  2681. }
  2682.  
  2683. // Send the response.
  2684. $this->sendResponse($results);
  2685. case 'getuserupgrade':
  2686. /**
  2687. * TODO
  2688. *
  2689. * EXAMPLES:
  2690. */
  2691. if (!$this->hasRequest('id')) {
  2692. // The 'id' argument has not been set, throw error.
  2693. $this->throwError(3, 'id');
  2694. } else if (!$this->getRequest('id')) {
  2695. // Throw error if the 'id' argument is set but empty.
  2696. $this->throwError(1, 'id');
  2697. }
  2698.  
  2699. $user_upgrade = $this->getXenAPI()->getUserUpgrade($this->getRequest('id'));
  2700.  
  2701. if (!$user_upgrade) {
  2702. $this->throwError(4, 'user upgrade', $this->getRequest('id'));
  2703. }
  2704.  
  2705. // Send the response.
  2706. $this->sendResponse($user_upgrade);
  2707. case 'getuserupgrades':
  2708. /**
  2709. * TODO
  2710. *
  2711. * EXAMPLES:
  2712. */
  2713. $user = NULL;
  2714.  
  2715. if ($this->hasRequest('user')) {
  2716. if (!$this->getRequest('user')) {
  2717. // Throw error if the 'user' argument is set but empty.
  2718. $this->throwError(1, 'user');
  2719. }
  2720. $user = $this->getXenAPI()->getUser($this->getRequest('user'));
  2721. if (!$user->isRegistered()) {
  2722. // Requested user was not registered, throw error.
  2723. $this->throwError(4, 'user', $this->getRequest('user'));
  2724. }
  2725. }
  2726.  
  2727. $user_upgrades = $this->getXenAPI()->getUserUpgrades($user);
  2728.  
  2729. if (!$user_upgrades && $this->hasRequest('user')) {
  2730. $this->throwError(4, 'user upgrades', $this->getRequest('user'));
  2731. }
  2732.  
  2733. // Send the response.
  2734. $this->sendResponse($user_upgrades);
  2735. case 'downgradeuser':
  2736. if (!$this->hasRequest('user')) {
  2737. // The 'user' argument has not been set, throw error.
  2738. $this->throwError(3, 'user');
  2739. } else if (!$this->getRequest('user')) {
  2740. // Throw error if the 'user' argument is set but empty.
  2741. $this->throwError(1, 'user');
  2742. }
  2743.  
  2744. $user = $this->getXenAPI()->getUser($this->getRequest('user'));
  2745. if (!$user->isRegistered()) {
  2746. // Requested user was not registered, throw error.
  2747. $this->throwError(4, 'user', $this->getRequest('user'));
  2748. }
  2749.  
  2750. if (!$this->hasRequest('upgrade_id')) {
  2751. // The 'upgrade_id' argument has not been set, throw error.
  2752. $this->throwError(3, 'upgrade_id');
  2753. } else if (!$this->getRequest('upgrade_id')) {
  2754. // Throw error if the 'upgrade_id' argument is set but empty.
  2755. $this->throwError(1, 'upgrade_id');
  2756. }
  2757.  
  2758. $user_upgrades = $this->getXenAPI()->getUserUpgrades($user);
  2759.  
  2760. if (!$user_upgrades && $this->hasRequest('user')) {
  2761. $this->throwError(4, 'user upgrades', $this->getRequest('user'));
  2762. }
  2763.  
  2764. $user_upgrade_object = NULL;
  2765. foreach ($user_upgrades as $user_upgrade) {
  2766. if ($user_upgrade['user_upgrade_id'] == $this->getRequest('upgrade_id')) {
  2767. $user_upgrade_object = $user_upgrade;
  2768. }
  2769. }
  2770.  
  2771. if ($user_upgrade_object === NULL) {
  2772. $this->throwError(4, 'user upgrade', $this->getRequest('upgrade_id'));
  2773. }
  2774.  
  2775. $record = $this->getXenAPI()->getUserUpgradeRecord($user_upgrade_object['user_upgrade_record_id']);
  2776.  
  2777. $this->getXenAPI()->downgradeUserUpgrade($record);
  2778.  
  2779. // Recheck upgrades to see if the user was downgraded.
  2780. $user_upgrades = $this->getXenAPI()->getUserUpgrades($user);
  2781.  
  2782. $user_upgrade_object = NULL;
  2783. foreach ($user_upgrades as $user_upgrade) {
  2784. if ($user_upgrade['user_upgrade_id'] == $this->getRequest('upgrade_id')) {
  2785. $user_upgrade_object = $user_upgrade;
  2786. }
  2787. }
  2788.  
  2789. if ($user_upgrade_object === NULL) {
  2790. $this->sendResponse(array('success' => TRUE));
  2791. } else {
  2792. $this->sendResponse(array('success' => FALSE));
  2793. }
  2794. case 'upgradeuser':
  2795. if (!$this->hasRequest('user')) {
  2796. // The 'user' argument has not been set, throw error.
  2797. $this->throwError(3, 'user');
  2798. } else if (!$this->getRequest('user')) {
  2799. // Throw error if the 'user' argument is set but empty.
  2800. $this->throwError(1, 'user');
  2801. }
  2802.  
  2803. $user = $this->getXenAPI()->getUser($this->getRequest('user'));
  2804. if (!$user->isRegistered()) {
  2805. // Requested user was not registered, throw error.
  2806. $this->throwError(4, 'user', $this->getRequest('user'));
  2807. }
  2808.  
  2809. if (!$this->hasRequest('id')) {
  2810. // The 'id' argument has not been set, throw error.
  2811. $this->throwError(3, 'id');
  2812. } else if (!$this->getRequest('id')) {
  2813. // Throw error if the 'id' argument is set but empty.
  2814. $this->throwError(1, 'id');
  2815. }
  2816.  
  2817. $upgrade = $this->getXenAPI()->getUserUpgrade($this->getRequest('id'));
  2818.  
  2819. if (!$upgrade) {
  2820. $this->throwError(4, 'user upgrade', $this->getRequest('id'));
  2821. }
  2822.  
  2823. $end_date = NULL;
  2824. if ($this->hasRequest('end_date')) {
  2825. // Request has end_date.
  2826. if (!$this->getRequest('end_date')) {
  2827. // Throw error if the 'end_date' argument is set but empty.
  2828. $this->throwError(1, 'end_date');
  2829. }
  2830. // Set the language id of the registration.
  2831. $end_date = $this->getRequest('end_date');
  2832. if (!(((string) (int) $this->getRequest('end_date') === $this->getRequest('end_date'))
  2833. && ($this->getRequest('end_date') <= PHP_INT_MAX)
  2834. && ($this->getRequest('end_date') >= ~PHP_INT_MAX))) {
  2835. $this->throwError(6, $this->getRequest('end_date'), 'unix timestamp');
  2836. }
  2837. }
  2838.  
  2839. $record_id = $this->getXenAPI()->upgradeUser($user, $upgrade, TRUE, $end_date);
  2840. $record = $this->getXenAPI()->getUserUpgradeRecord($record_id);
  2841. $return = array();
  2842. if (is_int($record_id)) {
  2843. $return['result'] = 'exists';
  2844. } else {
  2845. $return['result'] = 'new';
  2846. }
  2847. $return['record'] = $record;
  2848. $this->sendResponse($return);
  2849. case 'login':
  2850. /**
  2851. * Logins the user.
  2852. *
  2853. * EXAMPLE:
  2854. * - api.php?action=login&username=USERNAME&password=PASSWORD
  2855. */
  2856. if (!$this->hasRequest('username')) {
  2857. // The 'username' argument has not been set, throw error.
  2858. $this->throwError(3, 'username');
  2859. } else if (!$this->getRequest('username')) {
  2860. // Throw error if the 'username' argument is set but empty.
  2861. $this->throwError(1, 'username');
  2862. } else if (!$this->hasRequest('password')) {
  2863. // The 'password' argument has not been set, throw error.
  2864. $this->throwError(3, 'password');
  2865. } else if (!$this->getRequest('password')) {
  2866. // Throw error if the 'password' argument is set but empty.
  2867. $this->throwError(1, 'password');
  2868. } else if (!$this->hasRequest('ip_address')) {
  2869. // The 'ip_address' argument has not been set, throw error.
  2870. $this->throwError(3, 'ip_address');
  2871. } else if (!$this->getRequest('ip_address')) {
  2872. // Throw error if the 'ip_address' argument is set but empty.
  2873. $this->throwError(1, 'ip_address');
  2874. }
  2875.  
  2876. // Get the user object.
  2877. $user = $this->xenAPI->getUser($this->getRequest('username'));
  2878. if (!$user->isRegistered()) {
  2879. // Requested user was not registered, throw error.
  2880. $this->throwError(4, 'user', $this->getRequest('username'));
  2881. } else {
  2882. // Requested user was registered, check authentication.
  2883. if ($user->validateAuthentication($this->getRequest('password'))) {
  2884. // Authentication was valid, grab the user's authentication record.
  2885. $record = $user->getAuthenticationRecord();
  2886. $ddata = unserialize($record['data']);
  2887.  
  2888. // Start session and saves the session to the database
  2889. $session = $this->getXenAPI()->login(
  2890. $user->getID(),
  2891. $user->getUsername(),
  2892. XenForo_Helper_Ip::convertIpStringToBinary($this->getRequest('ip_address'))
  2893. );
  2894.  
  2895. $cookie_domain = XenForo_Application::get('config')->cookie->domain;
  2896.  
  2897. // Check if cookie domain is empty, grab board url and use its domain if it is empty
  2898. if (empty($cookie_domain)) {
  2899. $url = XenForo_Application::getOptions()->boardUrl;
  2900. $parse = parse_url($url);
  2901. $cookie_domain = $parse['host'];
  2902. }
  2903.  
  2904. // Return data required for creating cookie
  2905. $this->sendResponse(array(
  2906. 'hash' => base64_encode($ddata['hash']),
  2907. 'cookie_name' => XenForo_Application::get('config')->cookie->prefix . 'session',
  2908. 'cookie_id' => $session->getSessionId(),
  2909. 'cookie_path' => XenForo_Application::get('config')->cookie->path,
  2910. 'cookie_domain' => $cookie_domain,
  2911. 'cookie_expiration' => 0,
  2912. 'cookie_secure' => XenForo_Application::$secure
  2913. ));
  2914. } else {
  2915. // The username or password was wrong, throw error.
  2916. $this->throwError(5, 'Invalid username or password!');
  2917. }
  2918. }
  2919. case 'logout':
  2920. /**
  2921. * Logout from Xenforo
  2922. * Based on : https://github.com/intelliants/subrion-plugin-xenforo/blob/master/includes/classes/ia.common.xenforo.php#L154-L172
  2923. */
  2924.  
  2925. XenForo_Session::startPublicSession();
  2926.  
  2927. if (XenForo_Visitor::getInstance()->get('is_admin'))
  2928. {
  2929. $getAdminSession = new XenForo_Session(['admin' => true]);
  2930. $getAdminSession->start();
  2931. if ($getAdminSession->get('user_id') == XenForo_Visitor::getUserId())
  2932. {
  2933. $getAdminSession->delete();
  2934. }
  2935. }
  2936.  
  2937. XenForo_Model::create('XenForo_Model_Session')->processLastActivityUpdateForLogOut(XenForo_Visitor::getUserId());
  2938. XenForo_Application::get('session')->delete();
  2939. XenForo_Helper_Cookie::deleteAllCookies(
  2940. ['session'],
  2941. ['user' => ['httpOnly' => false]]
  2942. );
  2943.  
  2944. XenForo_Visitor::setup(0);
  2945.  
  2946. $this->sendResponse(['success' => 'xf_session has been removed, user has been logged out !']);
  2947. case 'register':
  2948. /**
  2949. * Registers a user.
  2950. */
  2951. // Init user array.
  2952. $user_data = array();
  2953.  
  2954. // Array of required parameters.
  2955. $required_parameters = array('username', 'password', 'email');
  2956.  
  2957. // Array of additional parameters.
  2958. $additional_parameters = array('timezone', 'gender', 'dob_day', 'dob_month', 'dob_year', 'ip_address');
  2959.  
  2960. foreach ($required_parameters as $required_parameter) {
  2961. // Check if the required parameter is set and not empty.
  2962. $this->checkRequestParameter($required_parameter);
  2963.  
  2964. // Set the request value.
  2965. $user_data[$required_parameter] = $this->getRequest($required_parameter);
  2966. }
  2967.  
  2968. foreach ($additional_parameters as $additional_parameter) {
  2969. // Check if the additional parameter is set and not empty.
  2970. $this->checkRequestParameter($additional_parameter, FALSE);
  2971.  
  2972. if ($this->getRequest($additional_parameter)) {
  2973. // Set the request value.
  2974. $user_data[$additional_parameter] = $this->getRequest($additional_parameter);
  2975. }
  2976. }
  2977.  
  2978. if ($this->hasRequest('group')) {
  2979. // Request has value.
  2980. if (!$this->getRequest('group')) {
  2981. // Throw error if the 'group' argument is set but empty.
  2982. $this->throwError(1, 'group');
  2983. }
  2984. $group = $this->getXenAPI()->getGroup($this->getRequest('group'));
  2985. if (!$group) {
  2986. $registration_error = array(
  2987. 'error_id' => 2,
  2988. 'error_key' => 'group_not_found',
  2989. 'error_field' => 'group',
  2990. 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest('group') . '"'
  2991. );
  2992. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  2993. }
  2994. // Set the group id of the registration.
  2995. $user_data['group_id'] = $group['user_group_id'];
  2996. }
  2997.  
  2998. if ($this->hasRequest('custom_fields')) {
  2999. // Request has value.
  3000. if (!$this->getRequest('custom_fields')) {
  3001. // Throw error if the 'custom_fields' argument is set but empty.
  3002. $this->throwError(1, 'custom_fields');
  3003. }
  3004. $custom_fields = $this->getCustomArray($this->getRequest('custom_fields'));
  3005.  
  3006. // Check if we found any valid custom fields, throw error if not.
  3007. if (count($custom_fields) == 0) {
  3008. // The custom fields array was empty, throw error.
  3009. $registration_error = array(
  3010. 'error_id' => 5,
  3011. 'error_key' => 'invalid_custom_fields',
  3012. 'error_field' => 'custom_fields',
  3013. 'error_phrase' => 'The custom fields values were invalid, valid values are: '
  3014. . 'custom_fields=custom_field1=custom_value1,custom_field2=custom_value2 '
  3015. . 'but got: "' . $this->getRequest('custom_fields') . '" instead'
  3016. );
  3017. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  3018. }
  3019. $user_data['custom_fields'] = $custom_fields;
  3020. }
  3021.  
  3022. // Check if add groups is set.
  3023. if ($this->hasRequest('add_groups')) {
  3024. // Request has value.
  3025. if (!$this->getRequest('add_groups')) {
  3026. // Throw error if the 'add_groups' argument is set but empty.
  3027. $this->throwError(1, 'add_groups');
  3028. }
  3029. // Initialize the array.
  3030. $user_data['add_groups'] = array();
  3031.  
  3032. // Check if value is an array.
  3033. if (strpos($this->getRequest('add_groups'), ',') !== FALSE) {
  3034. // Value is an array, explode it.
  3035. $groups = explode(',', $this->getRequest('add_groups'));
  3036.  
  3037. // Loop through the group values.
  3038. foreach ($groups as $group_value) {
  3039. // Grab the group from the group value.
  3040. $group = $this->getXenAPI()->getGroup($group_value);
  3041.  
  3042. // Check if group was found.
  3043. if (!$group) {
  3044. // Group was not found, throw error.
  3045. $registration_error = array(
  3046. 'error_id' => 2,
  3047. 'error_key' => 'group_not_found',
  3048. 'error_field' => 'add_groups',
  3049. 'error_phrase' => 'Could not find group with parameter "' . $group_value . '" in array "' . $this->getRequest('add_group') . '"'
  3050. );
  3051. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  3052. }
  3053. // Add the group_id to the the add_group array.
  3054. $user_data['add_groups'][] = $group['user_group_id'];
  3055. }
  3056. } else {
  3057. // Grab the group from the group value.
  3058. $group = $this->getXenAPI()->getGroup($this->getRequest('add_groups'));
  3059.  
  3060. // Check if group was found.
  3061. if (!$group) {
  3062. // Group was not found, throw error.
  3063. $registration_error = array(
  3064. 'error_id' => 2,
  3065. 'error_key' => 'group_not_found',
  3066. 'error_field' => 'add_groups',
  3067. 'error_phrase' => 'Could not find group with parameter "' . $this->getRequest('add_groups') . '"'
  3068. );
  3069. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  3070. }
  3071. // Add the group_id to the the add_groups array.
  3072. $user_data['add_groups'][] = $group['user_group_id'];
  3073. }
  3074. }
  3075.  
  3076. if ($this->hasRequest('user_state')) {
  3077. // Request has user_state.
  3078. if (!$this->getRequest('user_state')) {
  3079. // Throw error if the 'user_state' argument is set but empty.
  3080. $this->throwError(1, 'user_state');
  3081. }
  3082. // Set the user state of the registration.
  3083. $user_data['user_state'] = $this->getRequest('user_state');
  3084. }
  3085.  
  3086. if ($this->hasRequest('language_id')) {
  3087. // Request has language_id.
  3088. if (!$this->getRequest('language_id')) {
  3089. // Throw error if the 'language_id' argument is set but empty.
  3090. $this->throwError(1, 'language_id');
  3091. }
  3092. // Set the language id of the registration.
  3093. $user_data['language_id'] = $this->getRequest('language_id');
  3094. }
  3095.  
  3096. $registration_results = $this->getXenAPI()->register($user_data);
  3097.  
  3098. if (!empty($registration_results['error'])) {
  3099. // The registration failed, process errors.
  3100. if (is_array($registration_results['errors'])) {
  3101. // The error message was an array, loop through the messages.
  3102. $error_keys = array();
  3103. foreach ($registration_results['errors'] as $error_field => $error) {
  3104. if (!($error instanceof XenForo_Phrase)) {
  3105. $registration_error = array(
  3106. 'error_id' => 1,
  3107. 'error_key' => 'field_not_recognised',
  3108. 'error_field' => $error_field,
  3109. 'error_phrase' => $error
  3110. );
  3111. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  3112.  
  3113. }
  3114.  
  3115. // Let's init the registration error array.
  3116. $registration_error = array(
  3117. 'error_id' => $this->getUserErrorID($error->getPhraseName()),
  3118. 'error_key' => $error->getPhraseName(),
  3119. 'error_field' => $error_field,
  3120. 'error_phrase' => $error->render()
  3121. );
  3122.  
  3123. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  3124. }
  3125. } else {
  3126. $registration_error = array(
  3127. 'error_id' => $registration_results['error'],
  3128. 'error_key' => 'general_user_registration_error',
  3129. 'error_phrase' => $registration_results['errors']
  3130. );
  3131.  
  3132. $this->throwError(self::USER_ERROR, $registration_error, 'registering a new user');
  3133. }
  3134. } else {
  3135. // Registration was successful, return results.
  3136. $this->sendResponse($registration_results);
  3137. }
  3138. case 'search':
  3139. if (!$this->hasRequest('value')) {
  3140. // The 'value' argument has not been set, throw error.
  3141. $this->throwError(3, 'value');
  3142. } else if (!$this->getRequest('value')) {
  3143. // Throw error if the 'value' argument is set but empty.
  3144. $this->throwError(1, 'value');
  3145. }
  3146. $order = 'asc';
  3147. $type = NULL;
  3148. if ($this->hasRequest('order')) {
  3149. // Request has order.
  3150. if (!$this->getRequest('order')) {
  3151. // Throw error if the 'order' argument is set but empty.
  3152. $this->throwError(1, 'order');
  3153. }
  3154. // Set the language id of the registration.
  3155. $order = $this->getRequest('order');
  3156. }
  3157. if ($this->hasRequest('type')) {
  3158. // Request has type.
  3159. if (!$this->getRequest('type')) {
  3160. // Throw error if the 'type' argument is set but empty.
  3161. $this->throwError(1, 'type');
  3162. }
  3163. // Set the language id of the registration.
  3164. $type = $this->getRequest('type');
  3165. }
  3166. $this->sendResponse($this->getXenAPI()->search($this->getRequest('value'), $order, $type));
  3167. default:
  3168. // Action was supported but has not yet been added to the switch statement, throw error.
  3169. $this->throwError(11, $this->getAction());
  3170. }
  3171. $this->throwError(7, 'executing action', $this->getAction());
  3172. }
  3173.  
  3174. /**
  3175. * Send the response array in JSON.
  3176. */
  3177. public function sendResponse($data) {
  3178. if ($this->hasRequest('debug')) {
  3179. $data['debug'] = $this->getXenAPI()->getDebugData();
  3180. }
  3181. header('Content-type: application/json');
  3182. die(json_encode($data));
  3183. }
  3184. }
  3185.  
  3186. /**
  3187. * The XenAPI class provides all the functions and variables
  3188. * that are needed to use XenForo's classes and functions.
  3189. */
  3190. class XenAPI {
  3191. private $xfDir, $models;
  3192.  
  3193. /**
  3194. * Default consturctor, instalizes XenForo classes and models.
  3195. */
  3196. public function __construct() {
  3197. $this->xfDir = dirname(__FILE__);
  3198. require_once($this->xfDir . '/library/XenForo/Autoloader.php');
  3199. XenForo_Autoloader::getInstance()->setupAutoloader($this->xfDir. '/library');
  3200. XenForo_Application::initialize($this->xfDir . '/library', $this->xfDir);
  3201. XenForo_Application::set('page_start_time', microtime(TRUE));
  3202.  
  3203. $deps = new XenForo_Dependencies_Public();
  3204. $deps->preLoadData();
  3205.  
  3206. // Disable XenForo's PHP error handler.
  3207. XenForo_Application::disablePhpErrorHandler();
  3208.  
  3209. // Enable error logging for PHP.
  3210. error_reporting(E_ALL & ~E_NOTICE);
  3211. $this->models = new Models();
  3212. // TODO: Don't create models on init, only create them if they're being used (see Models::checkModel($model_name, $model)).
  3213. $this->getModels()->setUserModel(XenForo_Model::create('XenForo_Model_User'));
  3214. $this->getModels()->setAlertModel(XenForo_Model::create('XenForo_Model_Alert'));
  3215. $this->getModels()->setUserFieldModel(XenForo_Model::create('XenForo_Model_UserField'));
  3216. $this->getModels()->setAvatarModel(XenForo_Model::create('XenForo_Model_Avatar'));
  3217. $this->getModels()->setModel('addon', XenForo_Model::create('XenForo_Model_AddOn'));
  3218. $this->getModels()->setModel('database', XenForo_Application::get('db'));
  3219. if ($this->hasAddon('XenResource') && $this->hasModel('XenResource_Model_Resource')) {
  3220. $this->getModels()->setModel('resource', XenForo_Model::create('XenResource_Model_Resource'));
  3221. }
  3222. }
  3223.  
  3224. public function getBoardURL($node, $inner_node) {
  3225. if (XenForo_Application::getOptions()->useFriendlyUrls == '1') {
  3226. return XenForo_Application::getOptions()->boardUrl . '/' . $node . '/' . $inner_node . '/';
  3227. } else {
  3228. return XenForo_Application::getOptions()->boardUrl . '/index.php?' . $node . '/' . $inner_node . '/';
  3229. }
  3230. }
  3231.  
  3232. public function createAlert($alert_user, $cause_user, $alert_data = array()) {
  3233. if ($alert_user == NULL) {
  3234. // An user is required to create a new alert.
  3235. return array('error' => 13, 'errors' => 'User is required to create an alert.');
  3236. } else if ($cause_user == NULL) {
  3237. // A cause user is required to create a new alert.
  3238. return array('error' => 13, 'errors' => 'User is required to create an alert.');
  3239. }
  3240.  
  3241. $this->getModels()->checkModel('alert', XenForo_Model::create('XenForo_Model_Alert'));
  3242.  
  3243. $this->getModels()->getModel('alert')->alertUser(
  3244. $alert_user->getID(),
  3245. $cause_user->getID(),
  3246. $cause_user->getUsername(),
  3247. $alert_data['content_type'],
  3248. $alert_data['content_id'],
  3249. $alert_data['action']
  3250. );
  3251.  
  3252.  
  3253. return $alert_data;
  3254. }
  3255.  
  3256. public function createConversation($user, $conversation_data = array()) {
  3257. if ($user == NULL) {
  3258. // An user is required to create a new conversation.
  3259. return array('error' => 13, 'errors' => 'User is required to create a conversation.');
  3260. }
  3261.  
  3262. $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User'));
  3263. $this->checkUserPermissions($user);
  3264. if (!$this->getModels()->getModel('user')->canStartConversations($null, $user->getData())) {
  3265. // User does not have permission to post in this thread.
  3266. return array('error' => 14, 'errors' => 'The user does not have permissions to create a new conversation.');
  3267. }
  3268.  
  3269. // TODO: Check if user has permissions to start a conversation with the specified recepients.
  3270.  
  3271. $conversation_data['message'] = XenForo_Helper_String::autoLinkBbCode($conversation_data['message']);
  3272.  
  3273. $writer = XenForo_DataWriter::create('XenForo_DataWriter_ConversationMaster');
  3274. $writer->setExtraData(XenForo_DataWriter_ConversationMaster::DATA_ACTION_USER, $user->data);
  3275. $writer->setExtraData(XenForo_DataWriter_ConversationMaster::DATA_MESSAGE, $conversation_data['message']);
  3276. $writer->set('user_id', $user->data['user_id']);
  3277. $writer->set('username', $user->data['username']);
  3278. $writer->set('title', $conversation_data['title']);
  3279. $writer->set('open_invite', $conversation_data['open_invite']);
  3280. $writer->set('conversation_open', $conversation_data['conversation_locked'] ? 0 : 1);
  3281. $writer->addRecipientUserNames(explode(',', $conversation_data['recipients'])); // checks permissions
  3282.  
  3283. $messageDw = $writer->getFirstMessageDw();
  3284. $messageDw->set('message', $conversation_data['message']);
  3285.  
  3286. $writer->preSave();
  3287.  
  3288. if ($writer->hasErrors()) {
  3289. // The post creation failed, return errors.
  3290. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3291. }
  3292.  
  3293. $writer->save();
  3294. $conversation = $writer->getMergedData();
  3295.  
  3296. $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation'));
  3297. $this->getModels()->getModel('conversation')->markConversationAsRead($conversation['conversation_id'], $user->data['user_id'], XenForo_Application::$time);
  3298.  
  3299. return $conversation;
  3300. }
  3301.  
  3302. public function login($user_id, $username, $ip_address) {
  3303. $session = XenForo_Session::startPublicSession();
  3304. $session->set('user_id', $user_id);
  3305. $session->set('username', $username);
  3306. $session->set('ip', XenForo_Helper_Ip::convertIpStringToBinary($ip_address));
  3307. //$session->set('userAgent', $user_agent);
  3308. $session->saveSessionToSource($session->getSessionId(), false);
  3309. return $session;
  3310. }
  3311.  
  3312. public function createConversationReply($user, $conversation_reply_data = array()) {
  3313. if ($user == NULL) {
  3314. // An user is required to create a new conversation.
  3315. return array('error' => 13, 'errors' => 'User is required to create a conversation reply.');
  3316. }
  3317.  
  3318. $conversation = $this->getConversation($conversation_reply_data['conversation_id'], $user);
  3319.  
  3320. $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation'));
  3321. if (!$this->getModels()->getModel('conversation')->canReplyToConversation($conversation, $null, $user->getData())) {
  3322. // User does not have permission to reply to this conversation.
  3323. return array('error' => 14, 'errors' => 'The user does not have permissions to reply to this conversation.');
  3324. }
  3325.  
  3326. $conversation_reply_data['message'] = XenForo_Helper_String::autoLinkBbCode($conversation_reply_data['message']);
  3327.  
  3328. $writer = XenForo_DataWriter::create('XenForo_DataWriter_ConversationMessage');
  3329. $writer->setExtraData(XenForo_DataWriter_ConversationMessage::DATA_MESSAGE_SENDER, $user->getData());
  3330. $writer->set('conversation_id', $conversation['conversation_id']);
  3331. $writer->set('user_id', $user->data['user_id']);
  3332. $writer->set('username', $user->data['username']);
  3333. $writer->set('message', $conversation_reply_data['message']);
  3334. $writer->preSave();
  3335.  
  3336. if ($writer->hasErrors()) {
  3337. // The conversation reply creation failed, return errors.
  3338. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3339. }
  3340.  
  3341. $writer->save();
  3342.  
  3343. $conversation_reply = $writer->getMergedData();
  3344.  
  3345. $this->getModels()->getModel('conversation')->markConversationAsRead($conversation['conversation_id'], $user->data['user_id'], XenForo_Application::$time, 0, FALSE);
  3346.  
  3347. return $conversation_reply;
  3348. }
  3349.  
  3350. public function search($keywords, $order = 'asc', $type = NULL) {
  3351. $keywords = strtolower(XenForo_Helper_String::censorString($keywords, null, ''));
  3352. $this->getModels()->checkModel('search', XenForo_Model::create('XenForo_Model_Search'));
  3353. $searcher = new XenForo_Search_Searcher($this->getModels()->getModel('search'));
  3354. $xenforo_results = $searcher->searchGeneral($keywords, array(), $order);
  3355. $results = array();
  3356. foreach ($xenforo_results as &$result) {
  3357. if ($type !== NULL) {
  3358. if (strtolower($result[0]) != strtolower($type)
  3359. && !(strtolower($result[0]) == 'thread' && strtolower($type) == 'thread_title')) {
  3360. continue;
  3361. }
  3362. }
  3363. $result = array(
  3364. 'type' => $result[0],
  3365. 'data' => $result[1]
  3366. );
  3367. switch ($result['type']) {
  3368. case 'post':
  3369. $result['data'] = $this->getPost($result['data']);
  3370. break;
  3371. case 'thread':
  3372. $result['data'] = $this->getThread($result['data']);
  3373. if ($type !== NULL && strtolower($type) == 'thread_title' && $titleFound = $result['data']['title'] != $keywords) {
  3374. continue 2;
  3375. }
  3376. break;
  3377. case 'resource_update':
  3378. // TODO
  3379. $result['data'] = array('resource_update_id' => $result['data']);
  3380. break;
  3381. }
  3382. $results[] = $result;
  3383. }
  3384. return $results;
  3385. }
  3386.  
  3387. public function createPost($user, $post_data = array()) {
  3388. if ($user == NULL) {
  3389. // An user is required to create a new post.
  3390. return array('error' => 13, 'errors' => 'User is required to create a post.');
  3391. }
  3392.  
  3393. $fetchOptions = array('permissionCombinationId' => $user->data['permission_combination_id']);
  3394.  
  3395. $thread = $this->getThread($post_data['thread_id']);
  3396. $forum = $this->getForum($thread['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  3397. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']);
  3398.  
  3399. if (!$this->canViewThread($user, $thread, $permissions) || !$this->canReplyToThread($user, $thread, $forum, $permissions)) {
  3400. // User does not have permission to post in this thread.
  3401. return array('error' => 14, 'errors' => 'The user does not have permissions to post in this thread.');
  3402. }
  3403.  
  3404. $input['message'] = XenForo_Helper_String::autoLinkBbCode($post_data['message']);
  3405.  
  3406. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post'));
  3407. $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post');
  3408. $writer->set('user_id', $user->data['user_id']);
  3409. $writer->set('username', $user->data['username']);
  3410. $writer->set('message', $input['message']);
  3411. $writer->set('message_state', $this->getModels()->getModel('post')->getPostInsertMessageState($thread, $forum));
  3412. $writer->set('thread_id', $thread['thread_id']);
  3413. $writer->setExtraData(XenForo_DataWriter_DiscussionMessage_Post::DATA_FORUM, $forum);
  3414. $writer->preSave();
  3415.  
  3416. if ($writer->hasErrors()) {
  3417. // The post creation failed, return errors.
  3418. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3419. }
  3420.  
  3421. $writer->save();
  3422. $post = $writer->getMergedData();
  3423.  
  3424. $this->getModels()->checkModel('thread_watch', XenForo_Model::create('XenForo_Model_ThreadWatch'));
  3425.  
  3426. $this->getModels()->getModel('thread_watch')->setThreadWatchStateWithUserDefault($user->data['user_id'], $thread['thread_id'], $user->data['default_watch_state']);
  3427.  
  3428. return $post;
  3429. }
  3430.  
  3431. public function createProfilePost($user, $profile_post_data = array()) {
  3432. if ($user == NULL) {
  3433. // An user is required to create a new post.
  3434. return array('error' => 13, 'errors' => 'User is required to create a profile post.');
  3435. }
  3436.  
  3437. $this->getModels()->checkModel('user_profile', XenForo_Model::create('XenForo_Model_UserProfile'));
  3438.  
  3439. $profile_user = $profile_post_data['user_id'];
  3440. $this->checkUserPermissions($profile_user, array('followingUserId' => $user->data['user_id']));
  3441. $this->checkUserPermissions($user, array('followingUserId' => $profile_user->data['user_id']));
  3442.  
  3443. if (!$this->getModels()->getModel('user_profile')->canPostOnProfile($profile_user->getData(), $null, $user->getData())) {
  3444. return array('error' => 14, 'errors' => 'The user does not have permissions to create a new profile post');
  3445. }
  3446.  
  3447. if ($user->data['user_id'] == $profile_post_data['user_id']) {
  3448. $profile_post_id = $this->getModels()->getModel('user_profile')->updateStatus($profile_post_data['message'], XenForo_Application::$time, $user->getData());
  3449. } else {
  3450. $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost'));
  3451. $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_ProfilePost');
  3452. $writer->set('user_id', $user->data['user_id']);
  3453. $writer->set('username', $user->data['username']);
  3454. $writer->set('message', $profile_post_data['message']);
  3455. $writer->set('profile_user_id', $profile_user->data['user_id']);
  3456. $writer->set('message_state', $this->getModels()->getModel('profile_post')->getProfilePostInsertMessageState($profile_user->getData(), $user->getData()));
  3457. $writer->setExtraData(XenForo_DataWriter_DiscussionMessage_ProfilePost::DATA_PROFILE_USER, $profile_user->getData());
  3458. $writer->preSave();
  3459.  
  3460. if ($writer->hasErrors()) {
  3461. // The profile post creation failed, return errors.
  3462. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3463. }
  3464.  
  3465. $writer->save();
  3466.  
  3467. $profile_post_id = $writer->get('profile_post_id');
  3468. }
  3469.  
  3470. return $this->getProfilePost($profile_post_id);
  3471. }
  3472.  
  3473. public function createProfilePostComment($user, $profile_post_data = array()) {
  3474. if ($user == NULL) {
  3475. // An user is required to create a new post.
  3476. return array('error' => 13, 'errors' => 'User is required to create a profile post comment.');
  3477. }
  3478.  
  3479. $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost'));
  3480.  
  3481. $profile_post = $this->getProfilePost($profile_post_data['profile_post_id']);
  3482.  
  3483. $profile_user = $profile_post_data['profile_user_id'];
  3484. $this->checkUserPermissions($profile_user, array('followingUserId' => $user->data['user_id']));
  3485. $this->checkUserPermissions($user, array('followingUserId' => $profile_user->data['user_id']));
  3486.  
  3487. if (!$this->getModels()->getModel('profile_post')->canCommentOnProfilePost($profile_post, $profile_user->getData(), $null, $user->getData())) {
  3488. return array('error' => 14, 'errors' => 'The user does not have permissions to create a new profile post');
  3489. }
  3490.  
  3491. $writer = XenForo_DataWriter::create('XenForo_DataWriter_ProfilePostComment');
  3492. $writer->setExtraData(XenForo_DataWriter_ProfilePostComment::DATA_PROFILE_USER, $profile_user->getData());
  3493. $writer->setExtraData(XenForo_DataWriter_ProfilePostComment::DATA_PROFILE_POST, $profile_post);
  3494. $writer->bulkSet(array(
  3495. 'profile_post_id' => $profile_post['profile_post_id'],
  3496. 'user_id' => $user->data['user_id'],
  3497. 'username' => $user->data['username'],
  3498. 'message' => $profile_post_data['message']
  3499. ));
  3500.  
  3501. $writer->preSave();
  3502.  
  3503. if ($writer->hasErrors()) {
  3504. // The profile post comment creation failed, return errors.
  3505. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3506. }
  3507.  
  3508. $writer->save();
  3509.  
  3510. return array_values($this->getModels()->getModel('profile_post')->getProfilePostCommentsByProfilePost($profile_post['profile_post_id']));
  3511. }
  3512.  
  3513.  
  3514. public function createThread($user, $thread_data = array()) {
  3515. // TODO: Add support for polls.
  3516. if ($user == NULL) {
  3517. // An user is required to create a new thread.
  3518. return array('error' => 13, 'errors' => 'User is required to create a thread.');
  3519. }
  3520.  
  3521. $forum = $this->getForum($thread_data['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  3522.  
  3523. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']);
  3524.  
  3525. // Check if user can view the forum, if not; it's most likely private or the user has not access to the forum.
  3526. if (!$this->canViewNode($user, $forum, $permissions) || !$this->canPostThreadInForum($user, $forum, $permissions)) {
  3527. // User does not have permission to post in this thread.
  3528. return array('error' => 14, 'errors' => 'The user does not have permissions to create a new thread in this forum.');
  3529. }
  3530.  
  3531. $input['title'] = $thread_data['title'];
  3532.  
  3533. $input['message'] = XenForo_Helper_String::autoLinkBbCode($thread_data['message']);
  3534.  
  3535. if (!empty($thread_data['prefix_id'])) {
  3536. $input['prefix_id'] = $thread_data['prefix_id'];
  3537. }
  3538.  
  3539. $this->getModels()->checkModel('thread_prefix', XenForo_Model::create('XenForo_Model_ThreadPrefix'));
  3540.  
  3541. if (!$this->getModels()->getModel('thread_prefix')->verifyPrefixIsUsable($input['prefix_id'], $thread_data['node_id'])) {
  3542. $input['prefix_id'] = 0; // not usable, just blank it out
  3543. }
  3544.  
  3545. $writer = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
  3546. $writer->bulkSet(array(
  3547. 'user_id' => $user->data['user_id'],
  3548. 'username' => $user->data['username'],
  3549. 'title' => $input['title'],
  3550. 'prefix_id' => $input['prefix_id'],
  3551. 'node_id' => $thread_data['node_id']
  3552. ));
  3553.  
  3554. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post'));
  3555.  
  3556. $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum'));
  3557.  
  3558. // discussion state - moderator permission required
  3559. if (!empty($thread_data['discussion_state']) && $this->getModels()->getModel('forum')->canLockUnlockThreadInForum($forum, $null, $permissions, $user->getData())) {
  3560. $writer->set('discussion_state', $thread_data['discussion_state']);
  3561. } else {
  3562. // discussion state changes instead of first message state
  3563. $writer->set('discussion_state', $this->getModels()->getModel('post')->getPostInsertMessageState(array(), $forum));
  3564. }
  3565.  
  3566. // discussion open state - moderator permission required
  3567. if (!empty($thread_data['discussion_open']) && $this->getModels()->getModel('forum')->canLockUnlockThreadInForum($forum, $null, $permissions, $user->getData())) {
  3568. $writer->set('discussion_open', $thread_data['discussion_open']);
  3569. }
  3570.  
  3571. // discussion sticky state - moderator permission required
  3572. if (!empty($thread_data['sticky']) && $this->getModels()->getModel('forum')->canStickUnstickThreadInForum($forum, $null, $permissions, $user->getData())) {
  3573. $writer->set('sticky', $thread_data['sticky']);
  3574. }
  3575.  
  3576. $postWriter = $writer->getFirstMessageDw();
  3577. $postWriter->set('message', $input['message']);
  3578. $postWriter->setExtraData(XenForo_DataWriter_DiscussionMessage_Post::DATA_FORUM, $forum);
  3579.  
  3580. $writer->setExtraData(XenForo_DataWriter_Discussion_Thread::DATA_FORUM, $forum);
  3581.  
  3582. $writer->preSave();
  3583.  
  3584. if ($writer->hasErrors()) {
  3585. // The thread creation failed, return errors.
  3586. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3587. }
  3588.  
  3589. $writer->save();
  3590.  
  3591. $thread = $writer->getMergedData();
  3592.  
  3593. $this->getModels()->checkModel('thread_watch', XenForo_Model::create('XenForo_Model_ThreadWatch'));
  3594. $this->getModels()->getModel('thread_watch')->setThreadWatchStateWithUserDefault($user->data['user_id'], $thread['thread_id'], $user->data['default_watch_state']);
  3595.  
  3596. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread'));
  3597. $this->getModels()->getModel('thread')->markThreadRead($thread, $forum, XenForo_Application::$time, $user->getData());
  3598.  
  3599. return $thread;
  3600. }
  3601.  
  3602. public function deletePost($post_id, $reason = NULL, $hard_delete = FALSE, $user = NULL) {
  3603. if ($hard_delete) {
  3604. $delete_type = 'hard';
  3605. } else {
  3606. $delete_type = 'soft';
  3607. }
  3608. if ($reason !== NULL) {
  3609. $options = array('reason' => $reason);
  3610. } else {
  3611. $options = array();
  3612. }
  3613.  
  3614. $post = $this->getPost($post_id);
  3615. if ($user !== NULL) {
  3616. $fetchOptions = array('permissionCombinationId' => $user->data['permission_combination_id']);
  3617. $thread = $this->getThread($post['thread_id'], $fetchOptions);
  3618. $forum = $this->getForum($thread['node_id'], $fetchOptions);
  3619. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']);
  3620. } else {
  3621. $thread = $this->getThread($post['thread_id']);
  3622. $forum = $this->getForum($thread['node_id']);
  3623. }
  3624.  
  3625. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post'));
  3626.  
  3627. if ($user !== NULL && (!$this->canViewThread($user, $thread, $permissions) || !$this->getModels()->getModel('post')->canDeletePost($post, $thread, $forum, $delete_type, $null, $permissions, $user->getData()))) {
  3628. // User does not have permission to delete this post.
  3629. return array('error' => 14, 'errors' => 'The user does not have permissions to delete this post.');
  3630. }
  3631.  
  3632. $this->getModels()->getModel('post')->deletePost($post_id, $delete_type, $options, $forum);
  3633.  
  3634. if ($delete_type == 'hard') {
  3635. $post['message_state'] = 'hard_deleted';
  3636. } else {
  3637. $post['message_state'] = 'deleted';
  3638. }
  3639.  
  3640. return $post;
  3641. }
  3642.  
  3643. public function deleteUser($user) {
  3644. if (!$user) {
  3645. return array('error' => 3, 'errors' => 'The user array key was not set.');
  3646. }
  3647. if (!$user->isRegistered()) {
  3648. return array('error' => 4, 'errors' => 'User is not registered.');
  3649. }
  3650. $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User'));
  3651. // Check if user is super admin.
  3652. if ($this->getModels()->getModel('user')->isUserSuperAdmin($user->data)) {
  3653. // User is super admin, we do not allow deleting super admins, return error.
  3654. return array('error' => 6, 'errors' => 'Deleting super admins is disabled.');
  3655. }
  3656.  
  3657. $writer = XenForo_DataWriter::create('XenForo_DataWriter_User', XenForo_DataWriter::ERROR_EXCEPTION);
  3658. $writer->setExistingData($user->data);
  3659. $writer->preDelete();
  3660.  
  3661. if ($writer->hasErrors()) {
  3662. // The delete failed, return errors.
  3663. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3664. }
  3665.  
  3666. $writer->delete();
  3667.  
  3668. return array('success' => TRUE);
  3669. }
  3670.  
  3671. public function editPost($post, $user, $edit_data = array()) {
  3672. unset($post['absolute_url']);
  3673. unset($post['message_html']);
  3674. if (!$user) {
  3675. return array('error' => 3, 'errors' => 'The user array key was not set.');
  3676. }
  3677. if (!$user->isRegistered()) {
  3678. return array('error' => 4, 'errors' => 'User is not registered.');
  3679. }
  3680.  
  3681. $fetchOptions = array('permissionCombinationId' => $user->data['permission_combination_id']);
  3682.  
  3683. $thread = $this->getThread($post['thread_id']);
  3684. $forum = $this->getForum($thread['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  3685. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']);
  3686.  
  3687. if (!$this->canViewThread($user, $thread, $permissions) || !$this->canReplyToThread($user, $thread, $forum, $permissions)) {
  3688. // User does not have permission to post in this thread.
  3689. return array('error' => 14, 'errors' => 'The user does not have permissions to post in this thread.');
  3690. }
  3691.  
  3692. if (array_key_exists('message', $edit_data)) {
  3693. $edit_data['message'] = XenForo_Helper_String::autoLinkBbCode($edit_data['message']);
  3694. }
  3695.  
  3696. // Init the diff array.
  3697. $diff_array = array();
  3698.  
  3699. // Create the data writer object for registrations, and set the defaults.
  3700. $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post');
  3701.  
  3702. // Set the existing data of the user before we submit the data.
  3703. $writer->setExistingData($post['post_id']);
  3704.  
  3705. // Bulkset the edited data.
  3706. $writer->bulkSet($edit_data);
  3707.  
  3708. // Pre save the data.
  3709. $writer->preSave();
  3710.  
  3711. if ($writer->hasErrors()) {
  3712. // The edit failed, return errors.
  3713. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3714. }
  3715.  
  3716. // Save the user to the database.
  3717. $writer->save();
  3718.  
  3719. // Get the user data.
  3720. $post_data = $writer->getMergedData();
  3721.  
  3722. // Check the difference between the before and after data.
  3723. $diff_array = array_merge(array_diff_assoc($post, $post_data), $diff_array);
  3724.  
  3725. foreach ($diff_array as $diff_key => $diff_value) {
  3726. if (array_key_exists($diff_key, $post_data)) {
  3727. $diff_array[$diff_key] = $post_data[$diff_key];
  3728. }
  3729. }
  3730.  
  3731. if (count($diff_array) == 0) {
  3732. // Nothing was changed, throw error.
  3733. return array('error' => 9, 'errors' => 'No values were changed.');
  3734. }
  3735.  
  3736. return $diff_array;
  3737. }
  3738.  
  3739. public function editThread($thread, $user, $edit_data = array()) {
  3740. unset($thread['absolute_url']);
  3741. if (!$user) {
  3742. return array('error' => 3, 'errors' => 'The user array key was not set.');
  3743. }
  3744. if (!$user->isRegistered()) {
  3745. return array('error' => 4, 'errors' => 'User is not registered.');
  3746. }
  3747.  
  3748. $this->getModels()->checkModel('thread_prefix', XenForo_Model::create('XenForo_Model_ThreadPrefix'));
  3749.  
  3750. // Check if the thread model has initialized.
  3751. $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum'));
  3752.  
  3753. $forum = $this->getForum($thread['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  3754.  
  3755. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']);
  3756.  
  3757. if (array_key_exists('prefix_id', $edit_data) && !$this->getModels()->getModel('thread_prefix')->verifyPrefixIsUsable($edit_data['prefix_id'], $thread['node_id'])) {
  3758. return array('error' => 0, 'errors' => 'Prefix ID is not usable.');
  3759. }
  3760.  
  3761. // discussion open state - moderator permission required
  3762. if (array_key_exists('discussion_open', $edit_data) && !empty($edit_data['discussion_open']) && !$this->getModels()->getModel('forum')->canLockUnlockThreadInForum($forum, $null, $permissions, $user->getData())) {
  3763. return array('error' => 0, 'errors' => 'User does not have permission to open/close this thread.');
  3764. }
  3765.  
  3766. // discussion sticky state - moderator permission required
  3767. if (array_key_exists('sticky', $edit_data) && !empty($edit_data['sticky']) && !$this->getModels()->getModel('forum')->canStickUnstickThreadInForum($forum, $null, $permissions, $user->getData())) {
  3768. return array('error' => 0, 'errors' => 'User does not have permission to change the sticky status of this thread.');
  3769. }
  3770.  
  3771. // Init the diff array.
  3772. $diff_array = array();
  3773.  
  3774. // Create the data writer object for registrations, and set the defaults.
  3775. $writer = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
  3776.  
  3777. // Set the existing data of the user before we submit the data.
  3778. $writer->setExistingData($thread['thread_id']);
  3779.  
  3780. // Bulkset the edited data.
  3781. $writer->bulkSet($edit_data);
  3782.  
  3783. // Pre save the data.
  3784. $writer->preSave();
  3785.  
  3786. if ($writer->hasErrors()) {
  3787. // The edit failed, return errors.
  3788. return array('error' => TRUE, 'errors' => $writer->getErrors());
  3789. }
  3790.  
  3791. // Save the user to the database.
  3792. $writer->save();
  3793.  
  3794. // Get the user data.
  3795. $thread_data = $writer->getMergedData();
  3796.  
  3797. // Check the difference between the before and after data.
  3798. $diff_array = array_merge(array_diff_assoc($thread, $thread_data), $diff_array);
  3799.  
  3800. foreach ($diff_array as $diff_key => $diff_value) {
  3801. if (array_key_exists($diff_key, $thread_data)) {
  3802. $diff_array[$diff_key] = $thread_data[$diff_key];
  3803. }
  3804. }
  3805.  
  3806. if (count($diff_array) == 0) {
  3807. // Nothing was changed, throw error.
  3808. return array('error' => 9, 'errors' => 'No values were changed.');
  3809. }
  3810.  
  3811. return $diff_array;
  3812. }
  3813.  
  3814. public function editUser($user, $edit_data = array()) {
  3815. if (!$user) {
  3816. return array('error' => 3, 'errors' => 'The user array key was not set.');
  3817. }
  3818. if (!$user->isRegistered()) {
  3819. return array('error' => 4, 'errors' => 'User is not registered.');
  3820. }
  3821. if (empty($user->data['dob_day'])) {
  3822. // We need the full profile of the user, let's re-grab the user and get the full profile.
  3823. $user = $this->getUser($user->getID(), array('join' => XenForo_Model_User::FETCH_USER_FULL));
  3824. }
  3825. $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User'));
  3826. // Check if user is super admin.
  3827. if ($this->getModels()->getModel('user')->isUserSuperAdmin($user->data)) {
  3828. // User is super admin, we do not allow editing super admins, return error.
  3829. return array('error' => 6, 'errors' => 'Editing super admins is disabled.');
  3830. }
  3831.  
  3832. if (!empty($edit_data['password'])) {
  3833. // Create a new variable for the password.
  3834. $password = $edit_data['password'];
  3835.  
  3836. // Unset the password from the user data array.
  3837. unset($edit_data['password']);
  3838. }
  3839.  
  3840. // Init the diff array.
  3841. $diff_array = array();
  3842.  
  3843. // Create the data writer object for registrations, and set the defaults.
  3844. $writer = XenForo_DataWriter::create('XenForo_DataWriter_User');
  3845.  
  3846. // Set the existing data of the user before we submit the data.
  3847. $writer->setExistingData($user->data);
  3848.  
  3849. // Let the writer know that the edit is legit and made by an administrator.
  3850. $writer->setOption(XenForo_DataWriter_User::OPTION_ADMIN_EDIT, TRUE);
  3851.  
  3852. if (!empty($edit_data['group_id'])) {
  3853. // Group ID is set.
  3854. $writer->set('user_group_id', $edit_data['group_id']);
  3855.  
  3856. // We need to unset the group id as we don't want it to be included into the bulk set.
  3857. unset($edit_data['group_id']);
  3858. }
  3859.  
  3860. if (!empty($edit_data['remove_group_id'])) {
  3861. // Group ID is set.
  3862. #$writer->set('user_group_id', $edit_data['group_id']);
  3863.  
  3864. // We need to unset the group id as we don't want it to be included into the bulk set.
  3865. unset($edit_data['remove_group_id']);
  3866. }
  3867. if (!empty($edit_data['add_groups'])) {
  3868. // Add group is set.
  3869.  
  3870. // Check if there are any custom fields in the data array.
  3871. if (!is_array($edit_data['add_groups']) || count($edit_data['add_groups']) == 0) {
  3872. // The edit failed, return errors.
  3873. return array('error' => 7, 'errors' => 'The add_groups parameter needs to be an array and have at least 1 item.');
  3874. }
  3875.  
  3876. // Initialize some arrays.
  3877. $groups = array();
  3878. $groups_exist = array();
  3879.  
  3880. // Check if there are more than one custom array.
  3881. if (strpos($user->data['secondary_group_ids'], ',') !== FALSE) {
  3882. // Value is an array, explode it.
  3883. $groups = explode(',', $user->data['secondary_group_ids']);
  3884. } else {
  3885. // Value is not an array, just add the single group to the array.
  3886. $groups[] = $user->data['secondary_group_ids'];
  3887. }
  3888.  
  3889. // Loop through the groups that are going to be added to check if the user already have the groups.
  3890. foreach ($edit_data['add_groups'] as $group_id) {
  3891. // Check if the user already is in the group.
  3892. if (in_array($group_id, $groups)) {
  3893. // User is already in the group, add the group ID to the group_exist array.
  3894. $groups_exist[] = $group_id;
  3895. } else {
  3896. // User is not in the group, add the group ID to the new_groups array.
  3897. $groups[] = $group_id;
  3898. $diff_array['new_secondary_groups'][] = $group_id;
  3899. }
  3900. }
  3901.  
  3902. // Check if the user is in one or more of the specified groups.
  3903. if (count($groups_exist) > 0) {
  3904. // The user was already in one or more groups, return error.
  3905. return array('error' => 8, 'errors' => 'The user is already a member of the group ID\'s: (' . implode(',', $groups_exist) . ')');
  3906. }
  3907.  
  3908. // Set the secondary group(s) of the user.
  3909. $writer->setSecondaryGroups($groups);
  3910.  
  3911. // We need to unset the group id as we don't want it to be included into the bulk set.
  3912. unset($edit_data['add_groups']);
  3913. }
  3914.  
  3915. if (!empty($edit_data['remove_groups'])) {
  3916. // Remove group is set.
  3917.  
  3918. // Check if there are any custom fields in the data array.
  3919. if (!is_array($edit_data['remove_groups']) || count($edit_data['remove_groups']) == 0) {
  3920. // The edit failed, return errors.
  3921. return array('error' => 11, 'errors' => 'The remove_groups parameter needs to be an array and have at least 1 item.');
  3922. }
  3923.  
  3924. // Initialize some arrays.
  3925. $groups = array();
  3926. $groups_not_exist = array();
  3927.  
  3928. // Check if there are more than one custom array.
  3929. if (strpos($user->data['secondary_group_ids'], ',') !== FALSE) {
  3930. // Value is an array, explode it.
  3931. $groups = explode(',', $user->data['secondary_group_ids']);
  3932. } else {
  3933. // Value is not an array, just add the single group to the array.
  3934. $groups[] = $user->data['secondary_group_ids'];
  3935. }
  3936.  
  3937. // Loop through the groups that are going to be added to check if the user already have the groups.
  3938. foreach ($edit_data['remove_groups'] as $group_key => $group_id) {
  3939. // Check if the user already is in the group.
  3940. if (!in_array($group_id, $groups) && $user->data['user_group_id'] != $group_id) {
  3941. // User is already in the group, add the group ID to the group_exist array.
  3942. $groups_not_exist[] = $group_id;
  3943. } else {
  3944. // Check if user's primary group is the group ID.
  3945. if (!empty($user->data['user_group_id']) && $user->data['user_group_id'] == $group_id) {
  3946. // User's primary group ID was found in the remove_groups array, move the user to the default registration group.
  3947. $writer->set('user_group_id', XenForo_Model_User::$defaultRegisteredGroupId);
  3948. $diff_array['removed_group'] = $group_id;
  3949. } else {
  3950. // User is in the group, add the group ID to the remove_groups array.
  3951. $diff_array['removed_secondary_groups'][] = $group_id;
  3952. }
  3953. // Unset the group id.
  3954. unset($groups[$group_key]);
  3955. }
  3956. }
  3957.  
  3958. // Check if the user is in one or more of the specified groups.
  3959. if (count($groups_not_exist) > 0) {
  3960. // The user was already in one or more groups, return error.
  3961. return array('error' => 12, 'errors' => 'The user is not a member of group ID\'s: (' . implode(',', $groups_not_exist) . ')');
  3962. }
  3963.  
  3964. // Set the secondary group(s) of the user.
  3965. $writer->setSecondaryGroups($groups);
  3966.  
  3967. // We need to unset the group id as we don't want it to be included into the bulk set.
  3968. unset($edit_data['remove_groups']);
  3969. }
  3970.  
  3971. if (!empty($edit_data['secondary_group_ids'])) {
  3972. // Secondary group ID's are set.
  3973. $writer->setSecondaryGroups(unserialize($edit_data['secondary_group_ids']));
  3974.  
  3975. // We need to unset the secondary group id's as we don't want it to be included into the bulk set.
  3976. unset($edit_data['secondary_group_ids']);
  3977. }
  3978.  
  3979. if (!empty($edit_data['custom_fields'])) {
  3980. // Custom fields are set.
  3981.  
  3982. // Check if there are any custom fields in the data array.
  3983. if (count($edit_data['custom_fields']) > 0) {
  3984. // There were one or more custom fields set, set them in the writer.
  3985. $writer->setCustomFields($edit_data['custom_fields']);
  3986. }
  3987. // We need to unset the custom fields as we don't want it to be included into the bulk set.
  3988. unset($edit_data['custom_fields']);
  3989. }
  3990.  
  3991. // Bulkset the edited data.
  3992. $writer->bulkSet($edit_data);
  3993.  
  3994. if (isset($password)) {
  3995. // Set the password for the data writer.
  3996. $writer->setPassword($password, $password);
  3997. }
  3998.  
  3999. // Set the data for the data writer.
  4000. $writer->bulkSet($edit_data);
  4001.  
  4002. // Pre save the data.
  4003. $writer->preSave();
  4004.  
  4005. if ($writer->hasErrors()) {
  4006. // The edit failed, return errors.
  4007. return array('error' => TRUE, 'errors' => $writer->getErrors());
  4008. }
  4009.  
  4010. // Save the user to the database.
  4011. $writer->save();
  4012.  
  4013. // Get the user data.
  4014. $user_data = $writer->getMergedData();
  4015.  
  4016. // Check the difference between the before and after data.
  4017. $diff_array = array_merge(array_diff_assoc($user->data, $user_data), $diff_array);
  4018.  
  4019. foreach ($diff_array as $diff_key => $diff_value) {
  4020. if (isset($user_data[$diff_key])) {
  4021. $diff_array[$diff_key] = $user_data[$diff_key];
  4022. }
  4023. }
  4024.  
  4025. if (isset($diff_array['secondary_group_ids'])) {
  4026. unset($diff_array['secondary_group_ids']);
  4027. }
  4028.  
  4029. if (!empty($diff_array['custom_fields'])) {
  4030. // Check the difference in the custom fields.
  4031. $custom_fields_diff_array = array_diff_assoc($user->data['custom_fields'], unserialize($diff_array['custom_fields']));
  4032.  
  4033. unset($diff_array['custom_fields']);
  4034.  
  4035. // Loop through the differences and add them to the diff array.
  4036. foreach ($custom_fields_diff_array as $custom_fields_diff_key => $custom_fields_diff_value) {
  4037. $diff_array['custom_fields'][$custom_fields_diff_key] = $custom_fields_diff_value;
  4038. }
  4039. }
  4040.  
  4041. if (isset($password)) {
  4042. // Password is changed, make sure we add it to the difference array.
  4043. $diff_array['password'] = 'OK';
  4044. }
  4045.  
  4046. if (count($diff_array) == 0) {
  4047. // Nothing was changed, throw error.
  4048. return array('error' => 9, 'errors' => 'No values were changed.');
  4049. }
  4050.  
  4051. return $diff_array;
  4052. }
  4053.  
  4054. /**
  4055. * Returns the Database model.
  4056. */
  4057. public function getDatabase() {
  4058. return $this->getModels()->getModel('database');
  4059. }
  4060.  
  4061. /**
  4062. * Returns the array of all the models.
  4063. */
  4064. public function getModels() {
  4065. return $this->models;
  4066. }
  4067.  
  4068. /**
  4069. * Grabs the User class of the last registered user.
  4070. */
  4071. public function getLatestUser() {
  4072. return new User($this->getModels(), $this->getModels()->getUserModel()->getLatestUser());
  4073. }
  4074.  
  4075. /**
  4076. * Returns the total count of registered users on XenForo.
  4077. */
  4078. public function getUserCount() {
  4079. return $this->getModels()->getUserModel()->countTotalUsers();
  4080. }
  4081.  
  4082. /**
  4083. * Returns a list of addons in the Addon class.
  4084. */
  4085. public function getAddons($type = 'all') {
  4086. // TODO: add support to grab addon options.
  4087. $type = strtolower($type);
  4088. $allowed_types = array('all', 'enabled', 'disabled');
  4089. if (!in_array($type, $allowed_types)) {
  4090. $type = 'all';
  4091. }
  4092. $installed_addons = $this->getModels()->getModel('addon')->getAllAddOns();
  4093. $addons = array();
  4094. foreach ($installed_addons as $addon) {
  4095. $temp_addon = new Addon($addon);
  4096. if (($type == 'enabled' && $temp_addon->isEnabled()) || ($type == 'disabled' && !$temp_addon->isEnabled()) || $type == 'all') {
  4097. $addons[] = $temp_addon;
  4098. }
  4099. }
  4100. return $addons;
  4101. }
  4102.  
  4103. /**
  4104. * Returns the Addon class of the $addon parameter.
  4105. */
  4106. public function getAddon($addon) {
  4107. return new Addon($this->getModels()->getModel('addon')->getAddOnById($addon));
  4108. }
  4109.  
  4110. /**
  4111. * Returns all the conversations of the user.
  4112. */
  4113. public function getConversations($user, $conditions = array(), $fetchOptions = array()) {
  4114. $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation'));
  4115. return $this->getModels()->getModel('conversation')->getConversationsForUser($user->getID(), $conditions, $fetchOptions);
  4116. }
  4117.  
  4118. public function getConversation($conversation, $user, $fetchOptions = array()) {
  4119. $this->getModels()->checkModel('conversation', XenForo_Model::create('XenForo_Model_Conversation'));
  4120. return $this->getModels()->getModel('conversation')->getConversationForUser($conversation, $user->getData(), $fetchOptions);
  4121. }
  4122.  
  4123. public function getGroup($group) {
  4124. // Get the group from the database.
  4125. return $this->getDatabase()->fetchRow("SELECT * FROM `xf_user_group` WHERE `user_group_id` = " . $this->getDatabase()->quote($group)
  4126. . " OR `title` = " . $this->getDatabase()->quote($group) . " OR `user_title` = " . $this->getDatabase()->quote($group));
  4127. }
  4128.  
  4129. /**
  4130. * Returns a list of resources.
  4131. */
  4132. public function getResources($conditions = array(), $fetchOptions = array()) {
  4133. $this->getModels()->checkModel('resource', XenForo_Model::create('XenResource_Model_Resource'));
  4134. $this->getModels()->checkModel('resource_version', XenForo_Model::create('XenResource_Model_Version'));
  4135. $this->getModels()->checkModel('attachment', XenForo_Model::create('XenForo_Model_Attachment'));
  4136. $resources_list = $this->getModels()->getModel('resource')->getResources($conditions, $fetchOptions);
  4137. $resources = array();
  4138. foreach ($resources_list as &$resource) {
  4139. $resource_version = $this->getModels()->getModel('resource_version')->getVersionById(
  4140. $resource['current_version_id'],
  4141. array('join' => XenResource_Model_Version::FETCH_FILE)
  4142. );
  4143. $resource['current_version_string'] = $resource_version['version_string'];
  4144. if ($resource['is_fileless'] === 0) {
  4145. $attachment_id = $resource_version['attachment_id'];
  4146. $attachment = $this->getModels()->getModel('attachment')->getAttachmentById($attachment_id);
  4147. $resource['current_file_hash'] = $attachment['file_hash'];
  4148. }
  4149. if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) {
  4150. $resource['custom_resource_fields'] = $resource['custom_resource_fields'] == FALSE ? NULL : unserialize($resource['custom_resource_fields']);
  4151. }
  4152. $resources[] = new Resource($resource);
  4153. }
  4154. return $resources;
  4155. }
  4156.  
  4157. /**
  4158. * Returns the Resource class of the $resource parameter.
  4159. */
  4160. public function getResource($resource, $fetchOptions = array()) {
  4161. $this->getModels()->checkModel('resource', XenForo_Model::create('XenResource_Model_Resource'));
  4162. $this->getModels()->checkModel('resource_version', XenForo_Model::create('XenResource_Model_Version'));
  4163. $this->getModels()->checkModel('attachment', XenForo_Model::create('XenForo_Model_Attachment'));
  4164. $resource = $this->getModels()->getModel('resource')->getResourceById($resource, $fetchOptions);
  4165. $resource_version = $this->getModels()->getModel('resource_version')->getVersionById(
  4166. $resource['current_version_id'],
  4167. array('join' => XenResource_Model_Version::FETCH_FILE)
  4168. );
  4169. $resource['current_version_string'] = $resource_version['version_string'];
  4170. if ($resource['is_fileless'] === 0) {
  4171. $attachment_id = $resource_version['attachment_id'];
  4172. $attachment = $this->getModels()->getModel('attachment')->getAttachmentById($attachment_id);
  4173. $resource['current_file_hash'] = $attachment['file_hash'];
  4174. }
  4175. if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) {
  4176. $resource['custom_resource_fields'] = $resource['custom_resource_fields'] == FALSE ? NULL : unserialize($resource['custom_resource_fields']);
  4177. }
  4178. return new Resource($resource);
  4179. }
  4180.  
  4181. /**
  4182. * Returns the list of resource categories.
  4183. */
  4184. public function getResourceCategories() {
  4185. $this->getModels()->checkModel('resource_category', XenForo_Model::create('XenResource_Model_Category'));
  4186. return $this->getModels()->getModel('resource_category')->getAllCategories();
  4187. }
  4188.  
  4189. /**
  4190. * TODO
  4191. */
  4192. public function getStats($start = NULL, $end = NULL, $types = NULL) {
  4193. $this->getModels()->checkModel('stats', XenForo_Model::create('XenForo_Model_Stats'));
  4194. // TODO
  4195. return $this->getModels()->getModel('stats')->getStatsData(time() - 5000, time());
  4196. }
  4197.  
  4198. public function getStatsItem($item, $include_deleted = FALSE) {
  4199. $this->getModels()->checkModel('database', XenForo_Application::get('db'));
  4200. switch ($item) {
  4201. case 'users':
  4202. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_user');
  4203. case 'conversations':
  4204. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_conversation_master');
  4205. case 'conversations_messages':
  4206. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_conversation_message');
  4207. case 'posts':
  4208. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_post' . ($include_deleted ? ' WHERE message_state != "deleted"' : ''));
  4209. case 'threads':
  4210. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_thread' . ($include_deleted ? ' WHERE discussion_state != "deleted"' : ''));
  4211. case 'registrations_today':
  4212. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_user WHERE register_date > UNIX_TIMESTAMP(CURDATE())');
  4213. case 'posts_today':
  4214. 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"' : ''));
  4215. case 'threads_today':
  4216. return $this->getModels()->getModel('database')->fetchOne('SELECT COUNT(*) FROM xf_thread WHERE post_date > UNIX_TIMESTAMP(CURDATE())' . ($include_deleted ? ' AND discussion_state != "deleted"' : ''));
  4217. default:
  4218. return NULL;
  4219. }
  4220. }
  4221.  
  4222. /**
  4223. * TODO
  4224. */
  4225. public function checkUserPermissions(&$user, array $fetchOptions = array()) {
  4226. if ($user !== NULL) {
  4227. $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User'));
  4228.  
  4229. if (!is_array($user) && !($user instanceof User)) {
  4230. $user = $this->getUser($user, array_merge($fetchOptions, array('join' => XenForo_Model_User::FETCH_USER_PERMISSIONS)));
  4231. if (empty($user->data['permissions'])) {
  4232. // Check if the user data has the permissions set, set it if not.
  4233. $user->data['permissions'] = XenForo_Permission::unserializePermissions($user->data['global_permission_cache']);
  4234. // Unset the permissions serialized cache as we don't need it anymore.
  4235. unset($user->data['global_permission_cache']);
  4236. }
  4237. } else {
  4238. if (empty($user->data['global_permission_cache'])) {
  4239. // Check if the user data has permissions cache set, grab it if not.
  4240. $user = $this->getUser($user->getID(), array_merge($fetchOptions, array('join' => XenForo_Model_User::FETCH_USER_PERMISSIONS)));
  4241. }
  4242.  
  4243. if (empty($user->data['permissions'])) {
  4244. // Check if the user data has the permissions set, set it if not.
  4245. $user->data['permissions'] = XenForo_Permission::unserializePermissions($user->data['global_permission_cache']);
  4246. // Unset the permissions serialized cache as we don't need it anymore.
  4247. unset($user->data['global_permission_cache']);
  4248. }
  4249. }
  4250. }
  4251. }
  4252.  
  4253. /**
  4254. * TODO
  4255. */
  4256. public function getUsersOnlineCount($user = NULL) {
  4257. $this->getModels()->checkModel('session', XenForo_Model::create('XenForo_Model_Session'));
  4258. if ($user !== NULL) {
  4259. // User parameter is not null, make sure to follow privacy of the users.
  4260. $this->getModels()->checkModel('user', XenForo_Model::create('XenForo_Model_User'));
  4261.  
  4262. // Check user permissions.
  4263. $this->checkUserPermissions($user);
  4264.  
  4265. // Check if the user can bypass user privacy.
  4266. $bypass = $this->getModels()->getModel('user')->canBypassUserPrivacy($null, $user->getData());
  4267. $conditions = array(
  4268. 'cutOff' => array('>', $this->getModels()->getModel('session')->getOnlineStatusTimeout()),
  4269. 'getInvisible' => $bypass,
  4270. 'getUnconfirmed' => $bypass,
  4271. 'forceInclude' => ($bypass ? FALSE : $user->getID())
  4272. );
  4273. } else {
  4274. // User parameter is null, ignore privacy and grab all the users.
  4275. $conditions = array(
  4276. 'cutOff' => array('>', $this->getModels()->getModel('session')->getOnlineStatusTimeout())
  4277. );
  4278. }
  4279. // Return the count of online visitors (users + guests).
  4280. return $this->getModels()->getModel('session')->countSessionActivityRecords($conditions);
  4281. }
  4282.  
  4283. /**
  4284. * Returns the Node array of the $node_id parameter.
  4285. */
  4286. public function getForum($node_id, $fetchOptions = array()) {
  4287. $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum'));
  4288. return $this->getModels()->getModel('forum')->getForumById($node_id, $fetchOptions);
  4289. }
  4290.  
  4291. /**
  4292. * Returns the Link Forum array of the $node_id parameter.
  4293. */
  4294. public function getLinkForum($node_id, $fetchOptions = array()) {
  4295. $this->getModels()->checkModel('link_forum', XenForo_Model::create('XenForo_Model_LinkForum'));
  4296. return $this->getModels()->getModel('link_forum')->getLinkForumById($node_id, $fetchOptions);
  4297. }
  4298.  
  4299.  
  4300. /**
  4301. * Returns the Node array of the $node_id parameter.
  4302. */
  4303. public function getNode($node_id, $fetchOptions = array()) {
  4304. $this->getModels()->checkModel('node', XenForo_Model::create('XenForo_Model_Node'));
  4305. $node = $this->getModels()->getModel('node')->getNodeById($node_id, $fetchOptions);
  4306. if (!empty($node['node_type_id'])) {
  4307. switch (strtolower($node['node_type_id'])) {
  4308. case 'forum':
  4309. return $this->getForum($node['node_id'], $fetchOptions);
  4310. case 'linkforum':
  4311. return $this->getLinkForum($node['node_id'], $fetchOptions);
  4312. case 'page':
  4313. return $this->getPage($node['node_id'], $fetchOptions);
  4314. case 'category':
  4315. default:
  4316. return $node;
  4317. }
  4318. }
  4319. return $node;
  4320. }
  4321.  
  4322. /**
  4323. * Returns a list of nodes.
  4324. */
  4325. public function getNodes($node_type = 'all', $fetchOptions = array('limit' => 10), $user = NULL) {
  4326. $this->getModels()->checkModel('node', XenForo_Model::create('XenForo_Model_Node'));
  4327.  
  4328. // Get the node list.
  4329. $node_list = $this->getModels()->getModel('node')->getAllNodes();
  4330.  
  4331. // Check if the node type that is set exists.
  4332. if ($node_type == NULL || !in_array($node_type, $this->getNodeTypes())) {
  4333. $node_type = 'all';
  4334. }
  4335.  
  4336. // Loop through the nodes to check if the user has permissions to view the thread.
  4337. foreach ($node_list as $key => &$node) {
  4338. if ($node_type != 'all' && strtolower($node['node_type_id']) != $node_type) {
  4339. // Node type does not equal the requested node type, unset the node and continue the loop.
  4340. unset($node_list[$key]);
  4341. continue;
  4342. }
  4343.  
  4344. // Check if user is set.
  4345. if ($user !== NULL) {
  4346. // Get the node.
  4347. $node = $this->getNode($node['node_id'], array_merge($fetchOptions, array('permissionCombinationId' => $user->data['permission_combination_id'])));
  4348. $permissions = XenForo_Permission::unserializePermissions($node['node_permission_cache']);
  4349.  
  4350. // User does not have permission to view this nodes, unset it and continue the loop.
  4351. if (!$this->canViewNode($user, $node, $permissions)) {
  4352. unset($node_list[$key]);
  4353. continue;
  4354. }
  4355.  
  4356. // Unset the permissions values.
  4357. unset($node_list[$key]['node_permission_cache']);
  4358. } else {
  4359. // Get the node.
  4360. $node = $this->getNode($node['node_id'], $fetchOptions);
  4361. }
  4362. }
  4363. return $node_list;
  4364. }
  4365.  
  4366. public function getDebugData() {
  4367. $database_debug = XenForo_Debug::getDatabaseDebugInfo($this->getModels()->getModel('database'));
  4368. unset($database_debug['queryHtml']);
  4369. $included_files_debug = XenForo_Debug::getIncludedFilesDebugInfo(get_included_files());
  4370. unset($included_files_debug['includedFileHtml']);
  4371. return array(
  4372. 'time' => microtime(TRUE) - XenForo_Application::get('page_start_time'),
  4373. 'database' => $database_debug,
  4374. 'memory' => array(
  4375. 'usage' => memory_get_usage(),
  4376. 'peak' => memory_get_peak_usage()
  4377. ),
  4378. 'included_files' => $included_files_debug
  4379. );
  4380. }
  4381.  
  4382. /**
  4383. * TODO
  4384. */
  4385. public function getNodeTypes() {
  4386. $this->getModels()->checkModel('node', XenForo_Model::create('XenForo_Model_Node'));
  4387. return array_keys(array_change_key_case($this->getModels()->getModel('node')->getAllNodeTypes(), CASE_LOWER));
  4388. }
  4389.  
  4390. /**
  4391. * Returns the Page array of the $node_id parameter.
  4392. */
  4393. public function getPage($node_id, $fetchOptions = array()) {
  4394. $this->getModels()->checkModel('page', XenForo_Model::create('XenForo_Model_Page'));
  4395. return $this->getModels()->getModel('page')->getPageById($node_id, $fetchOptions);
  4396. }
  4397.  
  4398. /**
  4399. * TODO
  4400. */
  4401. public function canViewNode($user, $node, $permissions = NULL) {
  4402. // Check if the forum model has initialized.
  4403. if (!empty($node['node_type_id'])) {
  4404. if ($permissions == NULL) {
  4405. // Let's grab the permissions.
  4406. $node = $this->getNode($node['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  4407.  
  4408. // Unserialize the permissions.
  4409. $permissions = XenForo_Permission::unserializePermissions($node['node_permission_cache']);
  4410. }
  4411. switch (strtolower($node['node_type_id'])) {
  4412. case 'category':
  4413. $this->getModels()->checkModel('category', XenForo_Model::create('XenForo_Model_Category'));
  4414. return $this->getModels()->getModel('category')->canViewCategory($node, $null, $permissions, $user->getData());
  4415. case 'forum':
  4416. $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum'));
  4417. return $this->getModels()->getModel('forum')->canViewForum($node, $null, $permissions, $user->getData());
  4418. case 'linkforum':
  4419. $this->getModels()->checkModel('link_forum', XenForo_Model::create('XenForo_Model_LinkForum'));
  4420. return $this->getModels()->getModel('link_forum')->canViewLinkForum($node, $null, $permissions, $user->getData());
  4421. case 'page':
  4422. $this->getModels()->checkModel('page', XenForo_Model::create('XenForo_Model_Page'));
  4423. return $this->getModels()->getModel('page')->canViewPage($node, $null, $permissions, $user->getData());
  4424. }
  4425. }
  4426. return FALSE;
  4427. }
  4428.  
  4429. /**
  4430. * Returns the Post array of the $post_id parameter.
  4431. */
  4432. public function getPost($post_id, $fetchOptions = array()) {
  4433. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post'));
  4434. $post = $this->getModels()->getModel('post')->getPostById($post_id, $fetchOptions);
  4435. if (!empty($fetchOptions['join'])) {
  4436. // Unset the thread values.
  4437. Post::stripThreadValues($post);
  4438. }
  4439.  
  4440. if ($post !== FALSE && $post !== NULL) {
  4441. // Add HTML as well
  4442. $formatter = XenForo_BbCode_Formatter_Base::create();
  4443. $parser = new XenForo_BbCode_Parser($formatter);
  4444. $post['message_html'] = str_replace("\n", '', $parser->render($post['message']));
  4445.  
  4446. $post['absolute_url'] = self::getBoardURL('posts', $post['post_id']);
  4447. } else {
  4448. $post = NULL;
  4449. }
  4450.  
  4451. return $post;
  4452. }
  4453.  
  4454. /**
  4455. * Returns a list of posts.
  4456. */
  4457. public function getPosts($conditions = array(), $fetchOptions = array('limit' => 10), $user = NULL) {
  4458. if (!empty($conditions['node_id']) || (!empty($fetchOptions['order']) && strtolower($fetchOptions['order']) == 'node_id')) {
  4459. // We need to grab the thread info to get the node_id.
  4460. $fetchOptions = array_merge($fetchOptions, array('join' => XenForo_Model_Post::FETCH_THREAD));
  4461. }
  4462. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post'));
  4463. if ($user !== NULL) {
  4464. // User is set, we need to include permissions.
  4465. if (!isset($fetchOptions['join'])) {
  4466. // WE need to grab the thread to get the node permissions.
  4467. $fetchOptions = array_merge($fetchOptions, array('join' => XenForo_Model_Post::FETCH_THREAD));
  4468. }
  4469. // User is set, we therefore have to grab the permissions to check if the user is allowed to view the post.
  4470. $fetchOptions = array_merge($fetchOptions, array('permissionCombinationId' => $user->data['permission_combination_id']));
  4471. }
  4472. // Prepare query conditions.
  4473. $whereConditions = Post::preparePostConditions($this->getModels()->getModel('database'), $this->getModels()->getModel('post'), $conditions);
  4474. $sqlClauses = $this->getModels()->getModel('post')->preparePostJoinOptions($fetchOptions);
  4475. $limitOptions = $this->getModels()->getModel('post')->prepareLimitFetchOptions($fetchOptions);
  4476.  
  4477. // Since the Post model of XenForo does not have order by implemented, we have to do it ourselves.
  4478. if (!empty($fetchOptions['order'])) {
  4479. $orderBySecondary = '';
  4480. switch ($fetchOptions['order']) {
  4481. case 'post_id':
  4482. case 'thread_id':
  4483. case 'user_id':
  4484. case 'username':
  4485. case 'attach_count':
  4486. case 'likes':
  4487. $orderBy = 'post.' . $fetchOptions['order'];
  4488. break;
  4489. case 'node_id':
  4490. $orderBy = 'thread.' . $fetchOptions['order'];
  4491. break;
  4492. case 'post_date':
  4493. default:
  4494. $orderBy = 'post.post_date';
  4495. }
  4496. // Check if order direction is set.
  4497. if (!isset($fetchOptions['orderDirection']) || $fetchOptions['orderDirection'] == 'desc') {
  4498. $orderBy .= ' DESC';
  4499. } else {
  4500. $orderBy .= ' ASC';
  4501. }
  4502. $orderBy .= $orderBySecondary;
  4503. }
  4504. $sqlClauses['orderClause'] = (isset($orderBy) ? "ORDER BY $orderBy" : '');
  4505.  
  4506. // Execute the query and get the result.
  4507. $post_list = $this->getModels()->getModel('post')->fetchAllKeyed($this->getModels()->getModel('post')->limitQueryResults(
  4508. '
  4509. SELECT post.*
  4510. ' . $sqlClauses['selectFields'] . '
  4511. FROM xf_post AS post ' . $sqlClauses['joinTables'] . '
  4512. WHERE ' . $whereConditions . '
  4513. ' . $sqlClauses['orderClause'] . '
  4514. ', $limitOptions['limit'], $limitOptions['offset']
  4515. ), 'post_id');
  4516.  
  4517. // Loop through the posts to unset some values that are not needed.
  4518. foreach ($post_list as $key => &$post) {
  4519. if ($user !== NULL) {
  4520. // Check if the user has permissions to view the post.
  4521. $permissions = XenForo_Permission::unserializePermissions($post['node_permission_cache']);
  4522. if (!$this->getModels()->getModel('post')->canViewPost($post, array('node_id' => $post['node_id']), array(), $null, $permissions, $user->getData())) {
  4523. // User does not have permission to view this post, unset it and continue the loop.
  4524. unset($post_list[$key]);
  4525. continue;
  4526. }
  4527. // Unset the permissions values.
  4528. unset($post_list[$key]['node_permission_cache']);
  4529. }
  4530.  
  4531. if (isset($fetchOptions['join'])) {
  4532. // Unset some not needed thread values.
  4533. Post::stripThreadValues($post_list[$key]);
  4534. }
  4535.  
  4536. if ($post !== FALSE && $post !== NULL) {
  4537. // Add HTML as well
  4538. $formatter = XenForo_BbCode_Formatter_Base::create();
  4539. $parser = new XenForo_BbCode_Parser($formatter);
  4540. $post['message_html'] = str_replace("\n", '', $parser->render($post['message']));
  4541.  
  4542. $post['absolute_url'] = self::getBoardURL('posts', $post['post_id']);
  4543. } else {
  4544. $post = NULL;
  4545. }
  4546. }
  4547. return array_values($post_list);
  4548. }
  4549.  
  4550. /**
  4551. * Check if user has permissions to view post.
  4552. */
  4553. public function canViewPost($user, $post, $permissions = NULL) {
  4554. // Check if the post model has initialized.
  4555. $this->getModels()->checkModel('post', XenForo_Model::create('XenForo_Model_Post'));
  4556. if ($permissions == NULL) {
  4557. // Let's grab the permissions.
  4558. $post = $this->getPost($post['post_id'], array(
  4559. 'permissionCombinationId' => $user->data['permission_combination_id'],
  4560. 'join' => XenForo_Model_Post::FETCH_FORUM
  4561. ));
  4562.  
  4563. // Unserialize the permissions.
  4564. $permissions = XenForo_Permission::unserializePermissions($post['node_permission_cache']);
  4565. }
  4566. return $this->getModels()->getModel('post')->canViewPost($post, array('node_id' => $post['node_id']), array(), $null, $permissions, $user->getData());
  4567. }
  4568.  
  4569. public function canPostThreadInForum($user, $forum, $permissions = NULL) {
  4570. // Does not take in count of private nodes.
  4571. if (!empty($forum['node_type_id'])) {
  4572. if ($permissions == NULL) {
  4573. // Let's grab the permissions.
  4574. $forum = $this->getForum($forum['node_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  4575.  
  4576. // Unserialize the permissions.
  4577. $permissions = XenForo_Permission::unserializePermissions($forum['node_permission_cache']);
  4578. }
  4579. $this->getModels()->checkModel('forum', XenForo_Model::create('XenForo_Model_Forum'));
  4580. return $this->getModels()->getModel('forum')->canPostThreadInForum($forum, $null, $permissions, $user->getData());
  4581. }
  4582. return FALSE;
  4583. }
  4584.  
  4585. public function canReplyToThread($user, $thread, $forum, $permissions = NULL) {
  4586. // Check if the thread model has initialized.
  4587. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread'));
  4588. if ($permissions == NULL) {
  4589. // Let's grab the permissions.
  4590. $thread = $this->getThread($thread['thread_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  4591.  
  4592. // Unserialize the permissions.
  4593. $permissions = XenForo_Permission::unserializePermissions($thread['node_permission_cache']);
  4594. }
  4595. return $this->getModels()->getModel('thread')->canReplyToThread($thread, $forum, $null, $permissions, $user->getData());
  4596. }
  4597.  
  4598. /**
  4599. * Returns the Post array of the $post_id parameter.
  4600. */
  4601. public function getProfilePost($profile_post_id, $fetchOptions = array()) {
  4602. $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost'));
  4603. return $this->getModels()->getModel('profile_post')->getProfilePostById($profile_post_id, $fetchOptions);
  4604. }
  4605.  
  4606. /**
  4607. * Returns a list of profile posts.
  4608. */
  4609. public function getProfilePosts($conditions = array(), $fetchOptions = array('limit' => 10), $user = NULL) {
  4610. $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost'));
  4611. if ($user !== NULL) {
  4612. // User is set, we need to include permissions.
  4613. $this->checkUserPermissions($user);
  4614. }
  4615.  
  4616. // Default the sql condition.
  4617. $sqlConditions = array();
  4618.  
  4619. if (count($conditions) > 0) {
  4620. // We need to make our own check for these conditions as XenForo's functions doesn't fully support what we want.
  4621.  
  4622. // Check if the author id is set.
  4623. if (!empty($conditions['author_id'])) {
  4624. $sqlConditions[] = "profile_post.user_id = " . $this->getModels()->getModel('database')->quote($conditions['author_id']);
  4625. }
  4626.  
  4627. // Check if the profile id is set.
  4628. if (!empty($conditions['profile_id'])) {
  4629. $sqlConditions[] = "profile_post.profile_user_id = " . $this->getModels()->getModel('database')->quote($conditions['profile_id']);
  4630. }
  4631. }
  4632.  
  4633. // Use the model function to get conditions for clause from the sql conditions.
  4634. $whereConditions = $this->getModels()->getModel('profile_post')->getConditionsForClause($sqlConditions);
  4635.  
  4636. // Prepare query conditions.
  4637. $sqlClauses = $this->getModels()->getModel('profile_post')->prepareProfilePostFetchOptions($fetchOptions);
  4638. $limitOptions = $this->getModels()->getModel('profile_post')->prepareLimitFetchOptions($fetchOptions);
  4639.  
  4640. // Since the profile post model of XenForo does not have order by implemented, we have to do it ourselves.
  4641. if (!empty($fetchOptions['order'])) {
  4642. $orderBySecondary = '';
  4643. switch ($fetchOptions['order']) {
  4644. case 'profile_post_id':
  4645. case 'profile_user_id':
  4646. case 'user_id':
  4647. case 'username':
  4648. case 'attach_count':
  4649. case 'likes':
  4650. case 'comment_count':
  4651. case 'first_comment_date':
  4652. case 'last_comment_date':
  4653. $orderBy = 'profile_post.' . $fetchOptions['order'];
  4654. break;
  4655. case 'post_date':
  4656. default:
  4657. $orderBy = 'profile_post.post_date';
  4658. }
  4659. // Check if order direction is set.
  4660. if (!isset($fetchOptions['orderDirection']) || $fetchOptions['orderDirection'] == 'desc') {
  4661. $orderBy .= ' DESC';
  4662. } else {
  4663. $orderBy .= ' ASC';
  4664. }
  4665. $orderBy .= $orderBySecondary;
  4666. }
  4667. $sqlClauses['orderClause'] = (isset($orderBy) ? "ORDER BY $orderBy" : '');
  4668.  
  4669. // Execute the query and get the result.
  4670. $profile_post_list = $this->getModels()->getModel('profile_post')->fetchAllKeyed($this->getModels()->getModel('profile_post')->limitQueryResults(
  4671. '
  4672. SELECT profile_post.*
  4673. ' . $sqlClauses['selectFields'] . '
  4674. FROM xf_profile_post AS profile_post ' . $sqlClauses['joinTables'] . '
  4675. WHERE ' . $whereConditions . '
  4676. ' . $sqlClauses['orderClause'] . '
  4677. ', $limitOptions['limit'], $limitOptions['offset']
  4678. ), 'profile_post_id');
  4679.  
  4680. if ($user !== NULL) {
  4681. // Loop through the profile posts to check permissions
  4682. foreach ($profile_post_list as $key => $profile_post) {
  4683. // Check if the user has permissions to view the profile post.
  4684. if (!$this->getModels()->getModel('profile_post')->canViewProfilePost($profile_post, array(), $null, $user->getData())) {
  4685. // User does not have permission to view this profile post, unset it and continue the loop.
  4686. unset($profile_post_list[$key]);
  4687. }
  4688. }
  4689. }
  4690.  
  4691. // Return the profile post list.
  4692. return array_values($profile_post_list);
  4693. }
  4694.  
  4695. /**
  4696. * Check if user has permissions to view post.
  4697. */
  4698. public function canViewProfilePost($user, $profile_post, $permissions = NULL) {
  4699. // Check if the profile post model has initialized.
  4700. $this->getModels()->checkModel('profile_post', XenForo_Model::create('XenForo_Model_ProfilePost'));
  4701.  
  4702. // Check if the user object has the permissions data.
  4703. $this->checkUserPermissions($user);
  4704.  
  4705. // Return if the user has permissions to view the profile post.
  4706. return $user !== NULL && $this->getModels()->getModel('profile_post')->canViewProfilePost($profile_post, array(), $null, $user->getData());
  4707. }
  4708.  
  4709. /**
  4710. * Returns the Thread array of the $thread_id parameter.
  4711. */
  4712. public function getThread($thread_id, array $fetchOptions = array(), $user = NULL) {
  4713. if (isset($fetchOptions['grab_content'])) {
  4714. $grab_content = TRUE;
  4715. unset($fetchOptions['grab_content']);
  4716. }
  4717. if (isset($fetchOptions['content_limit'])) {
  4718. $content_limit = $fetchOptions['content_limit'];
  4719. unset($fetchOptions['content_limit']);
  4720. } else {
  4721. $content_limit = 1;
  4722. }
  4723. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread'));
  4724. $thread = $this->getModels()->getModel('thread')->getThreadById($thread_id, $fetchOptions);
  4725.  
  4726. if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) {
  4727. $thread['custom_fields'] = $thread['custom_fields'] == FALSE ? NULL : unserialize($thread['custom_fields']);
  4728. }
  4729.  
  4730. if ($thread !== FALSE && $thread !== NULL) {
  4731. if (isset($grab_content)) {
  4732. $posts = $this->getPosts(array('thread_id' => $thread_id), array('limit' => $content_limit), $user);
  4733. $thread['content'] = array('count' => count($posts), 'content' => $posts);
  4734. unset($posts);
  4735. }
  4736. $thread['absolute_url'] = self::getBoardURL('threads', $thread['thread_id']);
  4737. } else {
  4738. $thread = NULL;
  4739. }
  4740.  
  4741. return $thread;
  4742. }
  4743.  
  4744. /**
  4745. * Returns a list of threads.
  4746. */
  4747. public function getThreads($conditions = array(), $fetchOptions = array('limit' => 10), $user = NULL) {
  4748. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread'));
  4749. if (isset($fetchOptions['grab_content'])) {
  4750. $grab_content = TRUE;
  4751. unset($fetchOptions['grab_content']);
  4752. }
  4753. if (isset($fetchOptions['content_limit'])) {
  4754. $content_limit = $fetchOptions['content_limit'];
  4755. unset($fetchOptions['content_limit']);
  4756. } else {
  4757. $content_limit = 1;
  4758. }
  4759. if ($user !== NULL) {
  4760. $thread_list = $this->getModels()->getModel('thread')->getThreads($conditions, array_merge($fetchOptions, array('permissionCombinationId' => $user->data['permission_combination_id'])));
  4761. } else {
  4762. $thread_list = $this->getModels()->getModel('thread')->getThreads($conditions, $fetchOptions);
  4763. }
  4764. // Loop through the threads to check if the user has permissions to view the thread.
  4765. foreach ($thread_list as $key => &$thread) {
  4766. if ($user !== NULL) {
  4767. $permissions = XenForo_Permission::unserializePermissions($thread['node_permission_cache']);
  4768. if (!$this->getModels()->getModel('thread')->canViewThread($thread, array(), $null, $permissions, $user->getData())) {
  4769. // User does not have permission to view this thread, unset it and continue the loop.
  4770. unset($thread_list[$key]);
  4771. // Unset the permissions values.
  4772. unset($thread_list[$key]['node_permission_cache']);
  4773. continue;
  4774. } else {
  4775. // Unset the permissions values.
  4776. unset($thread_list[$key]['node_permission_cache']);
  4777. }
  4778. }
  4779. if ($thread !== FALSE && $thread !== NULL) {
  4780. if (isset($grab_content)) {
  4781. $posts = $this->getPosts(array('thread_id' => $thread['thread_id']), array('limit' => $content_limit), $user);
  4782. $thread['content'] = array('count' => count($posts), 'content' => $posts);
  4783. unset($posts);
  4784. }
  4785. if ($this->hasAddon('Waindigo_CustomFields') && $this->hasModel('Waindigo_CustomFields_Model_ThreadField')) {
  4786. $thread['custom_fields'] = $thread['custom_fields'] == FALSE ? NULL : unserialize($thread['custom_fields']);
  4787. }
  4788. $thread['absolute_url'] = self::getBoardURL('threads', $thread['thread_id']);
  4789. } else {
  4790. $thread = NULL;
  4791. }
  4792. }
  4793. return array_values($thread_list);
  4794. }
  4795.  
  4796.  
  4797. /**
  4798. * Returns the Thread array of the $thread_id parameter.
  4799. */
  4800. public function canViewThread($user, $thread, $permissions = NULL) {
  4801. // Check if the thread model has initialized.
  4802. $this->getModels()->checkModel('thread', XenForo_Model::create('XenForo_Model_Thread'));
  4803. if ($permissions == NULL) {
  4804. // Let's grab the permissions.
  4805. $thread = $this->getThread($thread['thread_id'], array('permissionCombinationId' => $user->data['permission_combination_id']));
  4806.  
  4807. // Unserialize the permissions.
  4808. $permissions = XenForo_Permission::unserializePermissions($thread['node_permission_cache']);
  4809. }
  4810. return $this->getModels()->getModel('thread')->canViewThread($thread, array(), $null, $permissions, $user->getData());
  4811. }
  4812.  
  4813. public function getUsersByIp($ip) {
  4814. $this->getModels()->checkModel('ip', XenForo_Model::create('XenForo_Model_Ip'));
  4815. return $this->getModels()->getModel('ip')->getUsersByIp($ip);
  4816. }
  4817.  
  4818. /**
  4819. * Returns the User class of the $input parameter.
  4820. *
  4821. * The $input parameter can be an user ID, username or e-mail.
  4822. * Returns FALSE if $input is NULL.
  4823. */
  4824. public function getUser($input, $fetchOptions = array()) {
  4825. if (!empty($fetchOptions['custom_field'])) {
  4826. $results = $this->getDatabase()->fetchRow("SELECT `user_id` FROM `xf_user_field_value` WHERE `field_id` = "
  4827. . $this->getDatabase()->quote($fetchOptions['custom_field']) . " AND `field_value` = " . $this->getDatabase()->quote($input));
  4828. if (!empty($results['user_id'])) {
  4829. $input = $results['user_id'];
  4830. }
  4831. }
  4832. if ($input == FALSE || $input == NULL) {
  4833. return FALSE;
  4834. } else if (is_numeric($input)) {
  4835. // $input is a number, grab the user by an ID.
  4836. $user = new User($this->models, $this->models->getUserModel()->getUserById($input, $fetchOptions));
  4837. if (!$user->isRegistered()) {
  4838. // The user ID was not found, grabbing the user by the username instead.
  4839. $user = new User($this->models, $this->models->getUserModel()->getUserByName($input, $fetchOptions));
  4840. }
  4841. } else if ($this->models->getUserModel()->couldBeEmail($input)) {
  4842. // $input is an e-mail, return the user of the e-mail.
  4843. $user = new User($this->models, $this->models->getUserModel()->getUserByEmail($input, $fetchOptions));
  4844. } else {
  4845. // $input is an username, return the user of the username.
  4846. $user = new User($this->models, $this->models->getUserModel()->getUserByName($input, $fetchOptions));
  4847. }
  4848. if ($user->isRegistered()) {
  4849. $this->getModels()->checkModel('user_field', XenForo_Model::create('XenForo_Model_UserField'));
  4850. $user->data['custom_fields'] = $this->getModels()->getModel('user_field')->getUserFieldValues($user->getID());
  4851. }
  4852. return $user;
  4853. }
  4854.  
  4855. public function getUserUpgrade($upgrade_id) {
  4856. $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade'));
  4857. return $this->getModels()->getModel('user_upgrade')->getUserUpgradeById($upgrade_id);
  4858. }
  4859.  
  4860. public function getUserUpgrades($user = NULL) {
  4861. $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade'));
  4862. if ($user !== NULL) {
  4863. $user_upgrades = $this->getModels()->getModel('user_upgrade')->getActiveUserUpgradeRecordsForUser($user->getID());
  4864. foreach ($user_upgrades as &$user_upgrade) {
  4865. $user_upgrade['extra'] = unserialize($user_upgrade['extra']);
  4866. }
  4867. return $user_upgrades;
  4868. }
  4869. return $this->getModels()->getModel('user_upgrade')->getAllUserUpgrades();
  4870. }
  4871.  
  4872. public function getUserUpgradeRecord($record_id) {
  4873. $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade'));
  4874. $upgrade_record = $this->getModels()->getModel('user_upgrade')->getActiveUserUpgradeRecordById($record_id);
  4875. if ($upgrade_record !== FALSE) {
  4876. $upgrade_record['extra'] = unserialize($upgrade_record['extra']);
  4877. }
  4878. return $upgrade_record;
  4879. }
  4880.  
  4881. public function upgradeUser($user, array $upgrade, $allow_insert_unpurchasable = FALSE, $end_date = NULL) {
  4882. $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade'));
  4883. return $this->getModels()->getModel('user_upgrade')->upgradeUser($user->getID(), $upgrade, $allow_insert_unpurchasable, $end_date);
  4884. }
  4885.  
  4886. public function downgradeUserUpgrade($record) {
  4887. $this->getModels()->checkModel('user_upgrade', XenForo_Model::create('XenForo_Model_UserUpgrade'));
  4888. return $this->getModels()->getModel('user_upgrade')->downgradeUserUpgrade($record);
  4889. }
  4890.  
  4891. public function hasModel($model) {
  4892. if (XenForo_Application::autoload($model)) {
  4893. $model = @XenForo_Model::create($model);
  4894. return is_a($model, 'XenForo_Model');
  4895. }
  4896. return FALSE;
  4897. }
  4898.  
  4899. public function hasAddon($addon_id) {
  4900. $has = FALSE;
  4901. $addons = $this->getAddons();
  4902. foreach ($addons as $addon) {
  4903. if (strtolower($addon->getID()) == strtolower($addon_id)) {
  4904. $has = TRUE;
  4905. break;
  4906. }
  4907. }
  4908. return $has;
  4909. }
  4910.  
  4911. /**
  4912. * TODO
  4913. */
  4914. public function register($user_data) {
  4915. if (empty($user_data['username'])) {
  4916. // Username was empty, return error.
  4917. return array('error' => 10, 'errors' => 'Missing required parameter: username');
  4918. } else if (empty($user_data['password'])) {
  4919. // Password was empty, return error.
  4920. return array('error' => 10, 'errors' => 'Missing required parameter: password');
  4921. } else if (empty($user_data['email'])) {
  4922. // Email was empty, return error.
  4923. return array('error' => 10, 'errors' => 'Missing required parameter: email');
  4924. }
  4925.  
  4926. // Create a new variable for the password.
  4927. $password = $user_data['password'];
  4928.  
  4929. // Unset the password from the user data array.
  4930. unset($user_data['password']);
  4931.  
  4932. if (!empty($user_data['ip_address'])) {
  4933. // Create a new variable for the ip address.
  4934. $ip_address = $user_data['ip_address'];
  4935.  
  4936. // Unset the ip address from the user data array.
  4937. unset($user_data['ip_address']);
  4938. }
  4939.  
  4940. // Get the default options from XenForo.
  4941. $options = XenForo_Application::get('options');
  4942.  
  4943. // Create the data writer object for registrations, and set the defaults.
  4944. $writer = XenForo_DataWriter::create('XenForo_DataWriter_User');
  4945. if ($options->registrationDefaults) {
  4946. // Set the default registration options if it's set in the XenForo options.
  4947. $writer->bulkSet($options->registrationDefaults, array('ignoreInvalidFields' => TRUE));
  4948. }
  4949.  
  4950. if (!empty($user_data['group_id'])) {
  4951. // Group ID is set.
  4952. $writer->set('user_group_id', $user_data['group_id']);
  4953.  
  4954. // We need to unset the group id as we don't want it to be included into the bulk set.
  4955. unset($user_data['group_id']);
  4956. } else {
  4957. // Group ID is not set, default back to default.
  4958. $writer->set('user_group_id', XenForo_Model_User::$defaultRegisteredGroupId);
  4959. }
  4960.  
  4961. if (!empty($user_data['user_state'])) {
  4962. // User state is set.
  4963. $writer->set('user_state', $user_data['user_state']);
  4964. } else {
  4965. // User state is not set, default back to default.
  4966. $writer->advanceRegistrationUserState();
  4967. }
  4968.  
  4969. if (!empty($user_data['language_id'])) {
  4970. // Language ID is set.
  4971. $writer->set('language_id', $user_data['language_id']);
  4972. } else {
  4973. // Language ID is not set, default back to default.
  4974. $writer->set('language_id', $options->defaultLanguageId);
  4975. }
  4976.  
  4977. if (!empty($user_data['custom_fields'])) {
  4978. // Custom fields are set.
  4979.  
  4980. // Check if there are any custom fields in the data array.
  4981. if (count($user_data['custom_fields']) > 0) {
  4982. // There were one or more custom fields set, set them in the writer.
  4983. $writer->setCustomFields($user_data['custom_fields']);
  4984. }
  4985. // We need to unset the custom fields as we don't want it to be included into the bulk set.
  4986. unset($user_data['custom_fields']);
  4987. }
  4988.  
  4989. if (!empty($user_data['add_groups'])) {
  4990. // Add group is set.
  4991.  
  4992. // Check if there are any custom fields in the data array.
  4993. if (!is_array($user_data['add_groups']) || count($user_data['add_groups']) == 0) {
  4994. // The edit failed, return errors.
  4995. return array('error' => 7, 'errors' => 'The add_groups parameter needs to be an array and have at least 1 item.');
  4996. }
  4997.  
  4998. // Set the secondary group(s) of the user.
  4999. $writer->setSecondaryGroups($user_data['add_groups']);
  5000.  
  5001. // We need to unset the group id as we don't want it to be included into the bulk set.
  5002. unset($user_data['add_groups']);
  5003. }
  5004.  
  5005. // Check if Gravatar is enabled, set the gravatar if it is and there's a gravatar for the email.
  5006. if ($options->gravatarEnable && XenForo_Model_Avatar::gravatarExists($data['email'])) {
  5007. $writer->set('gravatar', $user_data['email']);
  5008. }
  5009.  
  5010. // Set the data for the data writer.
  5011. $writer->bulkSet($user_data);
  5012.  
  5013. // Set the password for the data writer.
  5014. $writer->setPassword($password, $password);
  5015.  
  5016. // Pre save the data.
  5017. $writer->preSave();
  5018.  
  5019. if ($writer->hasErrors()) {
  5020. // The registration failed, return errors.
  5021. return array('error' => TRUE, 'errors' => $writer->getErrors());
  5022. }
  5023.  
  5024. // Save the user to the database.
  5025. $writer->save();
  5026.  
  5027. // Get the User as a variable:
  5028. $user = $writer->getMergedData();
  5029.  
  5030. // Check if IP is set.
  5031. if (!empty($user_data['ip_address'])) {
  5032. // Log the IP of the user that registered.
  5033. XenForo_Model_Ip::log($user['user_id'], 'user', $user['user_id'], 'register', $ip_address);
  5034. }
  5035.  
  5036. // Send email if the user state was specified.
  5037. if ($user['user_state'] == 'email_confirm') {
  5038. $this->getModels()->checkModel('user_confirmation', XenForo_Model::create('XenForo_Model_UserConfirmation'));
  5039. $this->getModels()->getModel('user_confirmation')->sendEmailConfirmation($user);
  5040. }
  5041.  
  5042. return $user;
  5043. }
  5044. }
  5045.  
  5046. /**
  5047. * This class contains all the required models of XenForo.
  5048. */
  5049. class Models {
  5050. private $models = array();
  5051.  
  5052. /**
  5053. * Returns TRUE if the model exists, FALSE if not.
  5054. */
  5055. public function hasModel($model_name) {
  5056. return isset($this->models[$model_name]) && $this->models[$model_name] !== NULL;
  5057. }
  5058.  
  5059. /**
  5060. * Checks if the model exists, adds it to the array if not.
  5061. */
  5062. public function checkModel($model_name, $model) {
  5063. if (!$this->hasModel($model_name)) {
  5064. $this->setModel($model_name, $model);
  5065. }
  5066. }
  5067.  
  5068. /**
  5069. * Returns the array of all the models.
  5070. */
  5071. public function getModels() {
  5072. return $this->models;
  5073. }
  5074.  
  5075. /**
  5076. * Returns the model defined by the parameter $model.
  5077. */
  5078. public function getModel($model) {
  5079. return $this->models[$model];
  5080. }
  5081.  
  5082. /**
  5083. * Sets the model of the parameter $model.
  5084. */
  5085. public function setModel($name, $model) {
  5086. $this->models[$name] = $model;
  5087. }
  5088.  
  5089. /**
  5090. * Sets the user model.
  5091. */
  5092. public function setUserModel($userModel) {
  5093. $this->models['userModel'] = $userModel;
  5094. }
  5095.  
  5096. /**
  5097. * Returns the user model.
  5098. */
  5099. public function getUserModel() {
  5100. return $this->models['userModel'];
  5101. }
  5102.  
  5103. /**
  5104. * Sets the alert model.
  5105. */
  5106. public function setAlertModel($alertModel) {
  5107. $this->models['alertModel'] = $alertModel;
  5108. }
  5109.  
  5110. /**
  5111. * Returns the alert model.
  5112. */
  5113. public function getAlertModel() {
  5114. return $this->models['alertModel'];
  5115. }
  5116.  
  5117. /**
  5118. * Sets the userfield model.
  5119. */
  5120. public function setUserFieldModel($userFieldModel) {
  5121. $this->models['userFieldModel'] = $userFieldModel;
  5122. }
  5123.  
  5124. /**
  5125. * Returns the userfield model.
  5126. */
  5127. public function getUserFieldModel() {
  5128. return $this->models['userFieldModel'];
  5129. }
  5130.  
  5131. /**
  5132. * Sets the avatar model.
  5133. */
  5134. public function setAvatarModel($avatarModel) {
  5135. $this->models['avatarModel'] = $avatarModel;
  5136. }
  5137.  
  5138. /**
  5139. * Returns the avatar model.
  5140. */
  5141. public function getAvatarModel() {
  5142. return $this->models['avatarModel'];
  5143. }
  5144.  
  5145. /**
  5146. * Returns the database model.
  5147. */
  5148. public function getDatabase() {
  5149. return $this->getModel('database');
  5150. }
  5151. }
  5152.  
  5153. class Post {
  5154. public static function stripThreadValues(&$post) {
  5155. unset($post['reply_count']);
  5156. unset($post['view_count']);
  5157. unset($post['sticky']);
  5158. unset($post['discussion_state']);
  5159. unset($post['discussion_open']);
  5160. unset($post['discussion_type']);
  5161. unset($post['first_post_id']);
  5162. unset($post['first_post_likes']);
  5163. unset($post['last_post_date']);
  5164. unset($post['last_post_id']);
  5165. unset($post['last_post_user_id']);
  5166. unset($post['last_post_username']);
  5167. unset($post['prefix_id']);
  5168. unset($post['thread_user_id']);
  5169. unset($post['thread_username']);
  5170. unset($post['thread_post_date']);
  5171. }
  5172. public static function preparePostConditions($db, $model, array $conditions) {
  5173. $sqlConditions = array();
  5174.  
  5175. if (!empty($conditions['forum_id']) && empty($conditions['node_id'])) {
  5176. $conditions['node_id'] = $conditions['forum_id'];
  5177. }
  5178.  
  5179. if (!empty($conditions['node_id'])) {
  5180. if (is_array($conditions['node_id'])) {
  5181. $sqlConditions[] = 'thread.node_id IN (' . $db->quote($conditions['node_id']) . ')';
  5182. } else {
  5183. $sqlConditions[] = 'thread.node_id = ' . $db->quote($conditions['node_id']);
  5184. }
  5185. }
  5186.  
  5187. if (!empty($conditions['thread_id'])) {
  5188. if (is_array($conditions['thread_id'])) {
  5189. $sqlConditions[] = 'post.thread_id IN (' . $db->quote($conditions['thread_id']) . ')';
  5190. } else {
  5191. $sqlConditions[] = 'post.thread_id = ' . $db->quote($conditions['thread_id']);
  5192. }
  5193. }
  5194.  
  5195. if (!empty($conditions['prefix_id'])) {
  5196. if (is_array($conditions['prefix_id'])) {
  5197. $sqlConditions[] = 'thread.prefix_id IN (' . $db->quote($conditions['prefix_id']) . ')';
  5198. } else {
  5199. $sqlConditions[] = 'thread.prefix_id = ' . $db->quote($conditions['prefix_id']);
  5200. }
  5201. }
  5202.  
  5203. if (!empty($conditions['post_date']) && is_array($conditions['post_date'])) {
  5204. list($operator, $cutOff) = $conditions['post_date'];
  5205.  
  5206. $model->assertValidCutOffOperator($operator);
  5207. $sqlConditions[] = "post.post_date $operator " . $db->quote($cutOff);
  5208. }
  5209.  
  5210. // thread starter
  5211. if (isset($conditions['user_id'])) {
  5212. $sqlConditions[] = 'post.user_id = ' . $db->quote($conditions['user_id']);
  5213. }
  5214.  
  5215. return $model->getConditionsForClause($sqlConditions);
  5216. }
  5217. }
  5218.  
  5219. /**
  5220. * This class contains all the functions and all the relevant data of a XenForo resource.
  5221. */
  5222. class Resource {
  5223. private $data;
  5224.  
  5225. /**
  5226. * Default constructor.
  5227. */
  5228. public function __construct($data) {
  5229. $this->data = $data;
  5230. }
  5231.  
  5232. /**
  5233. * Returns an array with that conists of limited data.
  5234. */
  5235. public static function getLimitedData($resource) {
  5236. return array('id' => $resource->getID(),
  5237. 'title' => $resource->getTitle(),
  5238. 'author_id' => $resource->getAuthorUserID(),
  5239. 'author_username' => $resource->getAuthorUsername(),
  5240. 'state' => $resource->getState(),
  5241. 'creation_date' => $resource->getCreationDate(),
  5242. 'category_id' => $resource->getCategoryID(),
  5243. 'version_id' => $resource->getCurrentVersionID(),
  5244. 'version_string' => $resource->getCurrentVersionString(),
  5245. 'file_hash' => $resource->getCurrentFileHash(),
  5246. 'description_id' => $resource->getDescriptionUpdateID(),
  5247. 'description' => $resource->getDescription(),
  5248. 'thread_id' => $resource->getDiscussionThreadID(),
  5249. 'external_url' => $resource->getExternalURL(),
  5250. 'price' => $resource->getPrice(),
  5251. 'currency' => $resource->getCurrency(),
  5252. 'times_downloaded' => $resource->getTimesDownloaded(),
  5253. 'times_rated' => $resource->getTimesRated(),
  5254. 'rating_sum' => $resource->getRatingSum(),
  5255. 'rating_avg' => $resource->getAverageRating(),
  5256. 'rating_weighted' => $resource->getWeightedRating(),
  5257. 'times_updated' => $resource->getTimesUpdated(),
  5258. 'times_reviewed' => $resource->getTimesReviewed(),
  5259. 'last_update' => $resource->getLastUpdateDate(),
  5260. 'custom_fields' => $resource->getCustomFields()
  5261. );
  5262. }
  5263.  
  5264. /**
  5265. * Returns an array which contains all the data of the resource.
  5266. */
  5267. public function getData() {
  5268. return $this->data;
  5269. }
  5270.  
  5271. /**
  5272. * Returns TRUE if the resource is valid, returns FALSE if not.
  5273. */
  5274. public function isValid() {
  5275. return $this->data !== NULL && is_array($this->data) && isset($this->data['resource_id']) && $this->data['resource_id'] !== NULL;
  5276. }
  5277.  
  5278. public function getCustomFields() {
  5279. return array_key_exists('custom_resource_fields', $this->data) ? $this->data['custom_resource_fields'] : NULL;
  5280. }
  5281.  
  5282. /**
  5283. * Returns the ID of the resource.
  5284. */
  5285. public function getID() {
  5286. return $this->data['resource_id'];
  5287. }
  5288.  
  5289. /**
  5290. * Returns the title of the resource.
  5291. */
  5292. public function getTitle() {
  5293. return $this->data['title'];
  5294. }
  5295.  
  5296. /**
  5297. * Returns the tag line of the resource.
  5298. */
  5299. public function getTagLine() {
  5300. return $this->data['tag_line'];
  5301. }
  5302.  
  5303. /**
  5304. * Returns the ID of the author.
  5305. */
  5306. public function getAuthorUserID() {
  5307. return $this->data['user_id'];
  5308. }
  5309.  
  5310. /**
  5311. * Returns the username of the author.
  5312. */
  5313. public function getAuthorUsername() {
  5314. return $this->data['username'];
  5315. }
  5316.  
  5317.  
  5318. /**
  5319. * Returns the state of the resource.
  5320. * TODO
  5321. */
  5322. public function getState() {
  5323. return $this->data['resource_state'];
  5324. }
  5325.  
  5326. /**
  5327. * Returns the creation date of the resource.
  5328. */
  5329. public function getCreationDate() {
  5330. return $this->data['resource_date'];
  5331. }
  5332.  
  5333. /**
  5334. * Returns the category ID of the resource.
  5335. */
  5336. public function getCategoryID() {
  5337. return $this->data['resource_category_id'];
  5338. }
  5339.  
  5340. /**
  5341. * Returns the current version ID of the resource.
  5342. */
  5343. public function getCurrentVersionID() {
  5344. return $this->data['current_version_id'];
  5345. }
  5346.  
  5347. /**
  5348. * Returns the current version string of the resource.
  5349. */
  5350. public function getCurrentVersionString() {
  5351. return $this->data['current_version_string'];
  5352. }
  5353.  
  5354. /**
  5355. * Returns the current file hash (MD5) of the resource.
  5356. */
  5357. public function getCurrentFileHash() {
  5358. return $this->data['current_file_hash'];
  5359. }
  5360.  
  5361. /**
  5362. * Returns the current description update ID of the resource.
  5363. */
  5364. public function getDescriptionUpdateID() {
  5365. return $this->data['description_update_id'];
  5366. }
  5367.  
  5368. /**
  5369. * Returns the current description of the resource.
  5370. */
  5371. public function getDescription() {
  5372. return $this->data['description'];
  5373. }
  5374.  
  5375. /**
  5376. * Returns the discussion thread ID of the resource.
  5377. */
  5378. public function getDiscussionThreadID() {
  5379. return $this->data['discussion_thread_id'];
  5380. }
  5381.  
  5382. /**
  5383. * Returns the external URL of the resource.
  5384. */
  5385. public function getExternalURL() {
  5386. return $this->data['external_url'];
  5387. }
  5388.  
  5389. /**
  5390. * Returns TRUE if the resource is fileless, FALSE if not.
  5391. */
  5392. public function isFileless() {
  5393. return $this->data['is_fileless'] == 1;
  5394. }
  5395.  
  5396. /**
  5397. * Returns the external purchase URL of the resource if it has any.
  5398. */
  5399. public function getExternalPurchaseURL() {
  5400. return $this->data['external_purchase_url'];
  5401. }
  5402.  
  5403. /**
  5404. * Returns the price of the resource.
  5405. */
  5406. public function getPrice() {
  5407. return $this->data['price'];
  5408. }
  5409.  
  5410. /**
  5411. * Returns the currency of the price of the resource.
  5412. */
  5413. public function getCurrency() {
  5414. return $this->data['currency'];
  5415. }
  5416.  
  5417. /**
  5418. * Returns the amount of times the resource has been downloaded.
  5419. */
  5420. public function getTimesDownloaded() {
  5421. return $this->data['download_count'];
  5422. }
  5423.  
  5424. /**
  5425. * Returns the amount of times the resource has been rated.
  5426. */
  5427. public function getTimesRated() {
  5428. return $this->data['rating_count'];
  5429. }
  5430.  
  5431. /**
  5432. * Returns the sum of the ratings.
  5433. */
  5434. public function getRatingSum() {
  5435. return $this->data['rating_sum'];
  5436. }
  5437.  
  5438. /**
  5439. * Returns the average rating of the resource.
  5440. */
  5441. public function getAverageRating() {
  5442. return $this->data['rating_avg'];
  5443. }
  5444.  
  5445. /**
  5446. * Returns the weighted rating of the resource.
  5447. */
  5448. public function getWeightedRating() {
  5449. return $this->data['rating_weighted'];
  5450. }
  5451.  
  5452. /**
  5453. * Returns the amount of times the resource has been updated.
  5454. */
  5455. public function getTimesUpdated() {
  5456. return $this->data['update_count'];
  5457. }
  5458.  
  5459. /**
  5460. * Returns the amount of times the resource has been reviewed.
  5461. */
  5462. public function getTimesReviewed() {
  5463. return $this->data['review_count'];
  5464. }
  5465.  
  5466. /**
  5467. * Returns the last update date of the resource.
  5468. */
  5469. public function getLastUpdateDate() {
  5470. return $this->data['last_update'];
  5471. }
  5472.  
  5473. /**
  5474. * Returns the alternative support URL of the resource.
  5475. */
  5476. public function getAlternativeSupportURL() {
  5477. return $this->data['alt_support_url'];
  5478. }
  5479.  
  5480. /**
  5481. * Returns TRUE if the resource had first visible.
  5482. */
  5483. public function hadFirstVisible() {
  5484. return $this->data['had_first_visible'] == 1;
  5485. }
  5486. }
  5487.  
  5488. /**
  5489. * This class contains all the functions and all the relevant data of a XenForo addon.
  5490. */
  5491. class Addon {
  5492. private $data;
  5493.  
  5494. /**
  5495. * Default constructor.
  5496. */
  5497. public function __construct($data) {
  5498. $this->data = $data;
  5499. }
  5500.  
  5501. /**
  5502. * Returns an array with that conists of limited data.
  5503. */
  5504. public static function getLimitedData($addon) {
  5505. return array('id' => $addon->getID(),
  5506. 'title' => $addon->getTitle(),
  5507. 'version' => $addon->getVersionString(),
  5508. 'enabled' => $addon->isEnabled(),
  5509. 'url' => $addon->getURL());
  5510. }
  5511.  
  5512. /**
  5513. * Returns an array which contains all the data of the addon.
  5514. */
  5515. public function getData() {
  5516. return $this->data;
  5517. }
  5518.  
  5519. /**
  5520. * Returns TRUE if the addon is installed, returns FALSE if not.
  5521. */
  5522. public function isInstalled() {
  5523. return $this->data !== NULL && is_array($this->data) && isset($this->data['addon_id']) && $this->data['addon_id'] !== NULL;
  5524. }
  5525.  
  5526. /**
  5527. * Returns TRUE if the addon is enabled, returns FALSE if not.
  5528. */
  5529. public function isEnabled() {
  5530. return $this->data['active'] == 1;
  5531. }
  5532.  
  5533. /**
  5534. * Returns the ID of the addon.
  5535. */
  5536. public function getID() {
  5537. return $this->data['addon_id'];
  5538. }
  5539.  
  5540. /**
  5541. * Returns the title of the addon.
  5542. */
  5543. public function getTitle() {
  5544. return $this->data['title'];
  5545. }
  5546.  
  5547. /**
  5548. * Returns the version string of the addon.
  5549. */
  5550. public function getVersionString() {
  5551. return $this->data['version_string'];
  5552. }
  5553.  
  5554. /**
  5555. * Returns the version ID of the addon.
  5556. */
  5557. public function getVersionID() {
  5558. return $this->data['version_id'];
  5559. }
  5560.  
  5561. /**
  5562. * Returns the URL of the addon.
  5563. */
  5564. public function getURL() {
  5565. return $this->data['url'];
  5566. }
  5567.  
  5568. /**
  5569. * Returns the install callback class of the addon.
  5570. */
  5571. public function getInstallCallbackClass() {
  5572. return $this->data['install_callback_class'];
  5573. }
  5574.  
  5575. /**
  5576. * Returns the install callback method of the addon.
  5577. */
  5578. public function getInstallCallbackMethod() {
  5579. return $this->data['install_callback_method'];
  5580. }
  5581.  
  5582. /**
  5583. * Returns the uninstall callback class of the addon.
  5584. */
  5585. public function getUninstallCallbackClass() {
  5586. return $this->data['uninstall_callback_class'];
  5587. }
  5588.  
  5589. /**
  5590. * Returns the uninstall callback method of the addon.
  5591. */
  5592. public function getUninstallCallbackMethod() {
  5593. return $this->data['uninstall_callback_class'];
  5594. }
  5595. }
  5596.  
  5597. /**
  5598. * This class contains all the functions and all the relevant data of a XenForo user.
  5599. */
  5600. class User {
  5601. public $data;
  5602. private $models, $registered = FALSE;
  5603.  
  5604. /**
  5605. * Default constructor.
  5606. */
  5607. public function __construct($models, $data) {
  5608. $this->models = $models;
  5609. $this->data = $data;
  5610. if (!empty($data)) {
  5611. $this->registered = TRUE;
  5612. }
  5613. }
  5614.  
  5615. /**
  5616. * Returns an array which contains all the data of the user.
  5617. */
  5618. public function getData() {
  5619. return $this->data;
  5620. }
  5621.  
  5622. /**
  5623. * Returns all the alerts and relevant information regarding the alerts.
  5624. */
  5625. public function getAlerts($type = 'fetchRecent') {
  5626. /*
  5627. * Options are:
  5628. * - fetchPopupItems: Fetch alerts viewed in the last options:alertsPopupExpiryHours hours.
  5629. * - fetchRecent: Fetch alerts viewed in the last options:alertExpiryDays days.
  5630. * - fetchAll: Fetch alerts regardless of their view_date.
  5631. *
  5632. * For more information, see /library/XenForo/Model/Alert.php.
  5633. */
  5634. $types = array('fetchPopupItems', 'fetchRecent', 'fetchAll');
  5635. if (!in_array($type, $types)) {
  5636. $type = 'fetchRecent';
  5637. }
  5638. return $this->models->getAlertModel()->getAlertsForUser($this->getID(), $type);
  5639. }
  5640.  
  5641. /**
  5642. * Returns the ID of the user.
  5643. */
  5644. public function getID() {
  5645. return $this->data['user_id'];
  5646. }
  5647.  
  5648. /**
  5649. * Returns the username of the user.
  5650. */
  5651. public function getUsername() {
  5652. return $this->data['username'];
  5653. }
  5654.  
  5655. /**
  5656. * Returns the email of the user.
  5657. */
  5658. public function getEmail() {
  5659. return $this->data['email'];
  5660. }
  5661.  
  5662. /**
  5663. * Returns the avatar URL of the user.
  5664. */
  5665. public function getAvatar($size) {
  5666. $avatarUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://')
  5667. . $_SERVER['HTTP_HOST']
  5668. . dirname($_SERVER['REQUEST_URI'])
  5669. . (dirname($_SERVER['REQUEST_URI']) != '/' ? '/' : '');
  5670. if ($this->data['gravatar']) {
  5671. return XenForo_Template_Helper_Core::getAvatarUrl($this->data, $size);
  5672. } else if (!empty($this->data['avatar_date'])) {
  5673. return $avatarUrl . XenForo_Template_Helper_Core::getAvatarUrl($this->data, $size, 'custom');
  5674. } else {
  5675. return $avatarUrl . XenForo_Template_Helper_Core::getAvatarUrl($this->data, $size, 'default');
  5676. }
  5677. }
  5678.  
  5679. /**
  5680. * Returns if the user is registered or not.
  5681. */
  5682. public function isRegistered() {
  5683. return $this->registered;
  5684. }
  5685.  
  5686. /**
  5687. * Returns TRUE if the user is a global moderator.
  5688. */
  5689. public function isModerator() {
  5690. return $this->data['is_moderator'] == 1;
  5691. }
  5692.  
  5693. /**
  5694. * Returns TRUE if the user an administrator.
  5695. */
  5696. public function isAdmin() {
  5697. return $this->data['is_admin'] == 1;
  5698. }
  5699.  
  5700. /**
  5701. * Returns TRUE if the user is banned.
  5702. */
  5703. public function isBanned() {
  5704. return $this->data['is_banned'] == 1;
  5705. }
  5706.  
  5707. /**
  5708. * Returns the authentication record of the user.
  5709. */
  5710. public function getAuthenticationRecord() {
  5711. return $this->models->getUserModel()->getUserAuthenticationRecordByUserId($this->data['user_id']);
  5712. }
  5713.  
  5714. /**
  5715. * Verifies the password of the user.
  5716. */
  5717. public function validateAuthentication($password) {
  5718. if (strlen($password) == 64) {
  5719. $record = $this->getAuthenticationRecord();
  5720. $ddata = unserialize($record['data']);
  5721. return $ddata['hash'] == $password;
  5722. } else {
  5723. return $this->models->getUserModel()->validateAuthentication($this->data['username'], $password);
  5724. }
  5725. }
  5726.  
  5727. /**
  5728. * Returns the amount of unread alerts.
  5729. */
  5730. public function getUnreadAlertsCount() {
  5731. return $this->models->getUserModel()->getUnreadAlertsCount($this->getID());
  5732. }
  5733.  
  5734. /**
  5735. * Returns the permission cache, if any.
  5736. */
  5737. public function getPermissionCache() {
  5738. return $this->data['global_permission_cache'];
  5739. }
  5740. }
Add Comment
Please, Sign In to add comment