<?php
###############################################################################
# domainauth.php
# Watch My Domains SED v3
# (c) Softnik Technologies. All rights reserved.
#
#  Author:   Anil Kumar
#  Version:	 1.0
#  Date:     10-July-2013
#
#  Acknowledgements
#  ----------------
#  Some parts of this code were inspired by UserCake v2 
#  http://usercake.com
#  UserCake created by: Adam Davis
#  UserCake v2.0 designed by: Jonathan Cassels
#  MIT Licence
#
###############################################################################

require_once("cppdo.php");
require_once("gridpdo.php");
require_once("domainpdo.php");

###############################################################################

class wmDomainAuthDB extends wmDomainDatabase
{
	public $user_groups_table 		= null;
	public $user_table   			= null;
	public $auth_log_table   		= null;
	public $category_access_table 	= null;
	public $group_access_table      = null;
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function __construct($db_type="mysql", $table_prefix="")
	{ 
		wmDomainDatabase::__construct($db_type, $table_prefix);
		
		$this->user_groups_table 		= trim(strtolower($table_prefix . "auth_usergroups"));
		$this->user_table   			= trim(strtolower($table_prefix . "auth_users"));
		$this->category_access_table 	= trim(strtolower($table_prefix . "auth_domain_categories"));
		$this->group_access_table 		= trim(strtolower($table_prefix . "auth_group_access"));
		$this->auth_log_table   		= trim(strtolower($table_prefix . "auth_logs"));
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function getColumns($tablename)
	{
		$columns = wmDomainDatabase::getColumns($tablename);
		
		if(strtolower($tablename) == $this->user_groups_table)
		{
			$columns[] = "id";
			$columns[] = "int(11)";
			$columns[] = "NOT NULL AUTO_INCREMENT";
			
			$columns[] = "name";
			$columns[] = "varchar(255)";
			$columns[] = "NOT NULL";
		}
		else if(strtolower($tablename) == $this->auth_log_table)
		{
			$columns[] = "ip";
			$columns[] = "varchar(24)";
			$columns[] = "NOT NULL";
			
			$columns[] = "login_last_failed_at";
			$columns[] = "datetime";
			$columns[] = "DEFAULT NULL";
			
			$columns[] = "login_last_succeeded_at";
			$columns[] = "datetime";
			$columns[] = "DEFAULT NULL";
			
			$columns[] = "login_fail_count";
			$columns[] = "int(11)";
			$columns[] = "DEFAULT 0";
		}
		else if(strtolower($tablename) == $this->user_table)
		{
			$columns[] = "id";
			$columns[] = "int(11)";
			$columns[] = "NOT NULL AUTO_INCREMENT";
			
			$columns[] = "name";
			$columns[] = "varchar(255)";
			$columns[] = "NOT NULL DEFAULT ''";
			
			$columns[] = "display_name";
			$columns[] = "varchar(50)";
			$columns[] = "NOT NULL DEFAULT ''";
				
			$columns[] = "password";
			$columns[] = "varchar(225)";
			$columns[] = "NOT NULL";
			
			$columns[] = "email";
			$columns[] = "varchar(255)";
			$columns[] = "DEFAULT NULL";
			
			$columns[] = "active";
			$columns[] = "tinyint(1)";
			$columns[] = "NOT NULL DEFAULT 0";
			
			$columns[] = "readwrite";
			$columns[] = "tinyint(1)";
			$columns[] = "NOT NULL DEFAULT 1";
			
			$columns[] = "full_name";
			$columns[] = "varchar(225)";
			$columns[] = "DEFAULT NULL";
			
			$columns[] = "last_sign_in_stamp";
			$columns[] = "datetime";
			$columns[] = "DEFAULT NULL";
			
			$columns[] = "added_on";
			$columns[] = "datetime";
			$columns[] = "DEFAULT NULL";
		}
		else if(strtolower($tablename) == $this->category_access_table)
		{
			$columns[] = "id";
			$columns[] = "bigint(20)";
			$columns[] = "NOT NULL AUTO_INCREMENT";
			
			$columns[] = "user_id";
			$columns[] = "bigint(20)";
			$columns[] = "NOT NULL";
			
			$columns[] = "cat_id";			# domain category id.
			$columns[] = "bigint(20)";
			$columns[] = "NOT NULL";
		}
		else if(strtolower($tablename) == $this->group_access_table)
		{
			$columns[] = "id";
			$columns[] = "bigint(20)";
			$columns[] = "NOT NULL AUTO_INCREMENT";
			
			$columns[] = "user_id";
			$columns[] = "int(11)";
			$columns[] = "NOT NULL";
			
			$columns[] = "group_id";			
			$columns[] = "int(11)";
			$columns[] = "NOT NULL";
		}
		return $columns;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function getDefaultKeys($tablename)
	{
		if(strtolower($tablename) == $this->user_groups_table)
			return "PRIMARY KEY (id)";
		else if(strtolower($tablename) == $this->user_table)
			return "PRIMARY KEY (id)";
		else if(strtolower($tablename) == $this->category_access_table)
			return "PRIMARY KEY (id)";
		else if(strtolower($tablename) == $this->group_access_table)
			return "PRIMARY KEY (id)";
		else if(strtolower($tablename) == $this->auth_log_table)
			return "PRIMARY KEY (ip)";
		else
			return wmDomainDatabase::getDefaultKeys($tablename);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function getDefaultAutoIncrement($tablename)
	{
		if(strtolower($tablename) == $this->user_groups_table)
			return 3;
		else if(strtolower($tablename) == $this->user_table)
			return 1;
		else if(strtolower($tablename) == $this->category_access_table)
			return 2;
		else if(strtolower($tablename) == $this->group_access_table)
			return 1;
		else if(strtolower($tablename) == $this->auth_log_table)
			return 1;
		else 
			return wmDomainDatabase::getDefaultAutoIncrement($tablename);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function initTables($engine="MyISAM")
	{
		wmDomainDatabase::initTables($engine);
		$this->initAuthTables($engine);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function initAuthTables($engine="MyISAM")
	{
		$this->initTable($this->user_groups_table, $engine);
		$this->initTable($this->user_table, $engine);
		$this->initTable($this->category_access_table, $engine);
		$this->initTable($this->group_access_table, $engine);
		$this->initTable($this->auth_log_table, $engine);
		
		# add the default data (admin and 'newuser')
		$this->addUserGroup("Admin", 1);
		$this->addUserGroup("New User", 2);
		
		# add any missing or new fields
		$this->repairTable($this->user_groups_table);
		$this->repairTable($this->user_table);
		$this->repairTable($this->category_access_table);
		$this->repairTable($this->group_access_table);
		$this->repairTable($this->auth_log_table);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	function getUserCategoryAccessTableName()
	{
		return $this->category_access_table;
	}
	
	###########################################################################
	
	public function getUserTableName()
	{
		return $this->user_table;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function userNameExists($name)
	{
		$dberror = false;
		$status = $this->isEntryPresent($this->user_table, "name", $name, $dberror);
		if($dberror == false)
			return $status;
			
		# actually a db error occurred. But for the purpose of this function, we will ignore and 
		# return false. The db error message will be in the log.
		
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function displayNameExists($display_name)
	{
		$dberror = false;
		$status = $this->isEntryPresent($this->user_table, "display_name", $display_name, $dberror);
		if($dberror == false)
			return $status;
			
		# actually a db error occurred. But for the purpose of this function, we will ignore and 
		# return false. The db error message will be in the log.
		
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function emailExists($email)
	{
		$dberror = false;
		$status = $this->isEntryPresent($this->user_table, "email", $email, $dberror);
		if($dberror == false)
			return $status;
			
		# actually a db error occurred. But for the purpose of this function, we will ignore and 
		# return false. The db error message will be in the log.
		
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function addAuthLog($login_status=true)
	{
		$ip = $_SERVER['REMOTE_ADDR'];
		
		# Check if the IP is in the DB. If not, add it.
		$dberror = false;
		$status = $this->isEntryPresent($this->auth_log_table, "ip", $ip, $dberror);
		if($dberror == false && $status === false)
		{
			try
			{
				$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->auth_log_table . " (ip) VALUES(:ip)");
				$stmt->execute(array(':ip' => $ip));
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
		
		try
		{
			$failcount = $this->getSingleEntry($this->auth_log_table, "ip", $ip, "login_fail_count");
			if($failcount !== false)
			{
				if(!$login_status)
				{
					$failcount++;
					$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->auth_log_table . " SET login_last_failed_at=?,login_fail_count=? WHERE ip=?");
				}
				else
				{
					$failcount = 0;
					$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->auth_log_table . " SET login_last_succeeded_at=?,login_fail_count=? WHERE ip=?");
				}
				$stmt->execute(array(date("Y-m-d H:i:s"), $failcount, $ip));
				return true;
			}
			else
				return false;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function addUserGroup($name, $gid=0)
	{
		$dberror = false;
		$status = $this->isEntryPresent($this->user_groups_table, "name", $name, $dberror);
		if($dberror == false && $status === false)
		{
			try
			{
				if($gid != 0)
				{
					$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->user_groups_table . " (id,name) VALUES(:id,:name)");
					$stmt->execute(
					array(':id' => $gid, ':name' => $name));
				}
				else
				{
					$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->user_groups_table . " (name) VALUES(:name)");
					$stmt->execute(
					array(':name' => $name));
				}
				return true;
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
		else if($dberror == false)
			$this->setError("The group '" . $name . "' already exists.");
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function addUserToGroup($uid, $groupname)
	{
		$gid = $this->getSingleEntry($this->user_groups_table, "name", $groupname, "id");
		if($gid !== false)
		{
			try
			{
				$stmt = $this->db_connect_handle->prepare("SELECT * FROM " . $this->group_access_table . " WHERE user_id=? AND group_id=?");
				$stmt->execute(array($uid, $gid));
				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
				if(count($rows) == 0)
				{
					$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->group_access_table . " (user_id,group_id) VALUES(:user_id,:group_id)");
					$stmt->execute(
					array(':user_id' => $uid, ':group_id' => $gid));
					return true;
				}
				else
				{
					$msg = "The user id '" . $uid . "' is already a member of '" . $groupname . "'.";
					$this->setError($msg);
					return false;
				}
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function removeUserFromGroup($uid, $groupname)
	{
		$gid = $this->getSingleEntry($this->user_groups_table, "name", $groupname, "id");
		if($gid !== false)
		{
			try
			{
				$stmt = $this->db_connect_handle->prepare("SELECT * FROM " . $this->group_access_table . " WHERE user_id=? AND group_id=?");
				$stmt->execute(array($uid, $gid));
				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
				if(count($rows) == 1)
				{
					$stmt = $this->db_connect_handle->prepare("DELETE FROM " . $this->group_access_table . " WHERE user_id=? AND group_id=?");
					$stmt->execute(array($uid, $gid));
					return true;
				}
				else
				{
					$msg = "The user id '" . $uid . "' is not a member of '" . $groupname . "'.";
					$this->setError($msg);
					return false;
				}
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function createUser($username, $displayname, $password, $group = "New User", $active=true, $readwrite=true, $email="")
	{
		$status = true;
		if($username == "" || $password == "")
		{		
			$this->setError("Empty user name or password.");
			$status = false;
		}
		if($this->userNameExists($username))
		{		
			$this->setError("User '" . $username . "' already exists.");
			$status = false;
		}
		/*
		if($this->displayNameExists($displayname))
		{
			$this->setError("Display name '" . $displayname . "' already exists.");
			$status = false;
		}
		*/
		if($email != "")
		{
			if(!filter_var($email, FILTER_VALIDATE_EMAIL)) 
			{
				$this->setError("Email address '" . $email . "' is not valid.");
				$status = false;
			}
			else if($this->emailExists($email))
			{
				$this->setError("Email address '" . $email . "' already exists.");
				$status = false;
			}
		}
		
		if($status == true)
		{
			$securepass = generateHash($password);
			try
			{
				$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->user_table . " (name,display_name,password,added_on,email,active,readwrite) VALUES(:name,:display_name,:password,:added_on,:email,:active,:readwrite)");
				$stmt->execute(
				array(
				':name' => $username, ':display_name' => $displayname, ':password' => $securepass, ':added_on' => date("Y-m-d H:i:s"), ':email' => $email, ':active'=>$active, ':readwrite'=>$readwrite
				));
				$uid = $this->db_connect_handle->lastInsertId('id');
				
				if($group != "")
					$this->addUserToGroup($uid, $group);
				
				$this->logAuditEntry(AUDIT_ADDED_USER, "Added user $username");
				
				return true;
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
		return $status;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function setCategoriesForUser($userid, $permissions)
	{
		if(is_array($permissions))
		{
			try
			{
				# first delete existing.
				$sql = "DELETE FROM " . $this->category_access_table . " WHERE user_id = ?";
				$stmt = $this->db_connect_handle->prepare($sql);
				$stmt->execute(array($userid));
				
				$categoryTable = $this->getCategoryTableName();
				foreach($permissions as $cat)
				{
					$catid = $this->getSingleEntry($categoryTable, "CategoryName", $cat, "CategoryID");
					$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->category_access_table . " (user_id,cat_id) VALUES(:userid,:catid)");
					$stmt->execute(array(':userid' => $userid, ':catid' => $catid));
				}
				return true;
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function setCategoryIdsForUser($userid, $permissions)
	{
		if(is_array($permissions))
		{
			try
			{
				# first delete existing.
				$sql = "DELETE FROM " . $this->category_access_table . " WHERE user_id = ?";
				$stmt = $this->db_connect_handle->prepare($sql);
				$stmt->execute(array($userid));
				
				$categoryTable = $this->getCategoryTableName();
				foreach($permissions as $catid)
				{
					$stmt = $this->db_connect_handle->prepare("INSERT INTO " . $this->category_access_table . " (user_id,cat_id) VALUES(:userid,:catid)");
					$stmt->execute(array(':userid' => $userid, ':catid' => $catid));
				}
				return true;
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function isValidLogin($username, $password)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("SELECT * FROM " . $this->user_table . " WHERE name=? AND active=1");
			$stmt->execute(array($username));
			$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
			if(count($rows) == 1)
			{
				$userid = $rows[0]['id'];
				$storedHash = $rows[0]['password'];
				$userpass = generateHash($password, $storedHash);
				if($userpass == $storedHash)
					return true;
				else
					return false;
			}
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function checkLogin($username, $password)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("SELECT * FROM " . $this->user_table . " WHERE name=? AND active=1");
			$stmt->execute(array($username));
			$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
			if(count($rows) == 1)
			{
				$userid = $rows[0]['id'];
				$storedHash = $rows[0]['password'];
				$userpass = generateHash($password, $storedHash);
				
				if($userpass == $storedHash)
				{
					$this->addAuthLog(true);
					
					$userinfo['uid'] = $userid;
					$userinfo['fullname'] = $rows[0]['full_name'];
					$userinfo['displayname'] = $rows[0]['display_name'];
					$userinfo['name'] = $rows[0]['name'];
					$userinfo['readwrite'] = $rows[0]['readwrite'];
					$userinfo['admin'] = false;
					$userinfo['lastsignin'] = $rows[0]['last_sign_in_stamp'];
					
					$sql = "SELECT user_id, group_id FROM " . $this->group_access_table . " WHERE user_id = ? AND group_id = 1";
					$stmt = $this->db_connect_handle->prepare($sql);
					$stmt->execute(array($userid));
					$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
					if(count($rows) == 1)
						$userinfo['admin'] = true;
					
					// Find all access rights for the user.
					$categoryTable = $this->getCategoryTableName();
					
					$sql = "SELECT user_id, cat_id FROM " .  $this->category_access_table . " WHERE user_id = ?";
					$stmt = $this->db_connect_handle->prepare($sql);
					$stmt->execute(array($userid));
					$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
					
					$permissions = array();
					foreach($rows as $row)
					{
						$entry['name'] = $this->getSingleEntry($categoryTable, "CategoryID", $row['cat_id'], "CategoryName");
						$entry['id'] = $row['cat_id'];
						$permissions[]  = $entry;
					}			
					
					$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->user_table . " SET last_sign_in_stamp=? WHERE id=?");
					$stmt->execute(array(date("Y-m-d H:i:s"), $userid));
					
					return $this->doLogin($userinfo, $permissions);
				}
				else
				{
					$this->addAuthLog(false);
					return false;
				}
			}
			else
			{
				$this->addAuthLog(false);
				return false;
			}
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	static function doLogin($userinfo, $permissions = null)
	{
		if($permissions == null)
			$permissions = array();
			
		$_SESSION['logged'] = true;
		$_SESSION['rid'] = $_SERVER["REMOTE_ADDR"];
		$_SESSION['timeout'] = time();
		
		$_SESSION['user'] = $userinfo;
		$_SESSION['permissions'] = $permissions;
		
		if(isset($_SESSION['redir']))
		{
			$redirpath = $_SESSION['redir'];
			unset($_SESSION['redir']);
			return $redirpath;
		}
		
		return get_install_url_path() . "main.php";
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function getUserInfo($userid)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("SELECT * FROM " . $this->user_table . " WHERE id=?");
			$stmt->execute(array($userid));
			$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
			if(count($rows) == 1)
			{
				$userinfo['uid'] = $userid;
				$userinfo['fullname'] = $rows[0]['full_name'];
				$userinfo['displayname'] = $rows[0]['display_name'];
				$userinfo['name'] = $rows[0]['name'];
				$userinfo['readwrite'] = $rows[0]['readwrite'];
				$userinfo['admin'] = false;
				$userinfo['lastsignin'] = $rows[0]['last_sign_in_stamp'];
				$userinfo['active'] = $rows[0]['active'];
				
				$sql = "SELECT user_id, group_id FROM " . $this->group_access_table . " WHERE user_id = ? AND group_id = 1";
				$stmt = $this->db_connect_handle->prepare($sql);
				$stmt->execute(array($userid));
				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
				if(count($rows) == 1)
					$userinfo['admin'] = true;
				
				// Find all access rights for the user.
				$categoryTable = $this->getCategoryTableName();
				
				$sql = "SELECT user_id, cat_id FROM " .  $this->category_access_table . " WHERE user_id = ?";
				$stmt = $this->db_connect_handle->prepare($sql);
				$stmt->execute(array($userid));
				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
				
				$permissions = array();
				foreach($rows as $row)
				{
					$entry['name'] = $this->getSingleEntry($categoryTable, "CategoryID", $row['cat_id'], "CategoryName");
					$entry['id'] = $row['cat_id'];
					$permissions[]  = $entry;
				}			
				$userinfo['permissions'] = $permissions;
				return $userinfo;
			}
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function deleteUserGroup($name)
	{
		$groupid = $this->getSingleEntry($this->user_groups_table, "name", $name, "id");
		if($groupid !== false)
		{
			try
			{
				$sql = "DELETE FROM " . $this->user_groups_table . " WHERE " . "id =  :uid";
				$stmt = $this->db_connect_handle->prepare($sql);
				$stmt->execute(array(':uid' => $groupid));
				
				$sql = "DELETE FROM " . $this->group_access_table . " WHERE " . "group_id =  :uid";
				$stmt = $this->db_connect_handle->prepare($sql);
				$stmt->execute(array(':uid' => $groupid));
				
				return true;
			}
			catch (PDOException $e) 
			{
				$this->setError($e->getMessage());
				return false;
			}
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function getUserNameFromID($uid)
	{
		if($uid == 0)
			return "Super Admin";
		else
			return $userid = $this->getSingleEntry($this->user_table, "id", $uid, "name");
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function deleteUser($name)
	{
		$userid = $this->getSingleEntry($this->user_table, "name", $name, "id");
		if($userid !== false)
			return deleteUserID($userid);
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function deleteUserID($userid)
	{
		try
		{
			$username = $this->getSingleEntry($this->user_table, "id", $userid, "name");
			
			$sql = "DELETE FROM " . $this->user_table . " WHERE " . "id =  :uid";
			$stmt = $this->db_connect_handle->prepare($sql);
			$stmt->execute(array(':uid' => $userid));
			
			$sql = "DELETE FROM " . $this->category_access_table . " WHERE " . "user_id =  :uid";
			$stmt = $this->db_connect_handle->prepare($sql);
			$stmt->execute(array(':uid' => $userid));
			
			$sql = "DELETE FROM " . $this->getAuditLogTableName() . " WHERE " . "uid =  :uid";
			$stmt = $this->db_connect_handle->prepare($sql);
			$stmt->execute(array(':uid' => $userid));
			
			$sql = "DELETE FROM " . $this->group_access_table . " WHERE " . "user_id =  :uid";
			$stmt = $this->db_connect_handle->prepare($sql);
			$stmt->execute(array(':uid' => $userid));
			
			$this->logAuditEntry(AUDIT_DELETED_USER, "Deleted user $username");
			
			return true;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function resetUserPassword($name, $password)
	{
		$userid = $this->getSingleEntry($this->user_table, "name", $name, "id");
		if($userid !== false)
			return $this->resetUserIDPassword($userid, $password);
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function resetUserIDPassword($userid, $password)
	{
		$securepass = generateHash($password);
		try
		{
			$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->user_table . " SET password=? WHERE id=?");
			$stmt->execute(array($securepass, $userid));
			return true;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function changeUserIDName($userid, $name)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->user_table . " SET name=? WHERE id=?");
			$stmt->execute(array($name, $userid));
			return true;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function changeUserIDDisplayName($userid, $name)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->user_table . " SET display_name=? WHERE id=?");
			$stmt->execute(array($name, $userid));
			return true;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function changeUserIDStatus($userid, $status)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->user_table . " SET active=? WHERE id=?");
			$stmt->execute(array($status, $userid));
			return true;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
		return false;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public function changeUserIDReadWrite($userid, $status)
	{
		try
		{
			$stmt = $this->db_connect_handle->prepare("UPDATE " . $this->user_table . " SET readwrite=? WHERE id=?");
			$stmt->execute(array($status, $userid));
			return true;
		}
		catch (PDOException $e) 
		{
			$this->setError($e->getMessage());
			return false;
		}
		return false;
	}
	
	###########################################################################
	
	public function deleteCategories($cidlist)
	{
		try
		{
			$catnames = array();
			$ids = explode(",", $cidlist);
			foreach($ids as &$id)
			{
				$id = intval($id);
				if($id == 1)  # Don't Delete 'All Domains' category.
					return false;
					$categoryname = $this->getSingleEntry($this->getCategoryTableName(), "CategoryID", $id, "CategoryName");
				$catnames[] = $categoryname;
				$id = $this->db_connect_handle->quote($id);	
			}
			$this->db_connect_handle->exec("DELETE FROM " . $this->getCategoryTableName() . " WHERE CategoryID IN (" . implode(', ', $ids) . ')');
			$this->db_connect_handle->exec("DELETE FROM " . $this->getCategoryIDToDomainIDTableName() . " WHERE CategoryID IN (" . implode(', ', $ids) . ')');
			$this->db_connect_handle->exec("DELETE FROM " . $this->getUserCategoryAccessTableName() . " WHERE cat_id IN (" . implode(', ', $ids) . ')');
			if(count($catnames))
				$this->logAuditEntry(AUDIT_DELETED_CATEGORY, "Deleted " . count($catnames) . " categories (" . implode(", ", $catnames) . ")");
			return true;
		}
		catch (PDOException $e) 
		{
			$dberror = true;
			$this->setError($e->getMessage());
			return false;
		}
	}
	
	###############################################################################
	
	public function getLastAuditLogEntries($limit=100, $tableclass="logtable", $rowclassfunc=null)
	{
		$alog = $this->getTableData($this->getAuditLogTableName(), "*", "ORDER BY timeat DESC LIMIT 0,$limit");
		if($alog !== false)
		{
			$index = 1;
			foreach($alog as &$row)
			{
				$desc = "";
				$action = -1;
				foreach($row as $key=>&$value)
				{
					if($key == "uid")
					{
						$uid = $value;
						$ui = $this->getUserInfo($uid);
						$value = $this->getUserNameFromId($value);
						$row['user'] = $row['uid'];
						if(isset($ui['admin']) && $ui['admin'])
							$row['user'] .= " (admin)";
						unset($row['uid']);
					}
					else if($key == "action")
					{
						$action = $value;
						$value = $this->getActionDescription($value);
					}
					else if($key == "description")
						$desc = $value;
				}
				if($desc == "" && isset($row['action']))
					$desc = $row['action'];
				
				$row['description'] = str_replace("\n", "<br>", $desc);
				
				if(isset($row['id']))
					unset($row['id']);
				if(isset($row['action']))
					unset($row['action']);
				
				$row['index'] = $index++;
				
				if(!isset($row['user']))
					$row['user'] = "unknown";
				if(!isset($row['timeat']))
					$row['timeat'] = "?";
			}
		}
		
		$tclass = "";
		if($tableclass != "")
			$tclass = " class=\"$tableclass\"";
		$tablehtml = "\n<table" . "$tclass>\n";
		
		$labels = array('#', 'Timestamp', 'User', 'Action', 'IP Address');
		$fields = array('index', 'timeat', 'user', 'description', 'remote');
		
		$tablehtml .= "<tr>";
		foreach($labels as $label)
			$tablehtml .= "<th>$label</th>";
		$tablehtml .= "</tr>\n";

		foreach($alog as $arow)
		{
			$rowhtml = "";
			foreach($fields as $column)
			{
				$entry = "";
				if(isset($arow[$column]))
					$entry = $arow[$column];
				$rowhtml .= "<td class=\"$column\">$entry</td>";
			}
			if($rowclassfunc != null)
				$rowhtml = $rowclassfunc($rowhtml, $arow);
			else
				$rowhtml = "<tr>$rowhtml</tr>\n";
			$tablehtml .= $rowhtml;
		}
		$tablehtml .= "</table>";
		return $tablehtml;
	}
	
	###############################################################################
	
	public function getActionDescription($action)
	{
		switch($action)
		{
			case AUDIT_ADD_DOMAINS:
				return "Added domains";
			case AUDIT_DELETE_DOMAINS:
				return "Deleted domains";
			case AUDIT_LOGGED_IN:
				return "User logged In";
			case AUDIT_LOGGED_OUT:
				return "User logged out";
			case AUDIT_SESSION_TIMEOUT:
				return "Session timedout";
			case AUDIT_ADDED_USER:
				return "Added User";
			case AUDIT_DELETED_USER:
				return "Removed user";
			case AUDIT_ADDED_CATEGORY:
				return "Added category";
			case AUDIT_DELETED_CATEGORY:
				return "Removed category";
			case AUDIT_CSV_DOWNLOAD:
				return "Domain Data downloaded";
			case AUDIT_SSL_CSV_DOWNLOAD:
				return "Domain SSL Data downloaded";
			case AUDIT_DNS_CSV_DOWNLOAD:
				return "Domain DNS Data downloaded";
			default:
				return "Unknown";
		}
	}
}

###############################################################################
?>
