mirror of
https://github.com/Yetangitu/ampache
synced 2025-10-03 17:59:21 +02:00
1300 lines
40 KiB
PHP
1300 lines
40 KiB
PHP
<?php
|
|
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
|
|
/**
|
|
*
|
|
* LICENSE: GNU General Public License, version 2 (GPLv2)
|
|
* Copyright 2001 - 2013 Ampache.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License v2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* User Class
|
|
*
|
|
* This class handles all of the user related functions includingn the creationg
|
|
* and deletion of the user objects from the database by defualt you constrcut it
|
|
* with a user_id from user.id
|
|
*
|
|
*/
|
|
class User extends database_object
|
|
{
|
|
//Basic Componets
|
|
public $id;
|
|
public $username;
|
|
public $fullname;
|
|
public $access;
|
|
public $disabled;
|
|
public $email;
|
|
public $last_seen;
|
|
public $create_date;
|
|
public $validation;
|
|
public $website;
|
|
public $apikey;
|
|
|
|
// Constructed variables
|
|
public $prefs = array();
|
|
|
|
/**
|
|
* Constructor
|
|
* This function is the constructor object for the user
|
|
* class, it currently takes a username
|
|
*/
|
|
public function __construct($user_id=0)
|
|
{
|
|
if (!$user_id) { return false; }
|
|
|
|
$this->id = intval($user_id);
|
|
|
|
$info = $this->_get_info();
|
|
|
|
foreach ($info as $key=>$value) {
|
|
// Let's not save the password in this object :S
|
|
if ($key == 'password') { continue; }
|
|
$this->$key = $value;
|
|
}
|
|
|
|
// Make sure the Full name is always filled
|
|
if (strlen($this->fullname) < 1) { $this->fullname = $this->username; }
|
|
|
|
} // Constructor
|
|
|
|
/**
|
|
* count
|
|
*
|
|
* This returns the number of user accounts that exist.
|
|
*/
|
|
public static function count()
|
|
{
|
|
$sql = 'SELECT COUNT(`id`) FROM `user`';
|
|
$db_results = Dba::read($sql);
|
|
$data = Dba::fetch_row($db_results);
|
|
$results['users'] = $data[0];
|
|
|
|
$time = time();
|
|
$last_seen = $time - 1200;
|
|
$sql = 'SELECT COUNT(DISTINCT `session`.`username`) FROM `session` ' .
|
|
'INNER JOIN `user` ON `session`.`username` = `user`.`username` ' .
|
|
'WHERE `session`.`expire` > ? and `user`.`last_seen` > ?';
|
|
$db_results = Dba::read($sql, array($time, $last_seen));
|
|
$data = Dba::fetch_row($db_results);
|
|
$results['connected'] = $data[0];
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* _get_info
|
|
* This function returns the information for this object
|
|
*/
|
|
private function _get_info()
|
|
{
|
|
$id = intval($this->id);
|
|
|
|
if (parent::is_cached('user',$id)) {
|
|
return parent::get_from_cache('user',$id);
|
|
}
|
|
|
|
// If the ID is -1 then
|
|
if ($id == '-1') {
|
|
$data['username'] = 'System';
|
|
$data['fullname'] = 'Ampache User';
|
|
$data['access'] = '25';
|
|
return $data;
|
|
}
|
|
|
|
$sql = "SELECT * FROM `user` WHERE `id`='$id'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
$data = Dba::fetch_assoc($db_results);
|
|
|
|
parent::add_to_cache('user',$id,$data);
|
|
|
|
return $data;
|
|
|
|
} // _get_info
|
|
|
|
/**
|
|
* load_playlist
|
|
* This is called once per page load it makes sure that this session
|
|
* has a tmp_playlist, creating it if it doesn't, then sets $this->playlist
|
|
* as a tmp_playlist object that can be fiddled with later on
|
|
*/
|
|
public function load_playlist()
|
|
{
|
|
$session_id = session_id();
|
|
|
|
$this->playlist = Tmp_Playlist::get_from_session($session_id);
|
|
|
|
} // load_playlist
|
|
|
|
/**
|
|
* get_valid_users
|
|
* This returns all valid users in database.
|
|
*/
|
|
public static function get_valid_users()
|
|
{
|
|
$users = array();
|
|
|
|
$sql = "SELECT `id` FROM `user` WHERE `disabled` = '0'";
|
|
$db_results = Dba::read($sql);
|
|
while ($results = Dba::fetch_assoc($db_results)) {
|
|
$users[] = $results['id'];
|
|
}
|
|
|
|
return $users;
|
|
} // get_valid_users
|
|
|
|
/**
|
|
* get_from_username
|
|
* This returns a built user from a username. This is a
|
|
* static function so it doesn't require an instance
|
|
*/
|
|
public static function get_from_username($username)
|
|
{
|
|
$sql = "SELECT `id` FROM `user` WHERE `username` = ?";
|
|
$db_results = Dba::read($sql, array($username));
|
|
$results = Dba::fetch_assoc($db_results);
|
|
|
|
$user = new User($results['id']);
|
|
|
|
return $user;
|
|
|
|
} // get_from_username
|
|
|
|
/**
|
|
* get_from_apikey
|
|
* This returns a built user from an apikey. This is a
|
|
* static function so it doesn't require an instance
|
|
*/
|
|
public static function get_from_apikey($apikey)
|
|
{
|
|
$user = null;
|
|
$apikey = trim($apikey);
|
|
if (!empty($apikey)) {
|
|
$sql = "SELECT `id` FROM `user` WHERE `apikey` = ?";
|
|
$db_results = Dba::read($sql, array($apikey));
|
|
$results = Dba::fetch_assoc($db_results);
|
|
|
|
if ($results['id']) {
|
|
$user = new User($results['id']);
|
|
}
|
|
}
|
|
|
|
return $user;
|
|
|
|
} // get_from_apikey
|
|
|
|
/**
|
|
* get_from_email
|
|
* This returns a built user from a email. This is a
|
|
* static function so it doesn't require an instance
|
|
*/
|
|
public static function get_from_email($email)
|
|
{
|
|
$sql = "SELECT `id` FROM `user` WHERE `email` = ?";
|
|
$db_results = Dba::read($sql, array($email));
|
|
if ($results = Dba::fetch_assoc($db_results)) {
|
|
$user = new User($results['id']);
|
|
}
|
|
|
|
return $user;
|
|
|
|
} // get_from_email
|
|
|
|
/**
|
|
* get_from_website
|
|
* This returns users list related to a website.
|
|
*/
|
|
public static function get_from_website($website)
|
|
{
|
|
$website = rtrim($website, "/");
|
|
$sql = "SELECT `id` FROM `user` WHERE `website` = ? LIMIT 1";
|
|
$db_results = Dba::read($sql, array($website));
|
|
$users = array();
|
|
while ($results = Dba::fetch_assoc($db_results)) {
|
|
$users[] = $results['id'];
|
|
}
|
|
return $users;
|
|
|
|
} // get_from_website
|
|
|
|
/**
|
|
* get_catalogs
|
|
* This returns the catalogs as an array of ids that this user is allowed to access
|
|
*/
|
|
public function get_catalogs()
|
|
{
|
|
if (parent::is_cached('user_catalog',$this->id)) {
|
|
return parent::get_from_cache('user_catalog',$this->id);
|
|
}
|
|
|
|
$sql = "SELECT * FROM `user_catalog` WHERE `user`='$user_id'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
while ($row = Dba::fetch_assoc($db_results)) {
|
|
$catalogs[] = $row['catalog'];
|
|
}
|
|
|
|
parent::add_to_cache('user_catalog',$this->id,$catalogs);
|
|
|
|
return $catalogs;
|
|
|
|
} // get_catalogs
|
|
|
|
/**
|
|
* get_preferences
|
|
* This is a little more complicate now that we've got many types of preferences
|
|
* This funtions pulls all of them an arranges them into a spiffy little array
|
|
* You can specify a type to limit it to a single type of preference
|
|
* []['title'] = ucased type name
|
|
* []['prefs'] = array(array('name','display','value'));
|
|
* []['admin'] = t/f value if this is an admin only section
|
|
*/
|
|
public function get_preferences($type = 0, $system = false)
|
|
{
|
|
// Fill out the user id
|
|
$user_id = $system ? Dba::escape(-1) : Dba::escape($this->id);
|
|
|
|
if (!$system) {
|
|
$user_limit = "AND preference.catagory != 'system'";
|
|
}
|
|
|
|
if ($type != '0') {
|
|
$user_limit = "AND preference.catagory = '" . Dba::escape($type) . "'";
|
|
}
|
|
|
|
|
|
$sql = "SELECT preference.name, preference.description, preference.catagory, preference.level, user_preference.value " .
|
|
"FROM preference INNER JOIN user_preference ON user_preference.preference=preference.id " .
|
|
"WHERE user_preference.user='$user_id' " . $user_limit .
|
|
" ORDER BY preference.catagory, preference.description";
|
|
|
|
$db_results = Dba::read($sql);
|
|
|
|
/* Ok this is crapy, need to clean this up or improve the code FIXME */
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$type = $r['catagory'];
|
|
$admin = false;
|
|
if ($type == 'system') { $admin = true; }
|
|
$type_array[$type][$r['name']] = array('name'=>$r['name'],'level'=>$r['level'],'description'=>$r['description'],'value'=>$r['value']);
|
|
$results[$type] = array ('title'=>ucwords($type),'admin'=>$admin,'prefs'=>$type_array[$type]);
|
|
} // end while
|
|
|
|
return $results;
|
|
|
|
} // get_preferences
|
|
|
|
/**
|
|
* set_preferences
|
|
* sets the prefs for this specific user
|
|
*/
|
|
public function set_preferences()
|
|
{
|
|
$user_id = Dba::escape($this->id);
|
|
|
|
$sql = "SELECT preference.name,user_preference.value FROM preference,user_preference WHERE user_preference.user='$user_id' " .
|
|
"AND user_preference.preference=preference.id AND preference.type != 'system'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$key = $r['name'];
|
|
$this->prefs[$key] = $r['value'];
|
|
}
|
|
} // set_preferences
|
|
|
|
/**
|
|
* get_favorites
|
|
* returns an array of your $type favorites
|
|
*/
|
|
public function get_favorites($type)
|
|
{
|
|
$web_path = AmpConfig::get('web_path');
|
|
|
|
$results = Stats::get_user(AmpConfig::get('popular_threshold'),$type,$this->id,1);
|
|
|
|
$items = array();
|
|
|
|
foreach ($results as $r) {
|
|
/* If its a song */
|
|
if ($type == 'song') {
|
|
$data = new Song($r['object_id']);
|
|
$data->count = $r['count'];
|
|
$data->format();
|
|
$data->f_name = $data->f_link;
|
|
$items[] = $data;
|
|
}
|
|
/* If its an album */
|
|
elseif ($type == 'album') {
|
|
$data = new Album($r['object_id']);
|
|
$data->count = $r['count'];
|
|
$data->format();
|
|
$items[] = $data;
|
|
}
|
|
/* If its an artist */
|
|
elseif ($type == 'artist') {
|
|
$data = new Artist($r['object_id']);
|
|
$data->count = $r['count'];
|
|
$data->format();
|
|
$data->f_name = $data->f_link;
|
|
$items[] = $data;
|
|
}
|
|
/* If it's a genre */
|
|
elseif ($type == 'genre') {
|
|
$data = new Genre($r['object_id']);
|
|
$data->count = $r['count'];
|
|
$data->format();
|
|
$data->f_name = $data->f_link;
|
|
$items[] = $data;
|
|
}
|
|
|
|
} // end foreach
|
|
|
|
return $items;
|
|
|
|
} // get_favorites
|
|
|
|
/**
|
|
* get_recommendations
|
|
* This returns recommended objects of $type. The recommendations
|
|
* are based on voodoo economics,the phase of the moon and my current BAL.
|
|
*/
|
|
public function get_recommendations($type)
|
|
{
|
|
/* First pull all of your ratings of this type */
|
|
$sql = "SELECT object_id,user_rating FROM ratings " .
|
|
"WHERE object_type='" . Dba::escape($type) . "' AND user='" . Dba::escape($this->id) . "'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
// Incase they only have one user
|
|
$users = array();
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
/* Store the fact that you rated this */
|
|
$key = $r['object_id'];
|
|
$ratings[$key] = true;
|
|
|
|
/* Build a key'd array of users with this same rating */
|
|
$sql = "SELECT user FROM ratings WHERE object_type='" . Dba::escape($type) . "' " .
|
|
"AND user !='" . Dba::escape($this->id) . "' AND object_id='" . Dba::escape($r['object_id']) . "' " .
|
|
"AND user_rating ='" . Dba::escape($r['user_rating']) . "'";
|
|
$user_results = Dba::read($sql);
|
|
|
|
while ($user_info = Dba::fetch_assoc($user_results)) {
|
|
$key = $user_info['user'];
|
|
$users[$key]++;
|
|
}
|
|
|
|
} // end while
|
|
|
|
/* now we've got your ratings, and all users and the # of ratings that match your ratings
|
|
* sort the users[$key] array by value and then find things they've rated high (4+) that you
|
|
* haven't rated
|
|
*/
|
|
$recommendations = array();
|
|
asort($users);
|
|
|
|
foreach ($users as $user_id=>$score) {
|
|
|
|
/* Find everything they've rated at 4+ */
|
|
$sql = "SELECT object_id,user_rating FROM ratings " .
|
|
"WHERE user='" . Dba::escape($user_id) . "' AND user_rating >='4' AND " .
|
|
"object_type = '" . Dba::escape($type) . "' ORDER BY user_rating DESC";
|
|
$db_results = Dba::read($sql);
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$key = $r['object_id'];
|
|
if (isset($ratings[$key])) { continue; }
|
|
|
|
/* Let's only get 5 total for now */
|
|
if (count($recommendations) > 5) { return $recommendations; }
|
|
|
|
$recommendations[$key] = $r['user_rating'];
|
|
|
|
} // end while
|
|
|
|
|
|
} // end foreach users
|
|
|
|
return $recommendations;
|
|
|
|
} // get_recommendations
|
|
|
|
/**
|
|
* is_logged_in
|
|
* checks to see if $this user is logged in returns their current IP if they
|
|
* are logged in
|
|
*/
|
|
public function is_logged_in()
|
|
{
|
|
$username = Dba::escape($this->username);
|
|
|
|
$sql = "SELECT `id`,`ip` FROM `session` WHERE `username`='$username'" .
|
|
" AND `expire` > ". time();
|
|
$db_results = Dba::read($sql);
|
|
|
|
if ($row = Dba::fetch_assoc($db_results)) {
|
|
$ip = $row['ip'] ? $row['ip'] : NULL;
|
|
return $ip;
|
|
}
|
|
|
|
return false;
|
|
|
|
} // is_logged_in
|
|
|
|
/**
|
|
* has_access
|
|
* this function checkes to see if this user has access
|
|
* to the passed action (pass a level requirement)
|
|
*/
|
|
public function has_access($needed_level)
|
|
{
|
|
if (!AmpConfig::get('use_auth') || AmpConfig::get('demo_mode')) { return true; }
|
|
|
|
if ($this->access >= $needed_level) { return true; }
|
|
|
|
return false;
|
|
|
|
} // has_access
|
|
|
|
/**
|
|
* update
|
|
* This function is an all encompasing update function that
|
|
* calls the mini ones does all the error checking and all that
|
|
* good stuff
|
|
*/
|
|
public function update($data)
|
|
{
|
|
if (empty($data['username'])) {
|
|
Error::add('username', T_('Error Username Required'));
|
|
}
|
|
|
|
if ($data['password1'] != $data['password2'] AND !empty($data['password1'])) {
|
|
Error::add('password', T_("Error Passwords don't match"));
|
|
}
|
|
|
|
if (Error::occurred()) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($data as $name => $value) {
|
|
if ($name == 'password1') {
|
|
$name = 'password';
|
|
} else {
|
|
$value = scrub_in($value);
|
|
}
|
|
|
|
switch ($name) {
|
|
case 'password';
|
|
case 'access':
|
|
case 'email':
|
|
case 'username':
|
|
case 'fullname':
|
|
case 'website':
|
|
if ($this->$name != $value) {
|
|
$function = 'update_' . $name;
|
|
$this->$function($value);
|
|
}
|
|
break;
|
|
default:
|
|
// Rien a faire
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* update_username
|
|
* updates their username
|
|
*/
|
|
public function update_username($new_username)
|
|
{
|
|
$sql = "UPDATE `user` SET `username` = ? WHERE `id` = ?";
|
|
$this->username = $new_username;
|
|
$db_results = Dba::write($sql, array($new_username, $this->id));
|
|
|
|
} // update_username
|
|
|
|
/**
|
|
* update_validation
|
|
* This is used by the registration mumbojumbo
|
|
* Use this function to update the validation key
|
|
* NOTE: crap this doesn't have update_item the humanity of it all
|
|
*/
|
|
public function update_validation($new_validation)
|
|
{
|
|
$sql = "UPDATE `user` SET `validation` = ?, `disabled`='1' WHERE `id` = ?";
|
|
$db_results = Dba::write($sql, array($new_validation, $this->id));
|
|
$this->validation = $new_validation;
|
|
|
|
return $db_results;
|
|
|
|
} // update_validation
|
|
|
|
/**
|
|
* update_fullname
|
|
* updates their fullname
|
|
*/
|
|
public function update_fullname($new_fullname)
|
|
{
|
|
$sql = "UPDATE `user` SET `fullname` = ? WHERE `id` = ?";
|
|
$db_results = Dba::write($sql, array($new_fullname, $this->id));
|
|
|
|
} // update_fullname
|
|
|
|
/**
|
|
* update_email
|
|
* updates their email address
|
|
*/
|
|
public function update_email($new_email)
|
|
{
|
|
$sql = "UPDATE `user` SET `email` = ? WHERE `id` = ?";
|
|
$db_results = Dba::write($sql, array($new_email, $this->id));
|
|
|
|
} // update_email
|
|
|
|
/**
|
|
* update_website
|
|
* updates their website address
|
|
*/
|
|
public function update_website($new_website)
|
|
{
|
|
$new_website = rtrim($new_website, "/");
|
|
$sql = "UPDATE `user` SET `website` = ? WHERE `id` = ?";
|
|
$db_results = Dba::write($sql, array($new_website, $this->id));
|
|
|
|
} // update_website
|
|
|
|
/**
|
|
* update_apikey
|
|
* Updates their api key
|
|
*/
|
|
public function update_apikey($new_apikey)
|
|
{
|
|
$sql = "UPDATE `user` SET `apikey` = ? WHERE `id` = ?";
|
|
$db_results = Dba::write($sql, array($new_apikey, $this->id));
|
|
|
|
} // update_website
|
|
|
|
/**
|
|
* generate_apikey
|
|
* Generate a new user API key
|
|
*/
|
|
public function generate_apikey()
|
|
{
|
|
$apikey = hash('md5', time() . $this->username . $this->get_password());
|
|
$this->update_apikey($apikey);
|
|
}
|
|
|
|
/**
|
|
* get_password
|
|
* Get the current hashed user password from database.
|
|
*/
|
|
public function get_password()
|
|
{
|
|
$sql = 'SELECT * FROM `user` WHERE `id` = ?';
|
|
$db_results = Dba::read($sql, array($this->id));
|
|
$row = Dba::fetch_assoc($db_results);
|
|
|
|
return $row['password'];
|
|
}
|
|
|
|
/**
|
|
* disable
|
|
* This disables the current user
|
|
*/
|
|
public function disable()
|
|
{
|
|
// Make sure we aren't disabling the last admin
|
|
$sql = "SELECT `id` FROM `user` WHERE `disabled` = '0' AND `id` != '" . $this->id . "' AND `access`='100'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
if (!Dba::num_rows($db_results)) { return false; }
|
|
|
|
$sql = "UPDATE `user` SET `disabled`='1' WHERE id='" . $this->id . "'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete any sessions they may have
|
|
$sql = "DELETE FROM `session` WHERE `username`='" . Dba::escape($this->username) . "'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
return true;
|
|
|
|
} // disable
|
|
|
|
/**
|
|
* enable
|
|
* this enables the current user
|
|
*/
|
|
public function enable()
|
|
{
|
|
$sql = "UPDATE `user` SET `disabled`='0' WHERE id='" . $this->id . "'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
return true;
|
|
|
|
} // enable
|
|
|
|
/**
|
|
* update_access
|
|
* updates their access level
|
|
*/
|
|
public function update_access($new_access)
|
|
{
|
|
/* Prevent Only User accounts */
|
|
if ($new_access < '100') {
|
|
$sql = "SELECT `id` FROM user WHERE `access`='100' AND `id` != '$this->id'";
|
|
$db_results = Dba::read($sql);
|
|
if (!Dba::num_rows($db_results)) { return false; }
|
|
}
|
|
|
|
$new_access = Dba::escape($new_access);
|
|
$sql = "UPDATE `user` SET `access`='$new_access' WHERE `id`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
} // update_access
|
|
|
|
/*!
|
|
@function update_last_seen
|
|
@discussion updates the last seen data for this user
|
|
*/
|
|
public function update_last_seen()
|
|
{
|
|
$sql = "UPDATE user SET last_seen='" . time() . "' WHERE `id`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
} // update_last_seen
|
|
|
|
/**
|
|
* update_user_stats
|
|
* updates the playcount mojo for this specific user
|
|
*/
|
|
public function update_stats($song_id, $agent = '')
|
|
{
|
|
debug_event('user.class.php', 'Updating stats for {'.$song_id.'} {'.$agent.'}...', '5');
|
|
$song_info = new Song($song_id);
|
|
$song_info->format();
|
|
$user = $this->id;
|
|
|
|
if (!strlen($song_info->file)) { return false; }
|
|
|
|
$this->set_preferences();
|
|
|
|
// If pthreads available, we call save_songplay in a new thread to quickly return
|
|
if (class_exists("Thread", false)) {
|
|
debug_event('user.class.php', 'Calling save_songplay plugins in a new thread...', '5');
|
|
$thread = new scrobbler_async($GLOBALS['user'], $song_info);
|
|
if ($thread->start()) {
|
|
//$thread->join();
|
|
} else {
|
|
debug_event('user.class.php', 'Error when starting the thread.', '1');
|
|
}
|
|
} else {
|
|
User::save_songplay($GLOBALS['user'], $song_info);
|
|
}
|
|
|
|
// Do this last so the 'last played checks are correct'
|
|
Stats::insert('song', $song_id, $user, $agent);
|
|
Stats::insert('album', $song_info->album, $user, $agent);
|
|
Stats::insert('artist', $song_info->artist, $user, $agent);
|
|
|
|
return true;
|
|
|
|
} // update_stats
|
|
|
|
public static function save_songplay($user, $song_info)
|
|
{
|
|
foreach (Plugin::get_plugins('save_songplay') as $plugin_name) {
|
|
try {
|
|
$plugin = new Plugin($plugin_name);
|
|
if ($plugin->load($user)) {
|
|
$plugin->_plugin->save_songplay($song_info);
|
|
}
|
|
} catch (Exeption $e) {
|
|
debug_event('user.class.php', 'Stats plugin error: ' . $e->getMessage(), '1');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* insert_ip_history
|
|
* This inserts a row into the IP History recording this user at this
|
|
* address at this time in this place, doing this thing.. you get the point
|
|
*/
|
|
public function insert_ip_history()
|
|
{
|
|
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
|
$sip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
|
debug_event('User Ip', 'Login from ip adress: ' . $sip,'3');
|
|
} else {
|
|
$sip = $_SERVER['REMOTE_ADDR'];
|
|
debug_event('User Ip', 'Login from ip adress: ' . $sip,'3');
|
|
}
|
|
|
|
$ip = Dba::escape(inet_pton($sip));
|
|
$date = time();
|
|
$user = $this->id;
|
|
$agent = Dba::escape($_SERVER['HTTP_USER_AGENT']);
|
|
|
|
$sql = "INSERT INTO `ip_history` (`ip`,`user`,`date`,`agent`) VALUES ('$ip','$user','$date','$agent')";
|
|
$db_results = Dba::write($sql);
|
|
|
|
/* Clean up old records... sometimes */
|
|
if (rand(1,100) > 60) {
|
|
$date = time() - (86400*AmpConfig::get('user_ip_cardinality'));
|
|
$sql = "DELETE FROM `ip_history` WHERE `date` < $date";
|
|
$db_results = Dba::write($sql);
|
|
}
|
|
|
|
return true;
|
|
|
|
} // insert_ip_history
|
|
|
|
/**
|
|
* create
|
|
* inserts a new user into ampache
|
|
*/
|
|
public static function create($username, $fullname, $email, $website, $password, $access, $disabled = false)
|
|
{
|
|
$website = rtrim($website, "/");
|
|
$password = hash('sha256', $password);
|
|
$disabled = $disabled ? 1 : 0;
|
|
|
|
/* Now Insert this new user */
|
|
$sql = "INSERT INTO `user` (`username`, `disabled`, " .
|
|
"`fullname`, `email`, `password`, `access`, `create_date`";
|
|
$params = array($username, $disabled, $fullname, $email, $password, $access, time());
|
|
if (!empty($website)) {
|
|
$sql .= ", `website`";
|
|
$params[] = $website;
|
|
}
|
|
$sql .= ") VALUES(?, ?, ?, ?, ?, ?, ?";
|
|
if (!empty($website)) {
|
|
$sql .= ", ?";
|
|
}
|
|
$sql .= ")";
|
|
$db_results = Dba::write($sql, $params);
|
|
|
|
if (!$db_results) { return false; }
|
|
|
|
// Get the insert_id
|
|
$insert_id = Dba::insert_id();
|
|
|
|
/* Populates any missing preferences, in this case all of them */
|
|
self::fix_preferences($insert_id);
|
|
|
|
return $insert_id;
|
|
|
|
} // create
|
|
|
|
/**
|
|
* update_password
|
|
* updates a users password
|
|
*/
|
|
public function update_password($new_password)
|
|
{
|
|
$new_password = hash('sha256',$new_password);
|
|
|
|
$new_password = Dba::escape($new_password);
|
|
$sql = "UPDATE `user` SET `password` = ? WHERE `id` = ?";
|
|
$db_results = Dba::write($sql, array($new_password, $this->id));
|
|
|
|
// Clear this (temp fix)
|
|
if ($db_results) { unset($_SESSION['userdata']['password']); }
|
|
|
|
} // update_password
|
|
|
|
/**
|
|
* format
|
|
* This function sets up the extra variables we need when we are displaying a
|
|
* user for an admin, these should not be normally called when creating a
|
|
* user object
|
|
*/
|
|
public function format()
|
|
{
|
|
/* If they have a last seen date */
|
|
if (!$this->last_seen) { $this->f_last_seen = T_('Never'); } else { $this->f_last_seen = date("m\/d\/Y - H:i",$this->last_seen); }
|
|
|
|
/* If they have a create date */
|
|
if (!$this->create_date) { $this->f_create_date = T_('Unknown'); } else { $this->f_create_date = date("m\/d\/Y - H:i",$this->create_date); }
|
|
|
|
// Base link
|
|
$this->f_link = '<a href="' . AmpConfig::get('web_path') . '/stats.php?action=show_user&user_id=' . $this->id . '">' . $this->fullname . '</a>';
|
|
|
|
/* Calculate their total Bandwidth Usage */
|
|
$sql = "SELECT `song`.`size` FROM `song` LEFT JOIN `object_count` ON `song`.`id`=`object_count`.`object_id` " .
|
|
"WHERE `object_count`.`user`='$this->id' AND `object_count`.`object_type`='song'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$total = $total + $r['size'];
|
|
}
|
|
|
|
$this->f_useage = UI::format_bytes($total);
|
|
|
|
/* Get Users Last ip */
|
|
if (count($data = $this->get_ip_history(1))) {
|
|
$this->ip_history = inet_ntop($data['0']['ip']);
|
|
} else {
|
|
$this->ip_history = T_('Not Enough Data');
|
|
}
|
|
|
|
$avatar = $this->get_avatar();
|
|
if (!empty($avatar['url'])) {
|
|
$this->f_avatar = '<img src="' . $avatar['url'] . '" title="' . $avatar['title'] . '" />';
|
|
}
|
|
if (!empty($avatar['url_mini'])) {
|
|
$this->f_avatar_mini = '<img src="' . $avatar['url_mini'] . '" title="' . $avatar['title'] . '" style="width: 32px; height: 32px;" />';
|
|
}
|
|
if (!empty($avatar['url_medium'])) {
|
|
$this->f_avatar_medium = '<img src="' . $avatar['url_medium'] . '" title="' . $avatar['title'] . '" style="width: 64px; height: 64px;" />';
|
|
}
|
|
|
|
} // format_user
|
|
|
|
/**
|
|
* format_recommendations
|
|
* This takes an array of [object_id] = ratings
|
|
* and displays them in a semi-pretty format
|
|
*/
|
|
function format_recommendations($items,$type)
|
|
{
|
|
foreach ($items as $object_id=>$rating) {
|
|
|
|
switch ($type) {
|
|
case 'artist':
|
|
$object = new Artist($object_id);
|
|
$object->format_artist();
|
|
$name = $object->link;
|
|
break;
|
|
case 'album':
|
|
$object = new Album($object_id);
|
|
$object->format_album();
|
|
$name = $object->f_link;
|
|
break;
|
|
case 'song':
|
|
$object = new Song($object_id);
|
|
$object->format_song();
|
|
$name = $object->f_link;
|
|
break;
|
|
} // end switch on type
|
|
$results[] = "<li>$name -- " . get_rating_name($rating) . "<br />\n</li>";
|
|
|
|
} // end foreach items
|
|
|
|
|
|
return $results;
|
|
|
|
} // format_recommendations
|
|
|
|
/**
|
|
* access_name_to_level
|
|
* This takes the access name for the user and returns the level
|
|
*/
|
|
public static function access_name_to_level($level)
|
|
{
|
|
switch ($level) {
|
|
case 'admin':
|
|
return '100';
|
|
break;
|
|
case 'user':
|
|
return '25';
|
|
break;
|
|
case 'manager':
|
|
return '75';
|
|
break;
|
|
case 'guest':
|
|
return '5';
|
|
break;
|
|
default:
|
|
return '0';
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
|
|
} // access_name_to_level
|
|
|
|
/**
|
|
* fix_preferences
|
|
* This is the new fix_preferences function, it does the following
|
|
* Remove Duplicates from user, add in missing
|
|
* If -1 is passed it also removes duplicates from the `preferences`
|
|
* table.
|
|
*/
|
|
public static function fix_preferences($user_id)
|
|
{
|
|
$user_id = Dba::escape($user_id);
|
|
|
|
/* Get All Preferences for the current user */
|
|
$sql = "SELECT * FROM `user_preference` WHERE `user`='$user_id'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
$results = array();
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$pref_id = $r['preference'];
|
|
/* Check for duplicates */
|
|
if (isset($results[$pref_id])) {
|
|
$r['value'] = Dba::escape($r['value']);
|
|
$sql = "DELETE FROM `user_preference` WHERE `user`='$user_id' AND `preference`='" . $r['preference'] . "' AND" .
|
|
" `value`='" . Dba::escape($r['value']) . "'";
|
|
$delete_results = Dba::write($sql);
|
|
} // if its set
|
|
else {
|
|
$results[$pref_id] = 1;
|
|
}
|
|
} // end while
|
|
|
|
/* If we aren't the -1 user before we continue grab the -1 users values */
|
|
if ($user_id != '-1') {
|
|
$sql = "SELECT `user_preference`.`preference`,`user_preference`.`value` FROM `user_preference`,`preference` " .
|
|
"WHERE `user_preference`.`preference` = `preference`.`id` AND `user_preference`.`user`='-1' AND `preference`.`catagory` !='system'";
|
|
$db_results = Dba::read($sql);
|
|
/* While through our base stuff */
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$key = $r['preference'];
|
|
$zero_results[$key] = $r['value'];
|
|
}
|
|
} // if not user -1
|
|
|
|
// get me _EVERYTHING_
|
|
$sql = "SELECT * FROM `preference`";
|
|
|
|
// If not system, exclude system... *gasp*
|
|
if ($user_id != '-1') {
|
|
$sql .= " WHERE catagory !='system'";
|
|
}
|
|
$db_results = Dba::read($sql);
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
|
|
$key = $r['id'];
|
|
|
|
/* Check if this preference is set */
|
|
if (!isset($results[$key])) {
|
|
if (isset($zero_results[$key])) {
|
|
$r['value'] = $zero_results[$key];
|
|
}
|
|
$value = Dba::escape($r['value']);
|
|
$sql = "INSERT INTO user_preference (`user`,`preference`,`value`) VALUES ('$user_id','$key','$value')";
|
|
$insert_db = Dba::write($sql);
|
|
}
|
|
} // while preferences
|
|
|
|
/* Let's also clean out any preferences garbage left over */
|
|
$sql = "SELECT DISTINCT(user_preference.user) FROM user_preference " .
|
|
"LEFT JOIN user ON user_preference.user = user.id " .
|
|
"WHERE user_preference.user!='-1' AND user.id IS NULL";
|
|
$db_results = Dba::read($sql);
|
|
|
|
$results = array();
|
|
|
|
while ($r = Dba::fetch_assoc($db_results)) {
|
|
$results[] = $r['user'];
|
|
}
|
|
|
|
foreach ($results as $data) {
|
|
$sql = "DELETE FROM user_preference WHERE user='$data'";
|
|
$db_results = Dba::write($sql);
|
|
}
|
|
|
|
} // fix_preferences
|
|
|
|
/**
|
|
* delete
|
|
* deletes this user and everything associated with it. This will affect
|
|
* ratings and tottal stats
|
|
*/
|
|
public function delete()
|
|
{
|
|
/*
|
|
Before we do anything make sure that they aren't the last
|
|
admin
|
|
*/
|
|
if ($this->has_access(100)) {
|
|
$sql = "SELECT `id` FROM `user` WHERE `access`='100' AND id !='" . Dba::escape($this->id) . "'";
|
|
$db_results = Dba::read($sql);
|
|
if (!Dba::num_rows($db_results)) {
|
|
return false;
|
|
}
|
|
} // if this is an admin check for others
|
|
|
|
// Delete their playlists
|
|
$sql = "DELETE FROM `playlist` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Clean up the playlist data table
|
|
$sql = "DELETE FROM `playlist_data` USING `playlist_data` " .
|
|
"LEFT JOIN `playlist` ON `playlist`.`id`=`playlist_data`.`playlist` " .
|
|
"WHERE `playlist`.`id` IS NULL";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete any stats they have
|
|
$sql = "DELETE FROM `object_count` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Clear the IP history for this user
|
|
$sql = "DELETE FROM `ip_history` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Nuke any access lists that are specific to this user
|
|
$sql = "DELETE FROM `access_list` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete their ratings
|
|
$sql = "DELETE FROM `rating` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete their tags
|
|
$sql = "DELETE FROM `tag_map` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Clean out the tags
|
|
$sql = "DELETE FROM `tags` USING `tag_map` LEFT JOIN `tag_map` ON tag_map.id=tags.map_id AND tag_map.id IS NULL";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete their preferences
|
|
$sql = "DELETE FROM `user_preference` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete their voted stuff in democratic play
|
|
$sql = "DELETE FROM `user_vote` WHERE `user`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete their shoutbox posts
|
|
$sql = "DELETE FROM `user_shout` WHERE `user='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
// Delete the user itself
|
|
$sql = "DELETE FROM `user` WHERE `id`='$this->id'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
$sql = "DELETE FROM `session` WHERE `username`='" . Dba::escape($this->username) . "'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
return true;
|
|
|
|
} // delete
|
|
|
|
/**
|
|
* is_online
|
|
* delay how long since last_seen in seconds default of 20 min
|
|
* calcs difference between now and last_seen
|
|
* if less than delay, we consider them still online
|
|
*/
|
|
public function is_online( $delay = 1200 )
|
|
{
|
|
return time() - $this->last_seen <= $delay;
|
|
|
|
} // is_online
|
|
|
|
/**
|
|
* get_user_validation
|
|
*if user exists before activation can be done.
|
|
*/
|
|
public static function get_validation($username)
|
|
{
|
|
$usename = Dba::escape($username);
|
|
|
|
$sql = "SELECT `validation` FROM `user` WHERE `username`='$username'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
$row = Dba::fetch_assoc($db_results);
|
|
|
|
return $row['validation'];
|
|
|
|
} // get_validation
|
|
|
|
/**
|
|
* get_recently_played
|
|
* This gets the recently played items for this user respecting
|
|
* the limit passed
|
|
*/
|
|
public function get_recently_played($limit,$type='')
|
|
{
|
|
if (!$type) { $type = 'song'; }
|
|
|
|
$sql = "SELECT * FROM `object_count` WHERE `object_type`='$type' AND `user`='$this->id' " .
|
|
"ORDER BY `date` DESC LIMIT $limit";
|
|
$db_results = Dba::read($sql);
|
|
|
|
while ($row = Dba::fetch_assoc($db_results)) {
|
|
$results[] = $row['object_id'];
|
|
}
|
|
|
|
return $results;
|
|
|
|
} // get_recently_played
|
|
|
|
/**
|
|
* get_ip_history
|
|
* This returns the ip_history from the
|
|
* last AmpConfig::get('user_ip_cardinality') days
|
|
*/
|
|
public function get_ip_history($count='',$distinct='')
|
|
{
|
|
$username = Dba::escape($this->id);
|
|
$count = $count ? intval($count) : intval(AmpConfig::get('user_ip_cardinality'));
|
|
|
|
// Make sure it's something
|
|
if ($count < 1) { $count = '1'; }
|
|
$limit_sql = "LIMIT " . intval($count);
|
|
|
|
if ($distinct) { $group_sql = "GROUP BY `ip`"; }
|
|
|
|
/* Select ip history */
|
|
$sql = "SELECT `ip`,`date` FROM `ip_history`" .
|
|
" WHERE `user`='$username'" .
|
|
" $group_sql ORDER BY `date` DESC $limit_sql";
|
|
$db_results = Dba::read($sql);
|
|
|
|
$results = array();
|
|
|
|
while ($row = Dba::fetch_assoc($db_results)) {
|
|
$results[] = $row;
|
|
}
|
|
|
|
return $results;
|
|
|
|
} // get_ip_history
|
|
|
|
/**
|
|
* get_avatar
|
|
* Get the user avatar
|
|
*/
|
|
public function get_avatar()
|
|
{
|
|
$avatar = array();
|
|
|
|
$avatar['title'] = T_('User avatar');
|
|
$upavatar = new Art($this->id, 'user');
|
|
if ($upavatar->get_db()) {
|
|
$avatar['url'] = AmpConfig::get('web_path') . '/image.php?object_type=user&id=' . $this->id;
|
|
$avatar['url_mini'] = $avatar['url'];
|
|
$avatar['url_medium'] = $avatar['url'];
|
|
$avatar['url'] .= '&thumb=3';
|
|
$avatar['url_mini'] .= '&thumb=5';
|
|
$avatar['url_medium'] .= '&thumb=3';
|
|
} else {
|
|
foreach (Plugin::get_plugins('get_avatar_url') as $plugin_name) {
|
|
$plugin = new Plugin($plugin_name);
|
|
if ($plugin->load($GLOBALS['user'])) {
|
|
$avatar['url'] = $plugin->_plugin->get_avatar_url($this);
|
|
if (!empty($avatar['url'])) {
|
|
$avatar['url_mini'] = $plugin->_plugin->get_avatar_url($this, 32);
|
|
$avatar['url_medium'] = $plugin->_plugin->get_avatar_url($this, 64);
|
|
$avatar['title'] .= ' (' . $plugin->_plugin->name . ')';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $avatar;
|
|
} // get_avatar
|
|
|
|
public function upload_avatar()
|
|
{
|
|
if (!empty($_FILES['avatar']['tmp_name'])) {
|
|
$path_info = pathinfo($_FILES['avatar']['name']);
|
|
$upload['file'] = $_FILES['avatar']['tmp_name'];
|
|
$upload['mime'] = 'image/' . $path_info['extension'];
|
|
$image_data = Art::get_from_source($upload, 'user');
|
|
|
|
if ($image_data) {
|
|
$art = new Art($this->id, 'user');
|
|
$art->insert($image_data, $upload['0']['mime']);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function delete_avatar()
|
|
{
|
|
$art = new Art($this->id, 'user');
|
|
$art->reset();
|
|
}
|
|
|
|
/**
|
|
* activate_user
|
|
* the user from public_registration
|
|
*/
|
|
public function activate_user($username)
|
|
{
|
|
$username = Dba::escape($username);
|
|
|
|
$sql = "UPDATE `user` SET `disabled`='0' WHERE `username`='$username'";
|
|
$db_results = Dba::write($sql);
|
|
|
|
} // activate_user
|
|
|
|
/**
|
|
* is_xmlrpc
|
|
* checks to see if this is a valid xmlrpc user
|
|
*/
|
|
public function is_xmlrpc()
|
|
{
|
|
/* If we aren't using XML-RPC return true */
|
|
if (!AmpConfig::get('xml_rpc')) {
|
|
return false;
|
|
}
|
|
|
|
//FIXME: Ok really what we will do is check the MD5 of the HTTP_REFERER
|
|
//FIXME: combined with the song title to make sure that the REFERER
|
|
//FIXME: is in the access list with full rights
|
|
return true;
|
|
|
|
} // is_xmlrpc
|
|
|
|
/**
|
|
* check_username
|
|
* This checks to make sure the username passed doesn't already
|
|
* exist in this instance of ampache
|
|
*/
|
|
public static function check_username($username)
|
|
{
|
|
$username = Dba::escape($username);
|
|
|
|
$sql = "SELECT `id` FROM `user` WHERE `username`='$username'";
|
|
$db_results = Dba::read($sql);
|
|
|
|
if (Dba::num_rows($db_results)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
} // check_username
|
|
|
|
/**
|
|
* rebuild_all_preferences
|
|
* This rebuilds the user preferences for all installed users, called by the plugin functions
|
|
*/
|
|
public static function rebuild_all_preferences()
|
|
{
|
|
$sql = "SELECT * FROM `user`";
|
|
$db_results = Dba::read($sql);
|
|
|
|
User::fix_preferences('-1');
|
|
|
|
while ($row = Dba::fetch_assoc($db_results)) {
|
|
User::fix_preferences($row['id']);
|
|
}
|
|
|
|
return true;
|
|
|
|
} // rebuild_all_preferences
|
|
|
|
} //end user class
|