OSB enhancements to date

This commit is contained in:
Deon George
2010-11-30 09:41:08 +11:00
parent 8715a2059b
commit ec6a542bc3
478 changed files with 23423 additions and 9309 deletions

View File

@@ -0,0 +1,289 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* OSB Auth driver.
*
* @package OSB
* @subpackage Account
* @category Auth
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Auth_OSB extends Auth_ORM {
/**
* OSB authentication is controlled via database queries.
*
* This method can be used to test two situations:
* 1) Is the user logged in? ($role == FALSE)
* 2) Can the user run the current controller->action ($role == TRUE)
*
* @param boolean If authentication should be done for this module:method (ie: controller:action).
* @return boolean
*/
public function logged_in($role = NULL, $debug = NULL) {
$status = FALSE;
// Get the user from the session
$user = $this->get_user(FALSE);
// If we are not a valid user object, then we are not logged in
if (is_object($user) AND $user instanceof Model_Account AND $user->loaded()) {
if (Config::sitemode() == Kohana::DEVELOPMENT && Kohana::config('config.site_debug'))
SystemMessage::add(array('title'=>'Debug','type'=>'debug','body'=>Kohana::debug(array('user'=>$user->username,'r'=>$role))));
if (! empty($role)) {
// Get the module details
$module = ORM::factory('module',array('name'=>Request::instance()->controller));
if (! $module->loaded() OR ! $module->status) {
SystemMessage::add(array(
'title'=>'Module is not defined or active in the Database',
'type'=>'warning',
'body'=>sprintf('Module not defined: %s',Request::instance()->controller),
));
} else {
if (Request::instance()->directory)
$method_name = sprintf('%s_%s',Request::instance()->directory,Request::instance()->action);
else
$method_name = Request::instance()->action;
// Get the method number
$method = ORM::factory('module_method',array('module_id'=>$module->id,'name'=>$method_name));
if (! $method->loaded()) {
SystemMessage::add(array(
'title'=>'Method is not defined or active in the Database',
'type'=>'warning',
'body'=>sprintf('Method not defined: %s for %s',Request::instance()->action,$module->name),
));
} else {
// If the role has the authorisation to run the method
$group_method = ORM::factory('group_method')
->where('method_id','=',$method->id);
$roles = '';
foreach ($group_method->find_all() as $gm) {
$roles .= ($roles ? '|' : '').$gm->group->name;
$ro = ORM::factory('group', array('name' => $gm->group->name));
// $ro->id == 0 means all users.
if ($ro->id == 0 OR $user->has('group', $ro)) {
$status = TRUE;
$roles = '';
break;
}
}
if (! $status) {
if (Config::sitemode() == Kohana::DEVELOPMENT)
SystemMessage::add(array(
'title'=>'User is not authorised in Database',
'type'=>'debug',
'body'=>sprintf('Role(s) checked: %s<br/>User: %s</br>Module: %s<br/>Method: %s',$roles,$user->username,$module->name,$method->name),
));
}
}
}
if (Config::sitemode() == Kohana::DEVELOPMENT)
SystemMessage::add(array(
'title'=>'Debug',
'type'=>'debug',
'body'=>sprintf('A-User: <b>%s</b>, Module: <b>%s</b>, Method: <b>%s</b>, Role: <b>%s</b>, Status: <b>%s</b>, Data: <b>%s</b>',
$user->username,Request::instance()->controller,Request::instance()->action,$role,$status,$debug)));
// There is no role, so the method should be allowed to run as anonymous
} else {
if (Config::sitemode() == Kohana::DEVELOPMENT)
SystemMessage::add(array(
'title'=>'Debug',
'type'=>'debug',
'body'=>sprintf('B-User: <b>%s</b>, Module: <b>%s</b>, Method: <b>%s</b>, Status: <b>%s</b>, Data: <b>%s</b>',
$user->username,Request::instance()->controller,Request::instance()->action,'No Role Default Access',$debug)));
$status = TRUE;
}
// Check and see if we have a token to login and run the method
} elseif ((! empty($_REQUEST['token']) AND $token = $_REQUEST['token']) OR $token=Session::instance()->get('token')) {
if ($user=$this->_get_token_user($token) AND $user !== FALSE)
$status = TRUE;
} else {
if (Config::sitemode() == Kohana::DEVELOPMENT)
SystemMessage::add(array('title'=>'Debug','type'=>'debug','body'=>'No user logged in'));
}
return $status;
}
/**
* Gets the currently logged in user from the session.
* Returns FALSE if no user is currently logged in.
*
* @param boolean Check token users too
* @return mixed
*/
public function get_user($tokenuser=TRUE) {
$user = parent::get_user();
// If we are not logged in, see if there is token for the usre
if ($tokenuser AND $user === FALSE AND $token=Session::instance()->get('token')) {
$user = $this->_get_token_user($token);
}
return $user;
}
/**
* Get the user that a token applies to
*
* This will check that the token is valid (not expired and for the request)
*
* @param $token The token
* @return mixed The user
*/
private function _get_token_user($token) {
$mmto = ORM::factory('module_method_token',array('token'=>$token));
$request = Request::instance();
$user = FALSE;
if ($mmto->loaded()) {
if ($mmto->date_expire < time()) {
SystemMessage::add(array(
'title'=>_('Token Not Valid'),
'type'=>'warning',
'body'=>_('Token expired')));
Session::instance()->delete('token');
$mmto->delete();
} else {
// Check that the token is for this URI
$mo = ORM::factory('module',array('name'=>$request->controller));
$mmo = ORM::factory('module_method',
array('name'=>$request->directory ? sprintf('%s_%s',$request->directory,$request->action) : $request->action));
// Ignore the token if this is not the right method.
if ($mmo->id == $mmto->method_id) {
// @todo Implement single use tokens
Session::instance()->set('token',$token);
$user = ORM::factory('account',$mmto->account_id);
}
}
}
return $user;
}
/**
* Logs a user in.
*
* @param string username
* @param string password
* @param boolean enable autologin
* @return boolean
*/
protected function _login($user, $password, $remember)
{
if ( ! is_object($user))
{
$username = $user;
// Load the user
$user = ORM::factory('user');
$user->where($user->unique_key($username), '=', $username)->find();
}
// If the passwords match, perform a login
if ($user->has('group', ORM::factory('group', array('name' => 'Registered Users'))) AND $user->password === $password)
{
if ($remember === TRUE)
{
// Create a new autologin token
$token = ORM::factory('user_token');
// Set token data
$token->user_id = $user->id;
$token->expires = time() + $this->_config['lifetime'];
$token->save();
// Set the autologin cookie
Cookie::set('authautologin', $token->token, $this->_config['lifetime']);
}
// Record our session ID, we may need to update our DB when we get a new ID
$oldsess = session_id();
// Finish the login
$this->complete_login($user);
// Do we need to update databases with our new sesion ID
// @todo figure out where this is best to go
$session_change_trigger = array('cart'=>'session_id');
if (count($session_change_trigger) AND (session_id() != $oldsess)) {
foreach ($session_change_trigger as $t => $c) {
$orm = ORM::factory($t)
->where($c,'=',$oldsess);
$orm->session_id = session_id();
$orm->save_all();
}
}
return TRUE;
}
// Login failed
return FALSE;
}
/**
* Override the supplied find_salt() to enable disabling salt keys
*/
public function find_salt($password) {
$salt = '';
foreach ($this->_config['salt_pattern'] as $i => $offset) {
// Find salt characters, take a good long look...
if (is_numeric($offset))
$salt .= substr($password, $offset + $i, 1);
}
return $salt;
}
/**
* Determine if a user is authorised to view an account
*
* @param integer Account ID
*
* @return boolean TRUE if authorised, FALSE if not.
*/
public function authorised($aid) {
if (! $this->get_user())
return FALSE;
// @todo Consider caching this.
$ao = ORM::factory('account',$this->get_user()->id);
if (! $ao->loaded() OR ($aid != $ao->id AND ! $ao->admin()))
return FALSE;
return TRUE;
}
/**
* Disable KO3 hash_password function
*/
public function hash_password($password,$salt = FALSE) {
return md5($password);
}
}
?>

