SOAP API: do not try to unserialize an invalid filter
[mantis.git] / core / user_pref_api.php
blobf9f2bcfe30a10eaef78b7086c952d2d733a27547
1 <?php
2 # MantisBT - A PHP based bugtracking system
4 # MantisBT is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 2 of the License, or
7 # (at your option) any later version.
9 # MantisBT is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * User Preferences API
20 * @package CoreAPI
21 * @subpackage UserPreferencesAPI
22 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
23 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net
24 * @link http://www.mantisbt.org
26 * @uses authentication_api.php
27 * @uses config_api.php
28 * @uses constant_inc.php
29 * @uses database_api.php
30 * @uses error_api.php
31 * @uses lang_api.php
32 * @uses user_api.php
33 * @uses utility_api.php
36 require_api( 'authentication_api.php' );
37 require_api( 'config_api.php' );
38 require_api( 'constant_inc.php' );
39 require_api( 'database_api.php' );
40 require_api( 'error_api.php' );
41 require_api( 'lang_api.php' );
42 require_api( 'user_api.php' );
43 require_api( 'utility_api.php' );
45 /**
46 * Preference Structure Definition
47 * @package MantisBT
48 * @subpackage classes
50 class UserPreferences {
51 protected $default_profile = NULL;
52 protected $default_project = NULL;
53 protected $refresh_delay = NULL;
54 protected $redirect_delay = NULL;
55 protected $bugnote_order = NULL;
56 protected $email_on_new = NULL;
57 protected $email_on_assigned = NULL;
58 protected $email_on_feedback = NULL;
59 protected $email_on_resolved = NULL;
60 protected $email_on_closed = NULL;
61 protected $email_on_reopened = NULL;
62 protected $email_on_bugnote = NULL;
63 protected $email_on_status = NULL;
64 protected $email_on_priority = NULL;
65 protected $email_on_new_min_severity = NULL;
66 protected $email_on_assigned_min_severity = NULL;
67 protected $email_on_feedback_min_severity = NULL;
68 protected $email_on_resolved_min_severity = NULL;
69 protected $email_on_closed_min_severity = NULL;
70 protected $email_on_reopened_min_severity = NULL;
71 protected $email_on_bugnote_min_severity = NULL;
72 protected $email_on_status_min_severity = NULL;
73 protected $email_on_priority_min_severity = NULL;
74 protected $email_bugnote_limit = NULL;
75 protected $language = NULL;
76 protected $timezone = NULL;
78 private $pref_user_id;
79 private $pref_project_id;
81 private static $default_mapping = array(
82 'default_profile' => 'default_profile',
83 'default_project' => 'default_project',
84 'refresh_delay' => 'default_refresh_delay',
85 'redirect_delay' => 'default_redirect_delay',
86 'bugnote_order' => 'default_bugnote_order',
87 'email_on_new' => 'default_email_on_new',
88 'email_on_assigned' => 'default_email_on_assigned',
89 'email_on_feedback' => 'default_email_on_feedback',
90 'email_on_resolved' => 'default_email_on_resolved',
91 'email_on_closed' => 'default_email_on_closed',
92 'email_on_reopened' => 'default_email_on_reopened',
93 'email_on_bugnote' => 'default_email_on_bugnote',
94 'email_on_status' => 'default_email_on_status',
95 'email_on_priority' => 'default_email_on_priority',
96 'email_on_new_min_severity' => 'default_email_on_new_minimum_severity',
97 'email_on_assigned_min_severity' => 'default_email_on_assigned_minimum_severity',
98 'email_on_feedback_min_severity' => 'default_email_on_feedback_minimum_severity',
99 'email_on_resolved_min_severity' => 'default_email_on_resolved_minimum_severity',
100 'email_on_closed_min_severity' => 'default_email_on_closed_minimum_severity',
101 'email_on_reopened_min_severity' => 'default_email_on_reopened_minimum_severity',
102 'email_on_bugnote_min_severity' => 'default_email_on_bugnote_minimum_severity',
103 'email_on_status_min_severity' => 'default_email_on_status_minimum_severity',
104 'email_on_priority_min_severity' => 'default_email_on_priority_minimum_severity',
105 'email_bugnote_limit' => 'default_email_bugnote_limit',
106 'language' => 'default_language',
107 'timezone' => 'default_timezone',
111 * Constructor
112 * @param int $p_user_id
113 * @param int $p_project_id
115 function UserPreferences( $p_user_id, $p_project_id ) {
116 $this->default_profile = 0;
117 $this->default_project = ALL_PROJECTS;
119 $this->pref_user_id = (int)$p_user_id;
120 $this->pref_project_id = (int)$p_project_id;
124 * @param string $name
125 * @param string $value
126 * @private
128 public function __set($name, $value) {
129 switch ($name) {
130 case 'timezone':
131 if( $value == '' ) {
132 $value = null;
135 $this->$name = $value;
139 * @param string $t_string
140 * @private
142 public function __get( $p_string ) {
143 if( is_null( $this->$p_string ) ) {
144 $this->$p_string = config_get( self::$default_mapping[$p_string], null, $this->pref_user_id, $this->pref_project_id );
146 return $this->$p_string;
150 * @param string $t_string
152 function Get( $p_string ) {
153 if( is_null( $this->$p_string ) ) {
154 $this->$p_string = config_get( self::$default_mapping[$p_string], null, $this->pref_user_id, $this->pref_project_id );
156 return $this->$p_string;
160 # ########################################
161 # SECURITY NOTE: cache globals are initialized here to prevent them
162 # being spoofed if register_globals is turned on
164 $g_cache_user_pref = array();
165 $g_cache_current_user_pref = array();
168 * Cache a user preferences row if necessary and return the cached copy
169 * If the third parameter is true (default), trigger an error
170 * if the preferences can't be found. If the second parameter is
171 * false, return false if the preferences can't be found.
173 * @param int $p_user_id
174 * @param int $p_project_id
175 * @param bool $p_trigger_errors
176 * @return false|array
178 function user_pref_cache_row( $p_user_id, $p_project_id = ALL_PROJECTS, $p_trigger_errors = true ) {
179 global $g_cache_user_pref;
181 if( isset( $g_cache_user_pref[(int)$p_user_id][(int)$p_project_id] ) ) {
182 return $g_cache_user_pref[(int)$p_user_id][(int)$p_project_id];
185 $t_user_pref_table = db_get_table( 'user_pref' );
187 $query = "SELECT *
188 FROM $t_user_pref_table
189 WHERE user_id=" . db_param() . " AND project_id=" . db_param();
190 $result = db_query_bound( $query, Array( (int)$p_user_id, (int)$p_project_id ) );
192 if( 0 == db_num_rows( $result ) ) {
193 if( $p_trigger_errors ) {
194 trigger_error( ERROR_USER_PREFS_NOT_FOUND, ERROR );
195 } else {
196 $g_cache_user_pref[(int)$p_user_id][(int)$p_project_id] = false;
197 return false;
201 $row = db_fetch_array( $result );
203 if( !isset( $g_cache_user_pref[(int)$p_user_id] ) ) {
204 $g_cache_user_pref[(int)$p_user_id] = array();
207 $g_cache_user_pref[(int)$p_user_id][(int)$p_project_id] = $row;
209 return $row;
213 * Cache user preferences for a set of users
214 * @param array $p_user_id_array
215 * @param int $p_project_id
216 * @return null
218 function user_pref_cache_array_rows( $p_user_id_array, $p_project_id = ALL_PROJECTS ) {
219 global $g_cache_user_pref;
220 $c_user_id_array = array();
222 # identify the user ids that are not cached already.
223 foreach( $p_user_id_array as $t_user_id ) {
224 if( !isset( $g_cache_user_pref[(int) $t_user_id][(int)$p_project_id] ) ) {
225 $c_user_id_array[(int)$t_user_id] = (int)$t_user_id;
229 # if all users are already cached, then return
230 if ( empty( $c_user_id_array ) ) {
231 return;
234 $t_user_pref_table = db_get_table( 'user_pref' );
236 $query = "SELECT *
237 FROM $t_user_pref_table
238 WHERE user_id IN (" . implode( ',', $c_user_id_array ) . ') AND project_id=' . db_param();
240 $result = db_query_bound( $query, Array( (int)$p_project_id ) );
242 while( $row = db_fetch_array( $result ) ) {
243 if ( !isset( $g_cache_user_pref[(int) $row['user_id']] ) ) {
244 $g_cache_user_pref[(int) $row['user_id']] = array();
247 $g_cache_user_pref[(int) $row['user_id']][(int)$p_project_id] = $row;
249 # remove found users from required set.
250 unset( $c_user_id_array[(int) $row['user_id']] );
253 # cache users that are not found as false (i.e. negative cache)
254 foreach( $c_user_id_array as $t_user_id ) {
255 $g_cache_user_pref[(int) $t_user_id][(int)$p_project_id] = false;
260 * Clear the user preferences cache (or just the given id if specified)
261 * @param $p_user_id
262 * @param $p_project_id
263 * @return true
265 function user_pref_clear_cache( $p_user_id = null, $p_project_id = null ) {
266 global $g_cache_user_pref;
268 if( null === $p_user_id ) {
269 $g_cache_user_pref = array();
270 } else if( null === $p_project_id ) {
271 unset( $g_cache_user_pref[(int)$p_user_id] );
272 } else {
273 unset( $g_cache_user_pref[(int)$p_user_id][(int)$p_project_id] );
276 return true;
280 * return true if the user has prefs assigned for the given project,
281 * false otherwise
282 * @param int $p_user_id
283 * @param int $p_project_id
284 * @return bool
286 function user_pref_exists( $p_user_id, $p_project_id = ALL_PROJECTS ) {
287 if( false === user_pref_cache_row( $p_user_id, $p_project_id, false ) ) {
288 return false;
289 } else {
290 return true;
295 * perform an insert of a preference object into the DB
296 * @param int $p_user_id
297 * @param int $p_project_id
298 * @param UserPreferences $p_prefs
299 * @return true
301 function user_pref_insert( $p_user_id, $p_project_id, $p_prefs ) {
302 static $t_vars;
303 $c_user_id = db_prepare_int( $p_user_id );
304 $c_project_id = db_prepare_int( $p_project_id );
306 user_ensure_unprotected( $p_user_id );
308 $t_user_pref_table = db_get_table( 'user_pref' );
310 if ($t_vars == null ) {
311 $t_vars = getClassProperties( 'UserPreferences', 'protected');
314 $t_values = array();
316 $t_params[] = db_param(); // user_id
317 $t_values[] = $c_user_id;
318 $t_params[] = db_param(); // project_id
319 $t_values[] = $c_project_id;
320 foreach( $t_vars as $var => $val ) {
321 array_push( $t_params, db_param());
322 array_push( $t_values, $p_prefs->Get( $var ) );
325 $t_vars_string = implode( ', ', array_keys( $t_vars ) );
326 $t_params_string = implode( ',', $t_params );
328 $query = 'INSERT INTO ' . $t_user_pref_table .
329 ' (user_id, project_id, ' . $t_vars_string . ') ' .
330 ' VALUES ( ' . $t_params_string . ')';
331 db_query_bound( $query, $t_values );
333 # db_query errors on failure so:
334 return true;
338 * perform an update of a preference object into the DB
339 * @param int $p_user_id
340 * @param int $p_project_id
341 * @param UserPreferences $p_prefs
342 * @return true
344 function user_pref_update( $p_user_id, $p_project_id, $p_prefs ) {
345 static $t_vars;
346 $c_user_id = db_prepare_int( $p_user_id );
347 $c_project_id = db_prepare_int( $p_project_id );
349 user_ensure_unprotected( $p_user_id );
351 $t_user_pref_table = db_get_table( 'user_pref' );
353 if ($t_vars == null ) {
354 $t_vars = getClassProperties( 'UserPreferences', 'protected');
357 $t_pairs = array();
358 $t_values = array();
360 foreach( $t_vars as $var => $val ) {
361 array_push( $t_pairs, "$var = " . db_param() ) ;
362 array_push( $t_values, $p_prefs->$var );
365 $t_pairs_string = implode( ', ', $t_pairs );
366 $t_values[] = $c_user_id;
367 $t_values[] = $c_project_id;
369 $query = "UPDATE $t_user_pref_table
370 SET $t_pairs_string
371 WHERE user_id=" . db_param() . " AND project_id=" . db_param();
372 db_query_bound( $query, $t_values );
374 user_pref_clear_cache( $p_user_id, $p_project_id );
376 # db_query errors on failure so:
377 return true;
381 * delete a preferencess row
382 * returns true if the prefs were successfully deleted
383 * @param int $p_user_id
384 * @param int $p_project_id
385 * @return true
387 function user_pref_delete( $p_user_id, $p_project_id = ALL_PROJECTS ) {
388 $c_user_id = db_prepare_int( $p_user_id );
389 $c_project_id = db_prepare_int( $p_project_id );
391 user_ensure_unprotected( $p_user_id );
393 $t_user_pref_table = db_get_table( 'user_pref' );
395 $query = "DELETE FROM $t_user_pref_table
396 WHERE user_id=" . db_param() . " AND
397 project_id=" . db_param();
398 db_query_bound( $query, Array( $c_user_id, $c_project_id ) );
400 user_pref_clear_cache( $p_user_id, $p_project_id );
402 # db_query errors on failure so:
403 return true;
407 * delete all preferences for a user in all projects
408 * returns true if the prefs were successfully deleted
410 * It is far more efficient to delete them all in one query than to
411 * call user_pref_delete() for each one and the code is short so that's
412 * what we do
413 * @param int $p_user_id
414 * @return true
416 function user_pref_delete_all( $p_user_id ) {
417 $c_user_id = db_prepare_int( $p_user_id );
419 user_ensure_unprotected( $p_user_id );
421 $t_user_pref_table = db_get_table( 'user_pref' );
423 $query = 'DELETE FROM ' . $t_user_pref_table . ' WHERE user_id=' . db_param();
424 db_query_bound( $query, Array( $c_user_id ) );
426 user_pref_clear_cache( $p_user_id );
428 # db_query errors on failure so:
429 return true;
433 * delete all preferences for a project for all users (part of deleting the project)
434 * returns true if the prefs were successfully deleted
436 * It is far more efficient to delete them all in one query than to
437 * call user_pref_delete() for each one and the code is short so that's
438 * what we do
439 * @param $p_project_id
440 * @return true
442 function user_pref_delete_project( $p_project_id ) {
443 $c_project_id = db_prepare_int( $p_project_id );
445 $t_user_pref_table = db_get_table( 'user_pref' );
447 $query = 'DELETE FROM ' . $t_user_pref_table . ' WHERE project_id=' . db_param();
448 db_query_bound( $query, Array( $c_project_id ) );
450 # db_query errors on failure so:
451 return true;
455 * return the user's preferences in a UserPreferences object
456 * @param int $p_user_id
457 * @param int $p_project_id
458 * @return UserPreferences
460 function user_pref_get( $p_user_id, $p_project_id = ALL_PROJECTS ) {
461 static $t_vars;
462 global $g_cache_current_user_pref;
464 if ( isset( $g_cache_current_user_pref[(int)$p_project_id] ) &&
465 auth_is_user_authenticated() &&
466 auth_get_current_user_id() == $p_user_id ) {
467 return $g_cache_current_user_pref[(int)$p_project_id];
470 $t_prefs = new UserPreferences( $p_user_id, $p_project_id );
472 $row = user_pref_cache_row( $p_user_id, $p_project_id, false );
474 # If the user has no preferences for the given project
475 if( false === $row ) {
476 if( ALL_PROJECTS != $p_project_id ) {
477 # Try to get the prefs for ALL_PROJECTS (the defaults)
478 $row = user_pref_cache_row( $p_user_id, ALL_PROJECTS, false );
481 # If $row is still false (the user doesn't have default preferences)
482 if( false === $row ) {
483 # We use an empty array
484 $row = array();
488 if ($t_vars == null ) {
489 $t_vars = getClassProperties( 'UserPreferences', 'protected');
492 $t_row_keys = array_keys( $row );
494 # Check each variable in the class
495 foreach( $t_vars as $var => $val ) {
496 # If we got a field from the DB with the same name
497 if( in_array( $var, $t_row_keys, true ) ) {
498 # Store that value in the object
499 $t_prefs->$var = $row[$var];
502 if ( auth_is_user_authenticated() && auth_get_current_user_id() == $p_user_id ) {
503 $g_cache_current_user_pref[ (int)$p_project_id ] = $t_prefs;
505 return $t_prefs;
509 * Return the specified preference field for the user id
510 * If the preference can't be found try to return a defined default
511 * If that fails, trigger a WARNING and return ''
512 * @param int $p_user_id
513 * @param string $p_pref_name
514 * @param int $p_project_id
515 * @return string
517 function user_pref_get_pref( $p_user_id, $p_pref_name, $p_project_id = ALL_PROJECTS ) {
518 static $t_vars;
520 $t_prefs = user_pref_get( $p_user_id, $p_project_id );
522 if ($t_vars == null ) {
523 $t_reflection = new ReflectionClass('UserPreferences');
524 $t_vars = $t_reflection->getDefaultProperties();
527 if( in_array( $p_pref_name, array_keys( $t_vars ), true ) ) {
528 return $t_prefs->Get( $p_pref_name );
529 } else {
530 error_parameters( $p_pref_name );
531 trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING );
532 return '';
537 * returns user language
538 * @param int $p_user_id
539 * @param int $p_project_id
540 * @return string language name or null if invalid language specified
542 function user_pref_get_language( $p_user_id, $p_project_id = ALL_PROJECTS ) {
543 $t_prefs = user_pref_get( $p_user_id, $p_project_id );
545 // ensure the language is a valid one
546 $t_lang = $t_prefs->language;
547 if( !lang_language_exists( $t_lang ) ) {
548 $t_lang = null;
550 return $t_lang;
554 * Set a user preference
556 * By getting the prefs for the project first we deal fairly well with defaults.
557 * If there are currently no prefs for that project, the ALL_PROJECTS prefs will
558 * be returned so we end up storing a new set of prefs for the given project
559 * based on the prefs for ALL_PROJECTS. If there isn't even an entry for
560 * ALL_PROJECTS, we'd get returned a default UserPreferences object to modify.
561 * @param int $p_user_id
562 * @param string $p_pref_name
563 * @param string $p_pref_value
564 * @param int $p_project_id
565 * @return true
567 function user_pref_set_pref( $p_user_id, $p_pref_name, $p_pref_value, $p_project_id = ALL_PROJECTS ) {
568 $t_prefs = user_pref_get( $p_user_id, $p_project_id );
570 $t_prefs->$p_pref_name = $p_pref_value;
572 user_pref_set( $p_user_id, $t_prefs, $p_project_id );
574 return true;
578 * set the user's preferences for the project from the given preferences object
579 * Do the work by calling user_pref_update() or user_pref_insert() as appropriate
580 * @param int $p_user_id
581 * @param UserPreferences $p_prefs
582 * @param int $p_project_id
583 * @return true
585 function user_pref_set( $p_user_id, $p_prefs, $p_project_id = ALL_PROJECTS ) {
586 if( user_pref_exists( $p_user_id, $p_project_id ) ) {
587 return user_pref_update( $p_user_id, $p_project_id, $p_prefs );
588 } else {
589 return user_pref_insert( $p_user_id, $p_project_id, $p_prefs );