1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 * 21 */ 22 23declare(strict_types=0); 24 25namespace Ampache\Repository\Model; 26 27use Ampache\Module\Authorization\Access; 28use Ampache\Module\System\Dba; 29use Ampache\Config\AmpConfig; 30use Ampache\Module\System\Core; 31 32/** 33 * This handles all of the preference stuff for Ampache 34 */ 35class Preference extends database_object 36{ 37 protected const DB_TABLENAME = 'preference'; 38 39 /** 40 * This array contains System preferences that can (should) not be edited or deleted from the api 41 */ 42 public const SYSTEM_LIST = array( 43 'ajax_load', 44 'album_group', 45 'album_release_type', 46 'album_release_type_sort', 47 'album_sort', 48 'allow_democratic_playback', 49 'allow_localplay_playback', 50 'allow_personal_info_agent', 51 'allow_personal_info_now', 52 'allow_personal_info_recent', 53 'allow_personal_info_time', 54 'allow_stream_playback', 55 'allow_upload', 56 'allow_video', 57 'autoupdate', 58 'autoupdate_lastcheck', 59 'autoupdate_lastversion', 60 'autoupdate_lastversion_new', 61 'broadcast_by_default', 62 'browse_filter', 63 'browser_notify', 64 'browser_notify_timeout', 65 'catalog_check_duplicate', 66 'cron_cache', 67 'custom_blankalbum', 68 'custom_blankmovie', 69 'custom_datetime', 70 'custom_favicon', 71 'custom_login_backgound', 72 'custom_login_logo', 73 'custom_logo', 74 'custom_text_footer', 75 'daap_backend', 76 'daap_pass', 77 'demo_clear_sessions', 78 'direct_play_limit', 79 'disabled_custom_metadata_fields', 80 'disabled_custom_metadata_fields_input', 81 'download', 82 'force_http_play', 83 'geolocation', 84 'home_moment_albums', 85 'home_moment_videos', 86 'home_now_playing', 87 'home_recently_played', 88 'httpq_active', 89 'lang', 90 'lastfm_challenge', 91 'lastfm_grant_link', 92 'libitem_browse_alpha', 93 'libitem_contextmenu', 94 'localplay_controller', 95 'localplay_level', 96 'lock_songs', 97 'mpd_active', 98 'notify_email', 99 'now_playing_per_user', 100 'offset_limit', 101 'playlist_method', 102 'playlist_type', 103 'play_type', 104 'podcast_keep', 105 'podcast_new_download', 106 'popular_threshold', 107 'rate_limit', 108 'share', 109 'share_expire', 110 'show_donate', 111 'show_lyrics', 112 'show_played_times', 113 'show_skipped_times', 114 'sidebar_light', 115 'site_title', 116 'slideshow_time', 117 'song_page_title', 118 'stats_threshold', 119 'stream_beautiful_url', 120 'subsonic_backend', 121 'theme_color', 122 'theme_name', 123 'topmenu', 124 'transcode', 125 'transcode_bitrate', 126 'ui_fixed', 127 'unique_playlist', 128 'upload_allow_edit', 129 'upload_allow_remove', 130 'upload_catalog', 131 'upload_catalog_pattern', 132 'upload_script', 133 'upload_subdir', 134 'upload_user_artist', 135 'upnp_backend', 136 'webdav_backend', 137 'webplayer_aurora', 138 'webplayer_confirmclose', 139 'webplayer_flash', 140 'webplayer_html5', 141 'webplayer_pausetabs' 142 ); 143 144 /** 145 * __constructor 146 * This does nothing... amazing isn't it! 147 */ 148 private function __construct() 149 { 150 // Rien a faire 151 } // __construct 152 153 /** 154 * get_by_user 155 * Return a preference for specific user identifier 156 * @param integer $user_id 157 * @param string $pref_name 158 * @return integer|string 159 */ 160 public static function get_by_user($user_id, $pref_name) 161 { 162 //debug_event(self::class, 'Getting preference {'.$pref_name.'} for user identifier {'.$user_id.'}...', 5); 163 $user_id = (int) Dba::escape($user_id); 164 $pref_name = Dba::escape($pref_name); 165 $pref_id = self::id_from_name($pref_name); 166 167 if (parent::is_cached('get_by_user-' . $pref_name, $user_id)) { 168 return (parent::get_from_cache('get_by_user-' . $pref_name, $user_id))['value']; 169 } 170 171 $sql = "SELECT `value` FROM `user_preference` WHERE `preference`='$pref_id' AND `user`='$user_id'"; 172 $db_results = Dba::read($sql); 173 if (Dba::num_rows($db_results) < 1) { 174 $sql = "SELECT `value` FROM `user_preference` WHERE `preference`='$pref_id' AND `user`='-1'"; 175 $db_results = Dba::read($sql); 176 } 177 $data = Dba::fetch_assoc($db_results); 178 179 parent::add_to_cache('get_by_user-' . $pref_name, $user_id, $data); 180 181 return $data['value']; 182 } // get_by_user 183 184 /** 185 * update 186 * This updates a single preference from the given name or id 187 * @param string $preference 188 * @param integer $user_id 189 * @param array|string $value 190 * @param boolean $applytoall 191 * @param boolean $applytodefault 192 * @return boolean 193 */ 194 public static function update($preference, $user_id, $value, $applytoall = false, $applytodefault = false) 195 { 196 // First prepare 197 if (!is_numeric($preference)) { 198 $pref_id = self::id_from_name($preference); 199 $name = $preference; 200 } else { 201 $pref_id = $preference; 202 $name = self::name_from_id($preference); 203 } 204 if (is_array($value)) { 205 $value = implode(',', $value); 206 } 207 $params = array($value, $pref_id); 208 209 if ($applytoall && Access::check('interface', 100)) { 210 $user_check = ""; 211 } else { 212 $user_check = "AND `user` = ?"; 213 $params[] = $user_id; 214 } 215 216 if ($applytodefault && Access::check('interface', 100)) { 217 $sql = "UPDATE `preference` SET `value` = ? WHERE `id`= ?"; 218 Dba::write($sql, $params); 219 } 220 221 if (self::has_access($name)) { 222 $sql = "UPDATE `user_preference` SET `value` = ? WHERE `preference` = ? $user_check"; 223 Dba::write($sql, $params); 224 self::clear_from_session(); 225 226 parent::remove_from_cache('get_by_user', $user_id); 227 228 return true; 229 } else { 230 debug_event(self::class, Core::get_global('user') ? Core::get_global('user')->username : '???' . ' attempted to update ' . $name . ' but does not have sufficient permissions', 3); 231 } 232 233 return false; 234 } // update 235 236 /** 237 * update_level 238 * This takes a preference ID and updates the level required to update it (performed by an admin) 239 * @param $preference 240 * @param $level 241 * @return boolean 242 */ 243 public static function update_level($preference, $level) 244 { 245 // First prepare 246 if (!is_numeric($preference)) { 247 $preference_id = self::id_from_name($preference); 248 } else { 249 $preference_id = $preference; 250 } 251 252 $preference_id = Dba::escape($preference_id); 253 $level = Dba::escape($level); 254 255 $sql = "UPDATE `preference` SET `level`='$level' WHERE `id`='$preference_id'"; 256 Dba::write($sql); 257 258 return true; 259 } // update_level 260 261 /** 262 * update_all 263 * This takes a preference id and a value and updates all users with the new info 264 * @param integer $preference_id 265 * @param string $value 266 * @return boolean 267 */ 268 public static function update_all($preference_id, $value) 269 { 270 $preference_id = (string)Dba::escape($preference_id); 271 $value = (string)Dba::escape($value); 272 273 $sql = "UPDATE `user_preference` SET `value`='$value' WHERE `preference`='$preference_id'"; 274 Dba::write($sql); 275 276 parent::clear_cache(); 277 278 return true; 279 } // update_all 280 281 /** 282 * exists 283 * This just checks to see if a preference currently exists 284 * @param string $preference 285 * @return integer 286 */ 287 public static function exists($preference) 288 { 289 // We assume it's the name 290 $name = Dba::escape($preference); 291 $sql = "SELECT * FROM `preference` WHERE `name`='$name'"; 292 $db_results = Dba::read($sql); 293 294 return Dba::num_rows($db_results); 295 } // exists 296 297 /** 298 * has_access 299 * This checks to see if the current user has access to modify this preference 300 * as defined by the preference name 301 * @param $preference 302 * @return boolean 303 */ 304 public static function has_access($preference) 305 { 306 // Nothing for those demo thugs 307 if (AmpConfig::get('demo_mode')) { 308 return false; 309 } 310 311 $preference = Dba::escape($preference); 312 313 $sql = "SELECT `level` FROM `preference` WHERE `name`='$preference'"; 314 $db_results = Dba::read($sql); 315 $data = Dba::fetch_assoc($db_results); 316 317 if (Access::check('interface', $data['level'])) { 318 return true; 319 } 320 321 return false; 322 } // has_access 323 324 /** 325 * id_from_name 326 * This takes a name and returns the id 327 * @param string $name 328 * @return array|integer 329 */ 330 public static function id_from_name($name) 331 { 332 $name = Dba::escape($name); 333 334 if (parent::is_cached('id_from_name', $name)) { 335 return (int)(parent::get_from_cache('id_from_name', $name))[0]; 336 } 337 338 $sql = "SELECT `id` FROM `preference` WHERE `name`='$name'"; 339 $db_results = Dba::read($sql); 340 $row = Dba::fetch_assoc($db_results); 341 342 parent::add_to_cache('id_from_name', $name, $row); 343 344 return (int)$row['id']; 345 } // id_from_name 346 347 /** 348 * name_from_id 349 * This returns the name from an id, it's the exact opposite 350 * of the function above it, amazing! 351 * @param $pref_id 352 * @return mixed 353 */ 354 public static function name_from_id($pref_id) 355 { 356 $pref_id = Dba::escape($pref_id); 357 358 $sql = "SELECT `name` FROM `preference` WHERE `id`='$pref_id'"; 359 $db_results = Dba::read($sql); 360 361 $row = Dba::fetch_assoc($db_results); 362 363 return $row['name']; 364 } // name_from_id 365 366 /** 367 * get_categories 368 * This returns an array of the names of the different possible sections 369 * it ignores the 'internal' category 370 */ 371 public static function get_categories() 372 { 373 $sql = "SELECT `preference`.`catagory` FROM `preference` GROUP BY `catagory` ORDER BY `catagory`"; 374 375 $db_results = Dba::read($sql); 376 $results = array(); 377 while ($row = Dba::fetch_assoc($db_results)) { 378 if ($row['catagory'] != 'internal') { 379 $results[] = $row['catagory']; 380 } 381 } // end while 382 383 return $results; 384 } // get_categories 385 386 /** 387 * get_all 388 * This returns a nice flat array of all of the possible preferences for the specified user 389 * @param integer $user_id 390 * @return array 391 */ 392 public static function get_all($user_id) 393 { 394 $user_id = Dba::escape($user_id); 395 $user_limit = ($user_id != -1) ? "AND `preference`.`catagory` != 'system'" : ""; 396 397 $sql = "SELECT `preference`.`id`, `preference`.`name`, `preference`.`description`, `preference`.`level`, `preference`.`type`, `preference`.`catagory`, `preference`.`subcatagory`, `user_preference`.`value` FROM `preference` INNER JOIN `user_preference` ON `user_preference`.`preference`=`preference`.`id` WHERE `user_preference`.`user` = ? AND `preference`.`catagory` != 'internal' $user_limit ORDER BY `preference`.`subcatagory`, `preference`.`description`"; 398 399 $db_results = Dba::read($sql, array($user_id)); 400 $results = array(); 401 402 while ($row = Dba::fetch_assoc($db_results)) { 403 $results[] = array( 404 'id' => $row['id'], 405 'name' => $row['name'], 406 'level' => $row['level'], 407 'description' => $row['description'], 408 'value' => $row['value'], 409 'type' => $row['type'], 410 'category' => $row['catagory'], 411 'subcategory' => $row['subcatagory'] 412 ); 413 } 414 415 return $results; 416 } // get_all 417 418 /** 419 * get 420 * This returns a nice flat array of all of the possible preferences for the specified user 421 * @param string $pref_name 422 * @param integer $user_id 423 * @return array 424 */ 425 public static function get($pref_name, $user_id) 426 { 427 $user_id = Dba::escape($user_id); 428 $user_limit = ($user_id != -1) ? "AND `preference`.`catagory` != 'system'" : ""; 429 430 $sql = "SELECT `preference`.`id`, `preference`.`name`, `preference`.`description`, `preference`.`level`, `preference`.`type`, `preference`.`catagory`, `preference`.`subcatagory`, `user_preference`.`value` FROM `preference` INNER JOIN `user_preference` ON `user_preference`.`preference`=`preference`.`id` WHERE `preference`.`name` = ? AND `user_preference`.`user`= ? AND `preference`.`catagory` != 'internal' $user_limit ORDER BY `preference`.`subcatagory`, `preference`.`description`"; 431 432 $db_results = Dba::read($sql, array($pref_name, $user_id)); 433 $results = array(); 434 435 while ($row = Dba::fetch_assoc($db_results)) { 436 $results[] = array('id' => $row['id'], 'name' => $row['name'], 'level' => $row['level'], 'description' => $row['description'], 437 'value' => $row['value'], 'type' => $row['type'], 'category' => $row['catagory'], 'subcategory' => $row['subcatagory']); 438 } 439 440 return $results; 441 } // get 442 443 /** 444 * insert 445 * This inserts a new preference into the preference table 446 * it does NOT sync up the users, that should be done independently 447 * @param string $name 448 * @param string $description 449 * @param string|integer $default 450 * @param integer $level 451 * @param string $type 452 * @param string $category 453 * @param string $subcategory 454 * @return boolean 455 */ 456 public static function insert($name, $description, $default, $level, $type, $category, $subcategory = null) 457 { 458 if ($subcategory !== null) { 459 $subcategory = strtolower((string)$subcategory); 460 } 461 $sql = "INSERT INTO `preference` (`name`, `description`, `value`, `level`, `type`, `catagory`, `subcatagory`) VALUES (?, ?, ?, ?, ?, ?, ?)"; 462 $db_results = Dba::write($sql, array($name, $description, $default, (int) $level, $type, $category, $subcategory)); 463 464 if (!$db_results) { 465 return false; 466 } 467 $pref_id = Dba::insert_id(); 468 $params = array($pref_id, $default); 469 $sql = "INSERT INTO `user_preference` VALUES (-1, ?, ?)"; 470 $db_results = Dba::write($sql, $params); 471 if (!$db_results) { 472 return false; 473 } 474 if ($category !== "system") { 475 $sql = "INSERT INTO `user_preference` SELECT `user`.`id`, ?, ? FROM `user`"; 476 $db_results = Dba::write($sql, $params); 477 if (!$db_results) { 478 return false; 479 } 480 } 481 482 return true; 483 } // insert 484 485 /** 486 * delete 487 * This deletes the specified preference, a name or a ID can be passed 488 * @param string|integer $preference 489 */ 490 public static function delete($preference) 491 { 492 // First prepare 493 if (!is_numeric($preference)) { 494 $sql = "DELETE FROM `preference` WHERE `name` = ?"; 495 } else { 496 $sql = "DELETE FROM `preference` WHERE `id` = ?"; 497 } 498 499 Dba::write($sql, array($preference)); 500 501 self::clean_preferences(); 502 } // delete 503 504 /** 505 * rename 506 * This renames a preference in the database 507 * @param $old 508 * @param $new 509 */ 510 public static function rename($old, $new) 511 { 512 $sql = "UPDATE `preference` SET `name` = ? WHERE `name` = ?"; 513 Dba::write($sql, array($new, $old)); 514 } 515 516 /** 517 * clean_preferences 518 * This removes any garbage 519 */ 520 public static function clean_preferences() 521 { 522 // First remove garbage 523 $sql = "DELETE FROM `user_preference` USING `user_preference` LEFT JOIN `preference` ON `preference`.`id`=`user_preference`.`preference` WHERE `preference`.`id` IS NULL"; 524 Dba::write($sql); 525 } // rebuild_preferences 526 527 /** 528 * fix_preferences 529 * This takes the preferences, explodes what needs to 530 * become an array and boolean everything 531 * @param $results 532 * @return array 533 */ 534 public static function fix_preferences($results) 535 { 536 $arrays = array( 537 'auth_methods', 538 'getid3_tag_order', 539 'metadata_order', 540 'metadata_order_video', 541 'art_order', 542 'registration_display_fields', 543 'registration_mandatory_fields' 544 ); 545 546 foreach ($arrays as $item) { 547 $results[$item] = (trim((string)$results[$item])) ? explode(',', $results[$item]) : array(); 548 } 549 550 foreach ($results as $key => $data) { 551 if (!is_array($data)) { 552 if (strcasecmp((string)$data, "true") == "0") { 553 $results[$key] = 1; 554 } 555 if (strcasecmp((string)$data, "false") == "0") { 556 $results[$key] = 0; 557 } 558 } 559 } 560 561 return $results; 562 } // fix_preferences 563 564 /** 565 * set_defaults 566 * Make sure the default prefs are set! 567 */ 568 public static function set_defaults() 569 { 570 $sql = "INSERT IGNORE INTO `preference` (`id`, `name`, `value`, `description`, `level`, `type`, `catagory`, `subcatagory`) VALUES " . 571 "(1, 'download', '1', 'Allow Downloads', 100, 'boolean', 'options', 'feature'), " . 572 "(4, 'popular_threshold', '10', 'Popular Threshold', 25, 'integer', 'interface', 'query'), " . 573 "(19, 'transcode_bitrate', '128', 'Transcode Bitrate', 25, 'string', 'streaming', 'transcoding'), " . 574 "(22, 'site_title', 'Ampache :: For the Love of Music', 'Website Title', 100, 'string', 'interface', 'custom'), " . 575 "(23, 'lock_songs', '0', 'Lock Songs', 100, 'boolean', 'system', null), " . 576 "(24, 'force_http_play', '0', 'Force HTTP playback regardless of port', 100, 'boolean', 'system', null), " . 577 "(29, 'play_type', 'web_player', 'Playback Type', 25, 'special', 'streaming', null), " . 578 "(31, 'lang', 'en_US', 'Language', 100, 'special', 'interface', null), " . 579 "(32, 'playlist_type', 'm3u', 'Playlist Type', 100, 'special', 'playlist', null), " . 580 "(33, 'theme_name', 'reborn', 'Theme', 0, 'special', 'interface', 'theme'), " . 581 "(40, 'localplay_level', '0', 'Localplay Access', 100, 'special', 'options', 'localplay'), " . 582 "(41, 'localplay_controller', '0', 'Localplay Type', 100, 'special', 'options', 'localplay'), " . 583 "(44, 'allow_stream_playback', '1', 'Allow Streaming', 100, 'boolean', 'options', 'feature'), " . 584 "(45, 'allow_democratic_playback', '0', 'Allow Democratic Play', 100, 'boolean', 'options', 'feature'), " . 585 "(46, 'allow_localplay_playback', '0', 'Allow Localplay Play', 100, 'boolean', 'options', 'localplay'), " . 586 "(47, 'stats_threshold', '7', 'Statistics Day Threshold', 25, 'integer', 'interface', 'query'), " . 587 "(51, 'offset_limit', '50', 'Offset Limit', 5, 'integer', 'interface', 'query'), " . 588 "(52, 'rate_limit', '8192', 'Rate Limit', 100, 'integer', 'streaming', 'transcoding'), " . 589 "(53, 'playlist_method', 'default', 'Playlist Method', 5, 'string', 'playlist', null), " . 590 "(55, 'transcode', 'default', 'Allow Transcoding', 25, 'string', 'streaming', 'transcoding'), " . 591 "(69, 'show_lyrics', '0', 'Show lyrics', 0, 'boolean', 'interface', 'player'), " . 592 "(70, 'mpd_active', '0', 'MPD Active Instance', 25, 'integer', 'internal', 'mpd'), " . 593 "(71, 'httpq_active', '0', 'httpQ Active Instance', 25, 'integer', 'internal', 'httpq'), " . 594 "(77, 'lastfm_grant_link', '', 'Last.FM Grant URL', 25, 'string', 'internal', 'lastfm'), " . 595 "(78, 'lastfm_challenge', '', 'Last.FM Submit Challenge', 25, 'string', 'internal', 'lastfm'), " . 596 "(82, 'now_playing_per_user', '1', 'Now Playing filtered per user', 50, 'boolean', 'interface', 'home'), " . 597 "(83, 'album_sort', '0', 'Album - Default sort', 25, 'string', 'interface', 'library'), " . 598 "(84, 'show_played_times', '0', 'Show # played', 25, 'string', 'interface', 'browse'), " . 599 "(85, 'song_page_title', '1', 'Show current song in Web player page title', 25, 'boolean', 'interface', 'player'), " . 600 "(86, 'subsonic_backend', '1', 'Use Subsonic backend', 100, 'boolean', 'system', 'backend'), " . 601 "(88, 'webplayer_flash', '1', 'Authorize Flash Web Player', 25, 'boolean', 'streaming', 'player'), " . 602 "(89, 'webplayer_html5', '1', 'Authorize HTML5 Web Player', 25, 'boolean', 'streaming', 'player'), " . 603 "(90, 'allow_personal_info_now', '1', 'Share Now Playing information', 25, 'boolean', 'interface', 'privacy'), " . 604 "(91, 'allow_personal_info_recent', '1', 'Share Recently Played information', 25, 'boolean', 'interface', 'privacy'), " . 605 "(92, 'allow_personal_info_time', '1', 'Share Recently Played information - Allow access to streaming date/time', 25, 'boolean', 'interface', 'privacy'), " . 606 "(93, 'allow_personal_info_agent', '1', 'Share Recently Played information - Allow access to streaming agent', 25, 'boolean', 'interface', 'privacy'), " . 607 "(94, 'ui_fixed', '0', 'Fix header position on compatible themes', 25, 'boolean', 'interface', 'theme'), " . 608 "(95, 'autoupdate', '1', 'Check for Ampache updates automatically', 25, 'boolean', 'system', 'update'), " . 609 "(96, 'autoupdate_lastcheck', '', 'AutoUpdate last check time', 25, 'string', 'internal', 'update'), " . 610 "(97, 'autoupdate_lastversion', '', 'AutoUpdate last version from last check', 25, 'string', 'internal', 'update'), " . 611 "(98, 'autoupdate_lastversion_new', '', 'AutoUpdate last version from last check is newer', 25, 'boolean', 'internal', 'update'), " . 612 "(99, 'webplayer_confirmclose', '0', 'Confirmation when closing current playing window', 25, 'boolean', 'interface', 'player'), " . 613 "(100, 'webplayer_pausetabs', '1', 'Auto-pause between tabs', 25, 'boolean', 'interface', 'player'), " . 614 "(101, 'stream_beautiful_url', '0', 'Enable URL Rewriting', 100, 'boolean', 'streaming', null), " . 615 "(102, 'share', '0', 'Allow Share', 100, 'boolean', 'options', 'feature'), " . 616 "(103, 'share_expire', '7', 'Share links default expiration days (0=never)', 100, 'integer', 'system', 'share'), " . 617 "(104, 'slideshow_time', '0', 'Artist slideshow inactivity time', 25, 'integer', 'interface', 'player'), " . 618 "(105, 'broadcast_by_default', '0', 'Broadcast web player by default', 25, 'boolean', 'streaming', 'player'), " . 619 "(108, 'album_group', '1', 'Album - Group multiple disks', 25, 'boolean', 'interface', 'library'), " . 620 "(109, 'topmenu', '0', 'Top menu', 25, 'boolean', 'interface', 'theme'), " . 621 "(110, 'demo_clear_sessions', '0', 'Democratic - Clear votes for expired user sessions', 25, 'boolean', 'playlist', null), " . 622 "(111, 'show_donate', '1', 'Show donate button in footer', 25, 'boolean', 'interface', null), " . 623 "(112, 'upload_catalog', '-1', 'Destination catalog', 75, 'integer', 'system', 'upload'), " . 624 "(113, 'allow_upload', '0', 'Allow user uploads', 75, 'boolean', 'system', 'upload'), " . 625 "(114, 'upload_subdir', '1', 'Create a subdirectory per user', 75, 'boolean', 'system', 'upload'), " . 626 "(115, 'upload_user_artist', '0', 'Consider the user sender as the track''s artist', 75, 'boolean', 'system', 'upload'), " . 627 "(116, 'upload_script', '', 'Post-upload script (current directory = upload target directory)', 75, 'string', 'system', 'upload'), " . 628 "(117, 'upload_allow_edit', '1', 'Allow users to edit uploaded songs', 75, 'boolean', 'system', 'upload'), " . 629 "(118, 'daap_backend', '0', 'Use DAAP backend', 100, 'boolean', 'system', 'backend'), " . 630 "(119, 'daap_pass', '', 'DAAP backend password', 100, 'string', 'system', 'backend'), " . 631 "(120, 'upnp_backend', '0', 'Use UPnP backend', 100, 'boolean', 'system', 'backend'), " . 632 "(121, 'allow_video', '0', 'Allow Video Features', 75, 'integer', 'options', 'feature'), " . 633 "(122, 'album_release_type', '1', 'Album - Group per release type', 25, 'boolean', 'interface', 'library'), " . 634 "(123, 'ajax_load', '1', 'Ajax page load', 25, 'boolean', 'interface', null), " . 635 "(124, 'direct_play_limit', '0', 'Limit direct play to maximum media count', 25, 'integer', 'interface', 'player'), " . 636 "(125, 'home_moment_albums', '1', 'Show Albums of the Moment', 25, 'integer', 'interface', 'home'), " . 637 "(126, 'home_moment_videos', '0', 'Show Videos of the Moment', 25, 'integer', 'interface', 'home'), " . 638 "(127, 'home_recently_played', '1', 'Show Recently Played', 25, 'integer', 'interface', 'home'), " . 639 "(128, 'home_now_playing', '1', 'Show Now Playing', 25, 'integer', 'interface', 'home'), " . 640 "(129, 'custom_logo', '', 'Custom URL - Logo', 25, 'string', 'interface', 'custom'), " . 641 "(130, 'album_release_type_sort', 'album,ep,live,single', 'Album - Group per release type sort', 25, 'string', 'interface', 'library'), " . 642 "(131, 'browser_notify', '1', 'Web Player browser notifications', 25, 'integer', 'interface', 'notification'), " . 643 "(132, 'browser_notify_timeout', '10', 'Web Player browser notifications timeout (seconds)', 25, 'integer', 'interface', 'notification'), " . 644 "(133, 'geolocation', '0', 'Allow Geolocation', 25, 'integer', 'options', 'feature'), " . 645 "(134, 'webplayer_aurora', '1', 'Authorize JavaScript decoder (Aurora.js) in Web Player', 25, 'boolean', 'streaming', 'player'), " . 646 "(135, 'upload_allow_remove', '1', 'Allow users to remove uploaded songs', 75, 'boolean', 'system', 'upload'), " . 647 "(136, 'custom_login_logo', '', 'Custom URL - Login page logo', 75, 'string', 'interface', 'custom'), " . 648 "(137, 'custom_favicon', '', 'Custom URL - Favicon', 75, 'string', 'interface', 'custom'), " . 649 "(138, 'custom_text_footer', '', 'Custom text footer', 75, 'string', 'interface', 'custom'), " . 650 "(139, 'webdav_backend', '0', 'Use WebDAV backend', 100, 'boolean', 'system', 'backend'), " . 651 "(140, 'notify_email', '0', 'Allow E-mail notifications', 25, 'boolean', 'options', null), " . 652 "(141, 'theme_color', 'dark', 'Theme color', 0, 'special', 'interface', 'theme'), " . 653 "(142, 'disabled_custom_metadata_fields', '', 'Custom metadata - Disable these fields', 100, 'string', 'system', 'metadata'), " . 654 "(143, 'disabled_custom_metadata_fields_input', '', 'Custom metadata - Define field list', 100, 'string', 'system', 'metadata'), " . 655 "(144, 'podcast_keep', '0', '# latest episodes to keep', 100, 'integer', 'system', 'podcast'), " . 656 "(145, 'podcast_new_download', '0', '# episodes to download when new episodes are available', 100, 'integer', 'system', 'podcast'), " . 657 "(146, 'libitem_contextmenu', '1', 'Library item context menu', 0, 'boolean', 'interface', 'library'), " . 658 "(147, 'upload_catalog_pattern', '0', 'Rename uploaded file according to catalog pattern', 100, 'boolean', 'system', 'upload'), " . 659 "(148, 'catalog_check_duplicate', '0', 'Check library item at import time and don\'t import duplicates', 100, 'boolean', 'system', 'catalog'), " . 660 "(149, 'browse_filter', '0', 'Show filter box on browse', 25, 'boolean', 'interface', 'browse'), " . 661 "(150, 'sidebar_light', '0', 'Light sidebar by default', 25, 'boolean', 'interface', 'theme'), " . 662 "(151, 'custom_blankalbum', '', 'Custom blank album default image', 75, 'string', 'interface', 'custom'), " . 663 "(152, 'custom_blankmovie', '', 'Custom blank video default image', 75, 'string', 'interface', 'custom'), " . 664 "(153, 'libitem_browse_alpha', '', 'Alphabet browsing by default for following library items (album,artist,...)', 75, 'string', 'interface', 'browse'), " . 665 "(154, 'show_skipped_times', '0', 'Show # skipped', 25, 'boolean', 'interface', 'browse'), " . 666 "(155, 'custom_datetime', '', 'Custom datetime', 25, 'string', 'interface', 'custom'), " . 667 "(156, 'cron_cache', '0', 'Cache computed SQL data (eg. media hits stats) using a cron', 25, 'boolean', 'system', 'catalog'), " . 668 "(157, 'unique_playlist', '0', 'Only add unique items to playlists', 25, 'boolean', 'playlist', NULL), " . 669 "(158, 'show_license', '0', 'Show License', 25, 'boolean', 'interface', 'browse'), " . 670 "(159, 'use_original_year', '0', 'Browse by Original Year for albums (falls back to Year)', 25, 'boolean', 'interface', 'browse'), " . 671 "(160, 'hide_single_artist', '0', 'Hide the Song Artist column for Albums with one Artist', 25, 'boolean', 'interface', 'browse');"; 672 Dba::write($sql); 673 } // set_defaults 674 675 /** 676 * load_from_session 677 * This loads the preferences from the session rather then creating a connection to the database 678 * @param integer $uid 679 * @return boolean 680 */ 681 public static function load_from_session($uid = -1) 682 { 683 if (isset($_SESSION['userdata']['preferences']) && is_array($_SESSION['userdata']['preferences']) && $_SESSION['userdata']['uid'] == $uid) { 684 AmpConfig::set_by_array($_SESSION['userdata']['preferences'], true); 685 686 return true; 687 } 688 689 return false; 690 } // load_from_session 691 692 /** 693 * clear_from_session 694 * This clears the users preferences, this is done whenever modifications are made to the preferences 695 * or the admin resets something 696 */ 697 public static function clear_from_session() 698 { 699 unset($_SESSION['userdata']['preferences']); 700 } // clear_from_session 701 702 /** 703 * is_boolean 704 * This returns true / false if the preference in question is a boolean preference 705 * This is currently only used by the debug view, could be used other places.. wouldn't be a half 706 * bad idea 707 * @param $key 708 * @return boolean 709 */ 710 public static function is_boolean($key) 711 { 712 $boolean_array = array( 713 'session_cookiesecure', 714 'require_session', 715 'access_control', 716 'require_localnet_session', 717 'downsample_remote', 718 'track_user_ip', 719 'xml_rpc', 720 'allow_zip_download', 721 'ratings', 722 'shoutbox', 723 'resize_images', 724 'show_played_times', 725 'show_skipped_times', 726 'show_album_art', 727 'allow_public_registration', 728 'captcha_public_reg', 729 'admin_notify_reg', 730 'use_rss', 731 'download', 732 'force_http_play', 733 'cookie_secure', 734 'allow_stream_playback', 735 'allow_democratic_playback', 736 'use_auth', 737 'allow_localplay_playback', 738 'debug', 739 'lock_songs', 740 'transcode_m4a', 741 'transcode_mp3', 742 'transcode_ogg', 743 'transcode_flac', 744 'httpq_active', 745 'show_lyrics' 746 ); 747 748 if (in_array($key, $boolean_array)) { 749 return true; 750 } 751 752 return false; 753 } // is_boolean 754 755 /** 756 * init 757 * This grabs the preferences and then loads them into conf it should be run on page load 758 * to initialize the needed variables 759 * @return boolean 760 */ 761 public static function init() 762 { 763 $user_id = Core::get_global('user')->id ? (int)(Core::get_global('user')->id) : -1; 764 765 // First go ahead and try to load it from the preferences 766 if (self::load_from_session($user_id)) { 767 return true; 768 } 769 770 /* Get Global Preferences */ 771 $sql = "SELECT `preference`.`name`, `user_preference`.`value`, `syspref`.`value` AS `system_value` FROM `preference` LEFT JOIN `user_preference` `syspref` ON `syspref`.`preference`=`preference`.`id` AND `syspref`.`user`='-1' AND `preference`.`catagory`='system' LEFT JOIN `user_preference` ON `user_preference`.`preference`=`preference`.`id` AND `user_preference`.`user` = ? AND `preference`.`catagory`!='system'"; 772 $db_results = Dba::read($sql, array($user_id)); 773 774 $results = array(); 775 while ($row = Dba::fetch_assoc($db_results)) { 776 $value = $row['system_value'] ? $row['system_value'] : $row['value']; 777 $name = $row['name']; 778 $results[$name] = $value; 779 } // end while sys prefs 780 781 /* Set the Theme mojo */ 782 if (strlen((string)$results['theme_name']) > 0) { 783 // In case the theme was removed 784 if (!Core::is_readable(__DIR__ . '/../../public/themes/' . $results['theme_name'])) { 785 unset($results['theme_name']); 786 } 787 } else { 788 unset($results['theme_name']); 789 } 790 // Default theme if we don't get anything from their 791 // preferences because we're going to want at least something otherwise 792 // the page is going to be really ugly 793 if (!isset($results['theme_name'])) { 794 $results['theme_name'] = 'reborn'; 795 } 796 $results['theme_path'] = '/themes/' . $results['theme_name']; 797 798 // Load theme settings 799 $themecfg = get_theme($results['theme_name']); 800 $results['theme_css_base'] = $themecfg['base']; 801 802 if (strlen((string)$results['theme_color']) > 0) { 803 // In case the color was removed 804 if (!Core::is_readable(__DIR__ . '/../../../public/themes/' . $results['theme_name'] . '/templates/' . $results['theme_color'] . '.css')) { 805 unset($results['theme_color']); 806 } 807 } else { 808 unset($results['theme_color']); 809 } 810 if (!isset($results['theme_color'])) { 811 $results['theme_color'] = strtolower((string)$themecfg['colors'][0]); 812 } 813 814 AmpConfig::set_by_array($results, true); 815 $_SESSION['userdata']['preferences'] = $results; 816 $_SESSION['userdata']['uid'] = $user_id; 817 818 return true; 819 } // init 820} 821