View File

@@ -0,0 +1,16 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides account management
*
* @package lnApp
* @subpackage Page/Account
* @category Controllers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
* @also [logout]
*/
class Controller_Account extends Controller_TemplateDefault {
}
?>

View File

@@ -0,0 +1,115 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides User Account Update functions
*
* @package OSB
* @subpackage Account
* @category Controllers/User
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Controller_User_Account extends Controller_TemplateDefault {
public $secure_actions = array(
'edit'=>TRUE,
'resetpassword'=>TRUE,
);
public function action_resetpassword() {
$ao = Auth::instance()->get_user();
if (! $ao->loaded())
throw new Kohana_Exception('Account doesnt exist :account ?',array(':account'=>$ao->id));
// @todo Fix this next logic, since matches_ifset is not being called when the value is on the form, but empty
if (empty($_POST['password_confirm']))
$_POST['password_confirm'] = ' ';
// Store our new values
$ao->values($_POST);
// Run validation and save
if ($ao->changed())
if ($ao->check()) {
SystemMessage::add(array(
'title'=>_('Record updated'),
'type'=>'info',
'body'=>_('Your account record has been updated.')
));
$ao->save();
Request::instance()->redirect('login');
} else {
SystemMessage::add(array(
'title'=>_('Record NOT updated'),
'type'=>'error',
'body'=>_('Your updates didnt pass validation.')
));
foreach ($ao->validate()->errors('form_errors') as $field => $error)
SystemMessage::add(array(
'title'=>$field,
'type'=>'error',
'body'=>$error,
));
}
Block::add(array(
'title'=>_('Password Reset'),
'body'=>View::factory('account/password_reset')
->set('record',$ao),
));
$this->template->content = Block::factory();
}
/**
* Show a product
*/
public function action_edit() {
$ao = Auth::instance()->get_user();
if (! $ao->loaded())
throw new Kohana_Exception('Account doesnt exist :account ?',array(':account'=>$ao->id));
// Store our new values
$ao->values($_POST);
// Run validation and save
if ($ao->changed())
if ($ao->check()) {
SystemMessage::add(array(
'title'=>_('Record updated'),
'type'=>'info',
'body'=>_('Your account record has been updated.')
));
$ao->save();
} else {
SystemMessage::add(array(
'title'=>_('Record NOT updated'),
'type'=>'error',
'body'=>_('Your updates didnt pass validation.')
));
foreach ($ao->validate()->errors('form_errors') as $field => $error)
SystemMessage::add(array(
'title'=>$field,
'type'=>'error',
'body'=>$error,
));
}
Block::add(array(
'title'=>sprintf('%s: %s - %s',_('Account Edit'),$ao->accnum(),$ao->name(TRUE)),
'body'=>View::factory('account/edit')
->set('record',$ao),
));
$this->template->content = Block::factory();
}
}
?>

