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