Initial commit
This commit is contained in:
286
app/models/group.php
Normal file
286
app/models/group.php
Normal file
@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* app/models/group.php
|
||||
*
|
||||
* This class is used for the manipulation of the groups database table.
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
use TheTempusProject\Classes\Permissions;
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
|
||||
class Group extends DatabaseModel {
|
||||
protected static $user;
|
||||
protected static $permissions;
|
||||
public $tableName = 'groups';
|
||||
public $configName = 'group';
|
||||
public $modelVersion = '1.0';
|
||||
public static $protectedGroups = [
|
||||
'Super', 'Admin', 'Moderator'
|
||||
];
|
||||
public $configMatrix = [
|
||||
'defaultGroup' => [
|
||||
'type' => 'customSelect',
|
||||
'pretty' => 'The Default Group for new registrations.',
|
||||
'default' => 5,
|
||||
],
|
||||
];
|
||||
public $databaseMatrix = [
|
||||
[ 'name', 'varchar', '32' ],
|
||||
[ 'permissions', 'text', '' ],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'adminAccess' => [
|
||||
'pretty' => 'Access Administrator Areas',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $resourceMatrix = [
|
||||
[
|
||||
'name' => 'Super',
|
||||
'permissions' => '{"adminAccess":true}',
|
||||
],
|
||||
[
|
||||
'name' => 'Admin',
|
||||
'permissions' => '{"adminAccess":true}',
|
||||
],
|
||||
[
|
||||
'name' => 'User',
|
||||
'permissions' => '{"adminAccess":false}',
|
||||
],
|
||||
[
|
||||
'name' => 'Guest',
|
||||
'permissions' => '{"adminAccess":false}',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$group = $this;
|
||||
self::$permissions = new Permissions;
|
||||
}
|
||||
|
||||
public function isEmpty( $id ) {
|
||||
if ( !Check::ID( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
$userData = self::$db->get( 'users', [ 'userGroup', '=', $id ] );
|
||||
if ( !$userData->count() ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to delete the specified group.
|
||||
*
|
||||
* @param int|array $ID the log ID or array of ID's to be deleted
|
||||
* @return bool
|
||||
*/
|
||||
public function delete( $data ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( !is_array( $data ) ) {
|
||||
$data = [ $data ];
|
||||
}
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !Check::id( $instance ) ) {
|
||||
$error = true;
|
||||
}
|
||||
if ( $this->countMembers( $instance ) !== 0 ) {
|
||||
Debug::info( 'Group is not empty.' );
|
||||
return false;
|
||||
}
|
||||
if ( $instance == Config::getValue( 'group/defaultGroup' ) ) {
|
||||
Debug::info( 'Cannot delete the default group.' );
|
||||
return false;
|
||||
}
|
||||
if ( $instance == '1' ) {
|
||||
Debug::info( 'Cannot delete the super group.' );
|
||||
return false;
|
||||
}
|
||||
self::$db->delete( $this->tableName, [ 'ID', '=', $instance ] );
|
||||
self::$log->admin( "Deleted group: $instance" );
|
||||
Debug::info( "Group deleted: $instance" );
|
||||
if ( !empty( $end ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !empty( $error ) ) {
|
||||
Debug::info( 'One or more invalid ID\'s.' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function hasPermission( $permission ) {
|
||||
|
||||
}
|
||||
|
||||
// update($data, Input::post('name'), ) {
|
||||
public function getPermissionsDelta( $id, $permissions ) {
|
||||
}
|
||||
|
||||
public function create( $name, $permissions ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( !Check::dataTitle( $name ) ) {
|
||||
Debug::info( 'modelGroup: illegal group name.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'permissions' => json_encode( $permissions ),
|
||||
];
|
||||
if ( self::$db->insert( $this->tableName, $fields ) ) {
|
||||
self::$log->admin( "Created Group: $name" );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update( $id, $name, $permissions ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $name ) ) {
|
||||
Debug::info( 'modelGroup: illegal group name.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'permissions' => json_encode( $permissions ),
|
||||
];
|
||||
if ( self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
self::$log->admin( "Updated Group: $id" );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDefaultPermissions() {
|
||||
return self::$permissions->getDefaultPermissionsArray();
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
$defaults = $this->getDefaultPermissions();
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$toArray = (array) $instance;
|
||||
$instance->perms = json_decode( $instance->permissions, true );
|
||||
$instance->userCount = $this->countMembers( $instance->ID );
|
||||
foreach ( $defaults as $name => $default ) {
|
||||
$string_name = $name . '_string';
|
||||
$text_name = $name . '_text';
|
||||
$pretty_name = $name . '_pretty';
|
||||
if ( isset( $instance->perms[ $name ] ) ) {
|
||||
$default = $instance->perms[ $name ];
|
||||
}
|
||||
$instance->$name = $default;
|
||||
$instance->$pretty_name = self::$permissions->getPrettyName( $name );
|
||||
if ( $default === true ) {
|
||||
$instance->$string_name = 'true';
|
||||
$instance->$text_name = 'yes';
|
||||
} else {
|
||||
$instance->$string_name = 'false';
|
||||
$instance->$text_name = 'no';
|
||||
}
|
||||
}
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function findByName( $name ) {
|
||||
if ( !Check::dataString( $name ) ) {
|
||||
Debug::warn( "$this->tableName findByName: illegal name: $name" );
|
||||
return false;
|
||||
}
|
||||
$groupData = self::$db->get( $this->tableName, [ 'name', '=', $name ] );
|
||||
if ( !$groupData->count() ) {
|
||||
Debug::warn( 'Could not find a group named: ' . $name );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $groupData->first() );
|
||||
}
|
||||
|
||||
public function listGroupsSimple( $include_all = false, $include_none = false ) {
|
||||
$db = self::$db->get( $this->tableName, '*' );
|
||||
if ( !$db->count() ) {
|
||||
Debug::warn( 'Could not find any groups' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$groups = $db->results();
|
||||
$out = [];
|
||||
if ( $include_all ) {
|
||||
$out[ 'All Groups' ] = 0;
|
||||
}
|
||||
if ( $include_none ) {
|
||||
$out[ 'No Group' ] = 0;
|
||||
}
|
||||
foreach ( $groups as &$group ) {
|
||||
$out[ $group->name ] = $group->ID;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function listMembers( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
$group = $this->findById( $id );
|
||||
if ( $group === false ) {
|
||||
return false;
|
||||
}
|
||||
$members = self::$db->get( 'users', [ 'userGroup', '=', $id ] );
|
||||
if ( !$members->count() ) {
|
||||
Debug::info( "list members: Could not find anyone in group: $id" );
|
||||
return false;
|
||||
}
|
||||
$out = $members->results();
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a count of the members in a specific group.
|
||||
*
|
||||
* @param integer $id - The group ID to count the members of
|
||||
* @return boolean|integer
|
||||
*/
|
||||
public function countMembers( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
$userData = self::$db->get( 'users', [ 'userGroup', '=', $id ] );
|
||||
if ( !$userData->count() ) {
|
||||
Debug::info( "count members: Could not find anyone in group: $id" );
|
||||
return 0;
|
||||
}
|
||||
return $userData->count();
|
||||
}
|
||||
}
|
197
app/models/log.php
Normal file
197
app/models/log.php
Normal file
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* app/models/log.php
|
||||
*
|
||||
* Model for handling all logging.
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
|
||||
class Log extends DatabaseModel {
|
||||
public $tableName = 'logs';
|
||||
public $configName = 'logging';
|
||||
public $modelVersion = '1.0';
|
||||
public $configMatrix = [
|
||||
'admin' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Admin Action Logging.',
|
||||
'default' => true,
|
||||
],
|
||||
'errors' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Error Logging',
|
||||
'default' => true,
|
||||
],
|
||||
'logins' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Login Logging',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $databaseMatrix = [
|
||||
[ 'userID', 'int', '11' ],
|
||||
[ 'time', 'int', '10' ],
|
||||
[ 'ip', 'varchar', '15' ],
|
||||
[ 'source', 'varchar', '64' ],
|
||||
[ 'action', 'text', '' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$log = $this;
|
||||
}
|
||||
|
||||
public function enabled( $type = '' ) {
|
||||
if ( true === parent::enabled() ) {
|
||||
return Config::getValue( 'logging/' . $type ) === true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$toArray = (array) $instance;
|
||||
switch ($instance->source) {
|
||||
case 'error':
|
||||
$out[] = (object) array_merge( json_decode( $instance->action, true ), $toArray );
|
||||
break;
|
||||
default:
|
||||
$instance->logUser = self::$user->getUsername( $instance->userID );
|
||||
$out[] = $instance;
|
||||
break;
|
||||
}
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function list( $filter = null ) {
|
||||
$logData = self::$db->getPaginated( $this->tableName, [ 'source', '=', $filter ] );
|
||||
if ( !$logData->count() ) {
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $logData->results() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to clear logs of a specific type.
|
||||
*
|
||||
* @param {string} $data - The log type to be cleared
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear( $data ) {
|
||||
switch ( $data ) {
|
||||
case 'admin':
|
||||
Debug::error( 'You cannot delete admin logs' );
|
||||
return false;
|
||||
case 'login':
|
||||
self::$db->delete( $this->tableName, [ 'source', '=', $data ] );
|
||||
$this->admin( "Cleared Logs: $data" );
|
||||
return true;
|
||||
case 'error':
|
||||
self::$db->delete( $this->tableName, [ 'source', '=', $data ] );
|
||||
$this->admin( "Cleared Logs: $data" );
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* logs an error to the DB.
|
||||
*
|
||||
* @param {int} [$errorID] - An associated error ID
|
||||
* @param {string} [$class] - Class where the error occurred
|
||||
* @param {string} [$function] - method in which the error occurred
|
||||
* @param {string} [$error] - What was the error
|
||||
* @param {string} [$data] - Any additional info
|
||||
*/
|
||||
public function error( $errorID = 500, $class = null, $function = null, $error = null, $data = null ) {
|
||||
if ( !$this->enabled( 'errors' ) ) {
|
||||
Debug::info( 'Error logging is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
$data = [
|
||||
'class' => $class,
|
||||
'function' => $function,
|
||||
'error' => $error,
|
||||
'description' => $data,
|
||||
];
|
||||
$output = json_encode( $data );
|
||||
$fields = [
|
||||
'userID' => $errorID,
|
||||
'action' => $output,
|
||||
'time' => time(),
|
||||
'source' => 'error',
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'logError', $data );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a login to the DB.
|
||||
*
|
||||
* @param {int} [$userID] - The User ID being logged in.
|
||||
* @param {string} [$action] - Must be 'pass' or 'fail'.
|
||||
*/
|
||||
public function login( $userID, $action = 'fail' ) {
|
||||
if ( !$this->enabled( 'logins' ) ) {
|
||||
Debug::info( 'Login logging is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'userID' => $userID,
|
||||
'action' => $action,
|
||||
'time' => time(),
|
||||
'source' => 'login',
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'logLogin' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an admin action to the DB.
|
||||
*
|
||||
* @param {string} [$action] - Must be 'pass' or 'fail'.
|
||||
*/
|
||||
public function admin( $action ) {
|
||||
if ( !$this->enabled( 'admin' ) ) {
|
||||
Debug::info( 'Admin logging is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'userID' => App::$activeUser->ID,
|
||||
'action' => $action,
|
||||
'time' => time(),
|
||||
'source' => 'admin',
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'logAdmin' );
|
||||
}
|
||||
}
|
||||
}
|
158
app/models/routes.php
Normal file
158
app/models/routes.php
Normal file
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* app/models/routes.php
|
||||
*
|
||||
* This class is used for the manipulation of the routes database table.
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
|
||||
class Routes extends DatabaseModel {
|
||||
public $tableName = 'routes';
|
||||
public $modelVersion = '1.0';
|
||||
public $databaseMatrix = [
|
||||
[ 'nickname', 'varchar', '32' ],
|
||||
[ 'redirect_type', 'varchar', '32' ],
|
||||
[ 'original_url', 'varchar', '32' ],
|
||||
[ 'forwarded_url', 'text', '' ],
|
||||
];
|
||||
public $resourceMatrix = [
|
||||
[
|
||||
'original_url' => 'fb',
|
||||
'redirect_type' => 'external',
|
||||
'nickname' => 'Facebook',
|
||||
'forwarded_url' => 'https://www.facebook.com/thetempusproject',
|
||||
],
|
||||
[
|
||||
'original_url' => 'twitter',
|
||||
'redirect_type' => 'external',
|
||||
'nickname' => 'Twitter',
|
||||
'forwarded_url' => 'https://twitter.com/ProjectTempus',
|
||||
],
|
||||
[
|
||||
'original_url' => 'in',
|
||||
'redirect_type' => 'external',
|
||||
'nickname' => 'LinkedIn',
|
||||
'forwarded_url' => 'https://www.linkedin.com/company/the-tempus-project/',
|
||||
],
|
||||
[
|
||||
'original_url' => 'youtube',
|
||||
'redirect_type' => 'external',
|
||||
'nickname' => 'YouTube',
|
||||
'forwarded_url' => 'https://www.youtube.com/channel/UCWy5mgBdvp8-nLJrvhnzC4w',
|
||||
],
|
||||
[
|
||||
'original_url' => 'git',
|
||||
'redirect_type' => 'external',
|
||||
'nickname' => 'GitHub',
|
||||
'forwarded_url' => 'https://github.com/TheTempusProject',
|
||||
],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'addRoute' => [
|
||||
'pretty' => 'Add Custom Routes',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
|
||||
public function create( $original_url, $forwarded_url, $nickname = '', $type = 'external' ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( empty( $forwarded_url ) || empty( $original_url ) ) {
|
||||
Debug::info( 'Missing some parts' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::simpleName( $nickname ) ) {
|
||||
Debug::warn( 'Invalid route nickname: ' . $name );
|
||||
return false;
|
||||
}
|
||||
if ( 'external' == $type && !Check::url( $forwarded_url ) ) {
|
||||
Debug::info( 'Routes: illegal forwarded_url.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'nickname' => $nickname,
|
||||
'redirect_type' => $type,
|
||||
'original_url' => $original_url,
|
||||
'forwarded_url' => $forwarded_url,
|
||||
];
|
||||
if ( self::$db->insert( $this->tableName, $fields ) ) {
|
||||
self::$log->admin( "Created Route: $nickname" );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update( $id, $original_url, $forwarded_url, $nickname, $type ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( !Check::simpleName( $nickname ) ) {
|
||||
Debug::warn( "Invalid route nickname: $name" );
|
||||
return false;
|
||||
}
|
||||
if ( empty( $forwarded_url ) || empty( $original_url ) ) {
|
||||
Debug::info( 'Missing some parts' );
|
||||
return false;
|
||||
}
|
||||
if ( 'external' == $type && !Check::url( $forwarded_url ) ) {
|
||||
Debug::info( 'Routes: illegal forwarded_url.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'nickname' => $nickname,
|
||||
'redirect_type' => $type,
|
||||
'original_url' => $original_url,
|
||||
'forwarded_url' => $forwarded_url,
|
||||
];
|
||||
if ( self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
self::$log->admin( "Updated Route: $id" );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function findByName( $name ) {
|
||||
if ( !Check::simpleName( $name ) ) {
|
||||
Debug::warn( "Invalid route nickname: $name" );
|
||||
return false;
|
||||
}
|
||||
$routeData = self::$db->get( $this->tableName, [ 'nickname', '=', $name ] );
|
||||
if ( !$routeData->count() ) {
|
||||
Debug::warn( "Could not find a group named: $name" );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $routeData->first() );
|
||||
}
|
||||
|
||||
public function findByOriginalUrl( $url ) {
|
||||
$routeData = self::$db->get( $this->tableName, [ 'original_url', '=', $url ] );
|
||||
if ( !$routeData->count() ) {
|
||||
Debug::warn( "Could not find route by original url: $url" );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $routeData->first() );
|
||||
}
|
||||
|
||||
public function findByforwardedUrl( $url ) {
|
||||
if ( !Check::url( $url ) ) {
|
||||
Debug::warn( "Invalid forwarded_url: $url" );
|
||||
return false;
|
||||
}
|
||||
$routeData = self::$db->get( $this->tableName, [ 'forwarded_url', '=', $url ] );
|
||||
if ( !$routeData->count() ) {
|
||||
Debug::warn( "Could not find route by forwarded url: $url" );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $routeData->first() );
|
||||
}
|
||||
}
|
283
app/models/sessions.php
Normal file
283
app/models/sessions.php
Normal file
@ -0,0 +1,283 @@
|
||||
<?php
|
||||
/**
|
||||
* app/models/sessions.php
|
||||
*
|
||||
* This model is used for the modification and management of the session data.
|
||||
*
|
||||
* Notes: After refactor, the sessions will use ID's for short term, and Cookies
|
||||
* will use the token for long term storage
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Code;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Bedrock\Functions\Cookie;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Sessions extends DatabaseModel {
|
||||
public $tableName = 'sessions';
|
||||
public $modelVersion = '1.0';
|
||||
public $databaseMatrix = [
|
||||
[ 'userID', 'int', '5' ],
|
||||
[ 'userGroup', 'int', '5' ],
|
||||
[ 'expire', 'int', '10' ],
|
||||
[ 'ip', 'varchar', '15' ],
|
||||
[ 'hash', 'varchar', '80' ],
|
||||
[ 'lastPage', 'varchar', '64' ],
|
||||
[ 'username', 'varchar', '20' ],
|
||||
[ 'token', 'varchar', '120' ],
|
||||
];
|
||||
public static $activeSession = false;
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$session = $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a session exists, verifies the username,
|
||||
* password, and IP address to prevent forgeries.
|
||||
*
|
||||
* @param {int} [$id] - The id of the session being checked.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function checkSession( $sessionID ) {
|
||||
$user = new User;
|
||||
// @todo lets put this on some sort of realistic checking regime other than check everything every time
|
||||
if ( $sessionID == false ) {
|
||||
return false;
|
||||
}
|
||||
if ( !Check::id( $sessionID ) ) {
|
||||
return false;
|
||||
}
|
||||
$data = self::$db->get( $this->tableName, [ 'ID', '=', $sessionID ] );
|
||||
if ( $data->count() == 0 ) {
|
||||
Debug::info( 'Session token not found.' );
|
||||
return false;
|
||||
}
|
||||
$session = $data->first();
|
||||
$user = $user->findById( $session->userID );
|
||||
if ( $user === false ) {
|
||||
Debug::info( 'User not found in DB.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( $user->username != $session->username ) {
|
||||
Debug::info( 'Usernames do not match.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( $user->password != $session->hash ) {
|
||||
Debug::info( 'Session Password does not match.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( time() > $session->expire ) {
|
||||
Debug::info( 'Session Expired.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( $user->userGroup !== $session->userGroup ) {
|
||||
Debug::info( 'Groups do not match.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( $_SERVER['REMOTE_ADDR'] != $session->ip ) {
|
||||
Debug::info( 'IP addresses do not match.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
self::$activeSession = $session;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the "remember me" cookie we use to identify
|
||||
* unique sessions across multiple visits. Checks that
|
||||
* the tokens match, checks the username as well as the
|
||||
* password from the database to ensure it hasn't been
|
||||
* modified elsewhere between visits.
|
||||
*
|
||||
* @param {string} [$token] - The unique token saved as a cookie that is being checked.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function checkCookie( $cookieToken, $create = false ) {
|
||||
$user = new User;
|
||||
if ( $cookieToken === false ) {
|
||||
return false;
|
||||
}
|
||||
$data = self::$db->get( $this->tableName, [ 'token', '=', $cookieToken ] );
|
||||
if ( !$data->count() ) {
|
||||
Debug::info( 'sessions->checkCookie - Session token not found.' );
|
||||
|
||||
return false;
|
||||
}
|
||||
$session = $data->first();
|
||||
$user = self::$user->findById( $session->userID );
|
||||
if ( $user === false ) {
|
||||
Debug::info( 'sessions->checkCookie - could not find user by ID.' );
|
||||
return false;
|
||||
}
|
||||
if ( $user->username != $session->username ) {
|
||||
Debug::info( 'sessions->checkCookie - Usernames do not match.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( $user->password != $session->hash ) {
|
||||
Debug::info( 'sessions->checkCookie - Session Password does not match.' );
|
||||
$this->destroy( $session->ID );
|
||||
return false;
|
||||
}
|
||||
if ( $create ) {
|
||||
return $this->newSession( null, false, false, $session->userID );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkToken( $apiToken, $create = false ) {
|
||||
$user = new User;
|
||||
if ( $apiToken === false ) {
|
||||
return false;
|
||||
}
|
||||
$result = $user->findByToken( $apiToken );
|
||||
if ( $result === false ) {
|
||||
Debug::info( 'sessions->checkToken - could not find user by token.' );
|
||||
return false;
|
||||
}
|
||||
if ( $create ) {
|
||||
return $this->newSession( null, false, false, $result->ID );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session from the data provided. The
|
||||
* expiration time is optional and will be set to the
|
||||
* system default if not provided.
|
||||
*
|
||||
* @param {int} [$ID] - The User ID of the new session holder.
|
||||
* @param {int} [$expire] - The expiration time (in seconds).
|
||||
* @return {bool}
|
||||
*/
|
||||
public function newSession( $expire = null, $override = false, $remember = false, $userID = null ) {
|
||||
if ( ! isset( $expire ) ) {
|
||||
// default Session Expiration is 24 hours
|
||||
$expire = ( time() + ( 3600 * 24 ) );
|
||||
Debug::log( 'Using default expiration time' );
|
||||
}
|
||||
$lastPage = App::getUrl();
|
||||
if ( self::$activeSession != false ) {
|
||||
// there is already an active session
|
||||
if ( $override === false ) {
|
||||
Debug::error( 'No need for a new session.' );
|
||||
return false;
|
||||
}
|
||||
// We can override the active session
|
||||
$data = self::$db->get( $this->tableName, [ 'userID', '=', self::$activeSession->ID ] );
|
||||
if ( $data->count() ) {
|
||||
Debug::log( 'Deleting old session from db' );
|
||||
$session = self::$db->first();
|
||||
$this->destroy( $session->ID );
|
||||
}
|
||||
}
|
||||
if ( empty( $userID ) ) {
|
||||
if ( App::$activeUser === null ) {
|
||||
Debug::info( 'Must provide user details to create a new session.' );
|
||||
return false;
|
||||
}
|
||||
$userID = App::$activeUser->ID;
|
||||
}
|
||||
$userObject = self::$user->findById( $userID );
|
||||
if ( $userObject === false ) {
|
||||
Debug::info( 'User not found.' );
|
||||
return false;
|
||||
}
|
||||
$token = Code::genToken();
|
||||
$result = self::$db->insert(
|
||||
$this->tableName,
|
||||
[
|
||||
'username' => $userObject->username,
|
||||
'hash' => $userObject->password,
|
||||
'userGroup' => $userObject->userGroup,
|
||||
'userID' => $userObject->ID,
|
||||
'lastPage' => $lastPage,
|
||||
'expire' => $expire,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
'token' => $token,
|
||||
]
|
||||
);
|
||||
$sessionID = self::$db->lastId();
|
||||
|
||||
|
||||
$sessionData = self::$db->get( $this->tableName, [ 'ID', '=', $sessionID ] )->first();
|
||||
|
||||
|
||||
Session::put( 'SessionID', $sessionID );
|
||||
if ( $remember ) {
|
||||
Cookie::put( 'RememberToken', $token, ( time() + ( 3600 * 24 * 30 ) ) );
|
||||
}
|
||||
self::$activeSession = $sessionData;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to update the users' current active page.
|
||||
* NOTE: Current session assumed if no $id is provided.
|
||||
*
|
||||
* @param {string} [$page] - The name of the page you are updating to.
|
||||
* @param {int|null} [$id] - The ID of the session you are updating.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function updatePage( $page, $id = null ) {
|
||||
if ( empty( $id ) ) {
|
||||
if ( self::$activeSession === false ) {
|
||||
Debug::info( 'Session::updatePage - Must provide session ID or have active session' );
|
||||
return false;
|
||||
}
|
||||
$id = self::$activeSession->ID;
|
||||
}
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Session::updatePage - Invalid ID' );
|
||||
return false;
|
||||
}
|
||||
if ( !self::$db->update( $this->tableName, $id, [ 'lastPage' => $page ] ) ) {
|
||||
Debug::info( 'Session::updatePage - Failed to update database' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a session.
|
||||
*
|
||||
* @param {int} [$id] - The ID of the session you wish to destroy.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function destroy( $id ) {
|
||||
Session::delete( 'SessionID' );
|
||||
Cookie::delete( 'RememberToken' );
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Session::destroy - Invalid ID' );
|
||||
return false;
|
||||
}
|
||||
$data = self::$db->get( $this->tableName, [ 'ID', '=', $id ] );
|
||||
if ( !$data->count() ) {
|
||||
Debug::info( 'Session::destroy - Session not found in DB' );
|
||||
return false;
|
||||
}
|
||||
self::$db->delete( $this->tableName, [ 'ID', '=', $id ] );
|
||||
self::$activeSession = false;
|
||||
return true;
|
||||
}
|
||||
}
|
726
app/models/user.php
Normal file
726
app/models/user.php
Normal file
@ -0,0 +1,726 @@
|
||||
<?php
|
||||
/**
|
||||
* app/models/user.php
|
||||
*
|
||||
* This class is used for the manipulation of the user database table.
|
||||
*
|
||||
* @todo needs a re-build
|
||||
* @todo finish fixing the check functions that were migrated here
|
||||
* These could go in the Forms class?
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
use TheTempusProject\Bedrock\Functions\Hash;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Bedrock\Functions\Code;
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
use TheTempusProject\Classes\Email;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\Classes\Preferences;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class User extends DatabaseModel {
|
||||
public $tableName = 'users';
|
||||
public $modelVersion = '1.0';
|
||||
public $databaseMatrix = [
|
||||
[ 'registered', 'int', '10' ],
|
||||
[ 'terms', 'int', '1' ],
|
||||
[ 'confirmed', 'int', '1' ],
|
||||
[ 'userGroup', 'int', '11' ],
|
||||
[ 'lastLogin', 'int', '10' ],
|
||||
[ 'username', 'varchar', '16' ],
|
||||
[ 'password', 'varchar', '80' ],
|
||||
[ 'email', 'varchar', '75' ],
|
||||
[ 'name', 'varchar', '20' ],
|
||||
[ 'confirmationCode', 'varchar', '80' ],
|
||||
[ 'prefs', 'text', '' ],
|
||||
[ 'auth_token', 'text', '' ],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'uploadImages' => [
|
||||
'pretty' => 'Upload images (such as avatars)',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $preferenceMatrix = [
|
||||
'gender' => [
|
||||
'pretty' => 'Gender',
|
||||
'type' => 'select',
|
||||
'default' => 'unspecified',
|
||||
'options' => [
|
||||
'male',
|
||||
'female',
|
||||
'other',
|
||||
'unspecified',
|
||||
],
|
||||
],
|
||||
'newsletter' => [
|
||||
'pretty' => 'Receive our Newsletter?',
|
||||
'type' => 'checkbox',
|
||||
'default' => 'true',
|
||||
],
|
||||
'avatar' => [
|
||||
'pretty' => 'Avatar',
|
||||
'type' => 'file',
|
||||
'default' => 'images/defaultAvatar.png',
|
||||
],
|
||||
'timezone' => [
|
||||
'pretty' => 'Timezone',
|
||||
'type' => 'timezone',
|
||||
'default' => 'America/New_York',
|
||||
],
|
||||
'dateFormat' => [
|
||||
'pretty' => 'Date Format',
|
||||
'type' => 'select',
|
||||
'default' => 'F j, Y',
|
||||
'options' => [
|
||||
'1-8-1991' => 'n-j-Y',
|
||||
'8-1-1991' => 'j-n-Y',
|
||||
'01-08-1991' => 'm-d-Y',
|
||||
'08-01-1991' => 'd-m-Y',
|
||||
'January 8, 1991' => 'F-j-Y',
|
||||
'8 January, 1991' => 'j-F-Y',
|
||||
'January 08, 1991' => 'F-d-Y',
|
||||
'08 January, 1991' => 'd-F-Y',
|
||||
'Jan 8, 1991' => 'M-j-Y',
|
||||
'8 Jan 1991' => 'j-M-Y',
|
||||
'Jan 08, 1991' => 'M-d-Y',
|
||||
'08 Jan 1991' => 'd-M-Y',
|
||||
],
|
||||
],
|
||||
'timeFormat' => [
|
||||
'pretty' => 'Time Format',
|
||||
'type' => 'select',
|
||||
'default' => 'g:i:s A',
|
||||
'options' => [
|
||||
'3:33:33 AM' => 'g:i:s A',
|
||||
'03:33:33 AM' => 'h:i:s A',
|
||||
'3:33:33 am' => 'g:i:s a',
|
||||
'03:33:33 am' => 'h:i:s a',
|
||||
'3:33:33 (military)' => 'G:i:s',
|
||||
'03:33:33 (military)' => 'H:i:s',
|
||||
],
|
||||
],
|
||||
'pageLimit' => [
|
||||
'pretty' => 'Items Displayed Per Page',
|
||||
'type' => 'select',
|
||||
'default' => '10',
|
||||
'options' => [
|
||||
'10',
|
||||
'15',
|
||||
'20',
|
||||
'25',
|
||||
'50',
|
||||
],
|
||||
],
|
||||
];
|
||||
protected static $avatars;
|
||||
protected static $preferences;
|
||||
protected static $group;
|
||||
protected static $usernames;
|
||||
protected $data;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$user = $this;
|
||||
self::$preferences = new Preferences;
|
||||
self::$group = new Group;
|
||||
}
|
||||
|
||||
public function getPreferences( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
$userData = $this->get( $id );
|
||||
$prefs = json_decode( $userData->prefs, true );
|
||||
return $prefs;
|
||||
}
|
||||
|
||||
public function getPreferencesDelta() {
|
||||
$defaults = $this->getDefaultPreferences();
|
||||
foreach ( $defaults as $key => $value ) {
|
||||
if ( isset( self::$preferences[ $key ] ) ) {
|
||||
$defaults[ $key ] = self::$preferences[ $key ];
|
||||
}
|
||||
}
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
public function getDefaultPreferences() {
|
||||
return self::$preferences->getDefaultPreferencesArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the database for a user with the same email.
|
||||
*
|
||||
* @param {string} [$email] - The email being tested.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function noEmailExists( $email ) {
|
||||
if ( Check::email( $email ) ) {
|
||||
$emailQuery = self::$db->get( $this->tableName, [ 'email', '=', $email ] );
|
||||
if ( $emailQuery->count() == 0 ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// self::addError("Email is already in use.", $email);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the database for a user with the same username.
|
||||
*
|
||||
* @param {string} [$data] - The string being tested.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function usernameExists( $data ) {
|
||||
if ( Forms::checkUsername( $data ) ) {
|
||||
$usernameResults = self::$db->get( $this->tableName, [ 'username', '=', $data ] );
|
||||
if ( $usernameResults->count() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// self::addError("No user exists in the DB.", $data);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks username formatting.
|
||||
*
|
||||
* Requirements:
|
||||
* - 4 - 16 characters long
|
||||
* - must only contain numbers and letters: [A - Z] , [a - z], [0 - 9]
|
||||
*
|
||||
* @param {string} [$data] - The string being tested.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function checkUsername( $data ) {
|
||||
if ( strlen( $data ) > 16 ) {
|
||||
// self::addError("Username must be be 4 to 16 numbers or letters.", $data);
|
||||
return false;
|
||||
}
|
||||
if ( strlen( $data ) < 4 ) {
|
||||
// self::addError("Username must be be 4 to 16 numbers or letters.", $data);
|
||||
return false;
|
||||
}
|
||||
if ( !ctype_alnum( $data ) ) {
|
||||
// self::addError("Username must be be 4 to 16 numbers or letters.", $data);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and define usernames by user ID.
|
||||
*
|
||||
* @param {int} [$id] - The ID of the user you are looking for.
|
||||
* @return {string} - Either the username or 'unknown' will be returned.
|
||||
*/
|
||||
public function getUsername( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !isset( self::$usernames[ $id ] ) ) {
|
||||
$user = $this->get( $id );
|
||||
if ( $user !== false ) {
|
||||
self::$usernames[ $id ] = $user->username;
|
||||
} else {
|
||||
self::$usernames[ $id ] = 'Unknown';
|
||||
}
|
||||
}
|
||||
return self::$usernames[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we need a cache of the usernames, we use this function
|
||||
* to find/return all usernames based on ID.
|
||||
*
|
||||
* @param {int} [$username] - The username of the user you are looking for.
|
||||
* @return {int}
|
||||
*/
|
||||
public function getID( $username ) {
|
||||
if ( !Forms::checkUsername( $username ) ) {
|
||||
return false;
|
||||
}
|
||||
$user = $this->get( $username );
|
||||
if ( $user !== false ) {
|
||||
return $user->ID;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and define user avatar image urls.
|
||||
*
|
||||
* @param {int} [$id] - The ID of the user you are looking for.
|
||||
* @return {string} - Either the username or 'unknown' will be returned.
|
||||
*/
|
||||
public function getAvatar( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !isset( self::$avatars[ $id ] ) ) {
|
||||
if ( $this->get( $id ) ) {
|
||||
self::$avatars[ $id ] = self::data()->avatar;
|
||||
} else {
|
||||
self::$avatars[ $id ] = '{BASE}images/defaultAvatar.png';
|
||||
}
|
||||
}
|
||||
return self::$avatars[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specified user(s).
|
||||
*
|
||||
* @param {int|array} [$data] - The log ID or array of ID's to be deleted.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function delete( $idArray ) {
|
||||
if ( !is_array( $idArray ) ) {
|
||||
$idArray = [ $idArray ];
|
||||
}
|
||||
foreach ( $idArray as $id ) {
|
||||
if ( App::$activeUser->ID == $id ) {
|
||||
Debug::info( 'Attempting to delete own account.' );
|
||||
return false;
|
||||
}
|
||||
$user = $this->get( $id );
|
||||
if (
|
||||
'Super' == $user->groupName
|
||||
&& 'Super' !== App::$activeGroup->name
|
||||
) {
|
||||
Debug::info( 'Attempting to delete superior account.' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return parent::delete( $idArray );
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to authenticate a user login and set them as the active user.
|
||||
*
|
||||
* @param {string} [$username] - The username being used to login.
|
||||
* @param {string} [$password] - The un-hashed password.
|
||||
* @param {bool} [$remember] - Whether the user wishes to be remembered or not.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function logIn( $username, $password, $remember = false ) {
|
||||
if ( !isset( self::$session ) ) {
|
||||
self::$session = new Sessions;
|
||||
}
|
||||
if ( !isset( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
Debug::group( 'login', 1 );
|
||||
if ( !Forms::checkUsername( $username ) ) {
|
||||
Debug::warn( 'Invalid Username.' );
|
||||
return false;
|
||||
}
|
||||
if ( !$this->get( $username ) ) {
|
||||
self::$log->login( 0, "User not found: $username" );
|
||||
Debug::warn( "User not found: $username" );
|
||||
return false;
|
||||
}
|
||||
// login attempts protection.
|
||||
$timeLimit = ( time() - 3600 );
|
||||
$limit = Config::getValue( 'main/loginLimit' );
|
||||
$user = $this->data();
|
||||
if ( $limit > 0 ) {
|
||||
$limitCheck = self::$db->get(
|
||||
'logs',
|
||||
[
|
||||
'source', '=', 'login',
|
||||
'AND',
|
||||
'userID', '=', $user->ID,
|
||||
'AND',
|
||||
'time', '>=', $timeLimit,
|
||||
'AND',
|
||||
'action', '!=', 'pass',
|
||||
]
|
||||
);
|
||||
if ( $limitCheck->count() >= $limit ) {
|
||||
Debug::info( 'login: Limit reached.', 1 );
|
||||
self::$log->login( $user->ID, 'Too many failed attempts.' );
|
||||
Debug::warn( 'Too many failed login attempts, please try again later.' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( !Check::password( $password ) ) {
|
||||
Debug::warn( 'Invalid password.' );
|
||||
self::$log->login( $user->ID, 'Invalid Password.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Hash::check( $password, $user->password ) ) {
|
||||
Debug::warn( 'Pass hash does not match.' );
|
||||
self::$log->login( $user->ID, 'Wrong Password.' );
|
||||
return false;
|
||||
}
|
||||
self::$session->newSession( null, true, $remember, $user->ID );
|
||||
self::$log->login( $this->data()->ID, 'pass' );
|
||||
$this->update( $this->data()->ID, [ 'lastLogin' => time() ] );
|
||||
Debug::gend();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log out the currently active user.
|
||||
*/
|
||||
public function logOut() {
|
||||
if ( !isset( self::$session ) ) {
|
||||
self::$session = new Sessions;
|
||||
}
|
||||
Debug::group( 'Logout', 1 );
|
||||
self::$session->destroy( Session::get( 'SessionToken' ) );
|
||||
App::$isLoggedIn = false;
|
||||
App::$isMember = false;
|
||||
App::$isMod = false;
|
||||
App::$isAdmin = false;
|
||||
App::$activeUser = null;
|
||||
Debug::info( 'User has been logged out.' );
|
||||
Debug::gend();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a user password.
|
||||
*
|
||||
* @param {string} [$code] - The confirmation code required from the password email.
|
||||
* @param {string} [$password] - The new password for the user's account.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function changePassword( $code, $password ) {
|
||||
if ( !Check::password( $password ) ) {
|
||||
return false;
|
||||
}
|
||||
$data = self::$db->get( $this->tableName, [ 'confirmationCode', '=', $code ] );
|
||||
if ( $data->count() ) {
|
||||
$this->data = $data->first();
|
||||
$this->update(
|
||||
$this->data->ID,
|
||||
[ 'password' => Hash::make( $password ), 'confirmationCode' => '', ],
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of registered users.
|
||||
*
|
||||
* @param {array} [$filter] - A filter to be applied to the users list.
|
||||
* @return {bool|object}
|
||||
*/
|
||||
public function userList( $filter = null ) {
|
||||
if ( ! empty( $filter ) ) {
|
||||
switch ( $filter ) {
|
||||
case 'newsletter':
|
||||
$data = self::$db->search( $this->tableName, 'prefs', 'newsletter":"true' );
|
||||
break;
|
||||
default:
|
||||
$data = self::$db->get( $this->tableName, '*' );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$data = self::$db->get( $this->tableName, '*' );
|
||||
}
|
||||
if ( ! $data->count() ) {
|
||||
return false;
|
||||
}
|
||||
return (object) $data->results();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of recently registered users.
|
||||
*
|
||||
* @param {int} [$limit] - How many posts you would like returned.
|
||||
* @return {bool|object}
|
||||
*/
|
||||
public function recent( $limit = null ) {
|
||||
if ( empty( $limit ) ) {
|
||||
$data = self::$db->getpaginated( $this->tableName, '*' );
|
||||
} else {
|
||||
$data = self::$db->get( $this->tableName, [ 'ID', '>', '0' ], 'ID', 'DESC', [ 0, $limit ] );
|
||||
}
|
||||
if ( !$data->count() ) {
|
||||
return false;
|
||||
}
|
||||
return (object) $data->results();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the database for a user with the same confirmation code.
|
||||
*
|
||||
* @param {string} [$code] - The confirmation code being checked.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function checkCode( $code ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'confirmationCode', '=', $code ] );
|
||||
if ( $data->count() > 0 ) {
|
||||
return true;
|
||||
}
|
||||
Debug::error( 'User confirmation code not found.' );
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and save a new confirmation code for the user.
|
||||
*
|
||||
* @param {int} [$id] - The user ID to update the confirmation code for.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function newCode( $id ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'ID', '=', $id ] );
|
||||
if ( $data->count() == 0 ) {
|
||||
return false;
|
||||
}
|
||||
$this->data = $data->first();
|
||||
$Ccode = md5( uniqid() );
|
||||
$this->update(
|
||||
$this->data->ID,
|
||||
[ 'confirmationCode' => $Ccode ],
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and confirms a user by their confirmation code.
|
||||
*
|
||||
* @param {string} [$code] - The confirmation code sent to the user.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function confirm( $code ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'confirmationCode', '=', $code ] );
|
||||
if ( $data->count() ) {
|
||||
$this->data = $data->first();
|
||||
$this->update(
|
||||
$this->data->ID,
|
||||
[ 'confirmed' => 1, 'confirmationCode' => '', ],
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified user exists or not.
|
||||
*
|
||||
* @return {bool}
|
||||
* @todo this function should actually check for a user
|
||||
*/
|
||||
public function exists() {
|
||||
return ( !empty( $this->data ) ) ? true : false;
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = (object) $data;
|
||||
$end = true;
|
||||
}
|
||||
if ( $instance->confirmed == 1 ) {
|
||||
$instance->confirmedText = 'Yes';
|
||||
} else {
|
||||
$instance->confirmedText = 'No';
|
||||
}
|
||||
$group = self::$group->findById( $instance->userGroup );
|
||||
if ( !empty( $group ) ) {
|
||||
$instance->groupName = $group->name;
|
||||
} else {
|
||||
$instance->groupName = 'Unknown';
|
||||
}
|
||||
$instance->prefs = json_decode( $instance->prefs, true );
|
||||
$instance->gender = $instance->prefs['gender'];
|
||||
$instance->avatar = $instance->prefs['avatar'];
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user data from an ID or username.
|
||||
*
|
||||
* @param {int|string} [$user] - Either the username or user ID being searched for.
|
||||
* @return {bool|array}
|
||||
*/
|
||||
public function get( $user ) {
|
||||
if ( empty( self::$group ) ) {
|
||||
self::$group = new Group;
|
||||
}
|
||||
$user = (string) $user;
|
||||
$field = ( ctype_digit( $user ) ) ? 'ID' : 'username';
|
||||
if ( $field == 'username' ) {
|
||||
if ( !Forms::checkUsername( $user ) ) {
|
||||
Debug::info( 'modelUser->get Username improperly formatted.' );
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( !Check::id( $user ) ) {
|
||||
Debug::info( 'modelUser->get Invalid ID.' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$data = self::$db->get( $this->tableName, [ $field, '=', $user ] );
|
||||
if ( !$data->count() ) {
|
||||
Debug::info( "modelUser->get User not found: $user" );
|
||||
return false;
|
||||
}
|
||||
$this->data = $this->filter( $data->first() );
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a user by email address.
|
||||
*
|
||||
* @param {string} [$email] - The email being searched for.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function findByEmail( $email ) {
|
||||
if ( Check::email( $email ) ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'email', '=', $email ] );
|
||||
if ( $data->count() ) {
|
||||
$this->data = $data->first();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Debug::error( "modelUser->findByEmail - User not found by email: $email" );
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user.
|
||||
*
|
||||
* @param {array} [$fields] - The New User's data.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function create( $fields = [] ) {
|
||||
if ( empty( $fields ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !isset( $fields['email' ] ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !isset( $fields['prefs' ] ) ) {
|
||||
$fields['prefs'] = json_encode( $this->getDefaultPreferences() );
|
||||
}
|
||||
if ( !isset( $fields['userGroup' ] ) ) {
|
||||
$fields['userGroup'] = Config::getValue( 'group/defaultGroup' );
|
||||
} else {
|
||||
if ( in_array( $fields['userGroup'], [ '1', 1 ] ) ) {
|
||||
if ( App::$activeGroup && 'Super' !== App::$activeGroup->name ) {
|
||||
Debug::error( 'You do not have permission to do this.' );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !isset( $fields['registered' ] ) ) {
|
||||
$fields['registered'] = time();
|
||||
}
|
||||
if ( !isset( $fields['confirmed' ] ) ) {
|
||||
$code = Code::genConfirmation();
|
||||
$fields['confirmed'] = 0;
|
||||
$fields['confirmationCode'] = $code;
|
||||
Email::send( $fields['email'], 'confirmation', $code, [ 'template' => true ] );
|
||||
}
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::error( 'User not created.' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user database entry.
|
||||
*
|
||||
* @param {array} [$fields] - The fields to be updated.
|
||||
* @param {int} [$id] - The user ID being updated.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function update( $id, $fields = [] ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'userUpdate' );
|
||||
Debug::error( "User: $id not updated: $fields" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user's preferences.
|
||||
*
|
||||
* @param {array} [$fields] - The fields to be updated.
|
||||
* @param {int} [$id] - The user ID being updated.
|
||||
* @return {bool}
|
||||
*/
|
||||
public function updatePrefs( $fields, $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
$userData = $this->get( $id );
|
||||
$prefsInput = $userData->prefs;
|
||||
foreach ( $fields as $name => $value ) {
|
||||
$prefsInput[$name] = $value;
|
||||
}
|
||||
$fields = [ 'prefs' => json_encode( $prefsInput ) ];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
Debug::error( "User: $id not updated." );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the most recent database data.
|
||||
*
|
||||
* @return {array} - An array of the user data.
|
||||
*/
|
||||
public function data() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function findByToken( $token ) {
|
||||
$data = self::$db->get( $this->tableName, [ 'auth_token', '=', $token ] );
|
||||
if ( ! $data->count() ) {
|
||||
return false;
|
||||
}
|
||||
return $data->first();
|
||||
}
|
||||
|
||||
public function addAccessToken( $id, $length = 64 ) {
|
||||
if ( ! Check::id( $id ) ) {
|
||||
return false;
|
||||
}
|
||||
$fields = [ 'auth_token' => $this->generateRandomString( $length ) ];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
Debug::error( "User: $id not updated." );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function generateRandomString( $length = 10 ) {
|
||||
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$charactersLength = strlen( $characters );
|
||||
$randomString = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$randomString .= $characters[random_int(0, $charactersLength - 1)];
|
||||
}
|
||||
return $randomString;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user