View File

@@ -0,0 +1,76 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* @package lnApp
* @subpackage Auth
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Account extends Model_Auth_UserDefault {
// Relationships
protected $_has_many = array(
'user_tokens' => array('model' => 'user_token'),
'group' => array('through' => 'account_group'),
'invoice' => array(),
'payment'=>array(),
'service' => array(),
);
// Complete our login
public function complete_login() {}
/**
* Return an account name
*/
public function name($withcompany=FALSE) {
if ($withcompany)
return sprintf('%s %s (%s)',$this->first_name,$this->last_name,$this->company);
else
return sprintf('%s %s',$this->first_name,$this->last_name);
}
public function accnum() {
return sprintf('%02s-%06s',Config::siteid(),$this->id);
}
public function date_last() {
return Config::date($this->date_last);
}
public function title($name) {
return StaticList_Title::form($name,$this->title);
}
public function currency($name) {
return StaticListModule::form($name,'currency',$this->currency_id,'id','name',array());
}
public function country($name) {
return StaticListModule::form($name,'country',$this->country_id,'id','name',array());
}
public function language($name) {
// @todo To setup
return 'en';
}
/**
* Get the groups that an account belongs to
*/
public function groups() {
return $this->group->find_all()->as_array();
}
public function admin() {
// @todo Define admins in the config file or DB
$admins = array('Root');
foreach ($this->groups() as $go)
if (in_array($go->name,$admins))
return TRUE;
return FALSE;
}
}

View File

@@ -0,0 +1,54 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* @package lnApp
* @subpackage Auth
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Auth_RoleDefault extends Model_Auth_Role {
protected $_table_names_plural = false;
protected $_object_formated = array();
protected $_formated = FALSE;
protected $_formats = array();
/**
* Format fields for display purposes
*
* @param string column name
* @return mixed
*/
protected function _format() {
$format = Validate::factory($this->_object);
foreach ($this->_formats as $column => $formats)
$format->filters($column,$formats);
if ($format->check())
foreach ($format as $column => $value)
$this->_object_formated[$column] = $value;
$this->_formated = TRUE;
}
/**
* Return a formated columns, as per the model definition
*/
public function display($column) {
// Trigger a load of the record.
$value = $this->__get($column);
// If some of our fields need to be formated for display purposes.
if ($this->_loaded AND ! $this->_formated AND $this->_formats)
$this->_format();
if (isset($this->_object_formated[$column]))
return $this->_object_formated[$column];
else
return $value;
}
}
?>

View File

@@ -0,0 +1,77 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* @package lnApp
* @subpackage Auth
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Auth_UserDefault extends Model_Auth_User {
protected $_table_names_plural = false;
// Validation rules
protected $_rules = array(
'username' => array(
'not_empty' => NULL,
'min_length' => array(4),
'max_length' => array(32),
),
'password' => array(
'not_empty' => NULL,
'min_length' => array(5),
'max_length' => array(42),
),
'password_confirm' => array(
'matches_ifset' => array('password'),
),
'email' => array(
'not_empty' => NULL,
'min_length' => array(4),
'max_length' => array(127),
'email' => NULL,
),
);
// Validation callbacks
protected $_callbacks = array(
'username' => array('username_available'),
'email' => array('email_available'),
);
// Columns to ignore
protected $_ignored_columns = array('password_confirm');
/*
* Complete our login
*
* For some database logins, we may not want to record the user last login
* details in the repository, so we just override that parent function
* here.
*
* We can also do some other post-login actions here.
*/
public function complete_login() {}
/**
* Test to see if a record has been changed
*/
public function changed() {
return ! (empty($this->_changed));
}
/**
* Debug function to see that has() finds
* @todo This function could be removed
*/
public function has_list($alias, $model) {
// Return list of matches
return DB::select()
->from($this->_has_many[$alias]['through'])
->where($this->_has_many[$alias]['foreign_key'], '=', $this->pk())
->where($this->_has_many[$alias]['far_key'], '=', $model->pk())
->execute($this->_db)
->as_array();
}
}