User edition
Added forms that allow user display names to be set and passwords to be changed. All users can modify users at this time.
This commit is contained in:
parent
ad4071b4e8
commit
9cc43ea4fe
4 changed files with 236 additions and 48 deletions
|
@ -25,6 +25,32 @@ REVOKE EXECUTE ON FUNCTION users_add( TEXT , TEXT , INT , TEXT , TEXT ) FROM PUB
|
|||
GRANT EXECUTE ON FUNCTION users_add( TEXT , TEXT , INT , TEXT , TEXT) TO :webapp_user;
|
||||
|
||||
|
||||
--
|
||||
-- Update an user's address and display name
|
||||
--
|
||||
|
||||
CREATE OR REPLACE FUNCTION users_edit( _id INT , _email TEXT , _name TEXT )
|
||||
RETURNS INT
|
||||
LANGUAGE PLPGSQL
|
||||
STRICT VOLATILE SECURITY INVOKER
|
||||
AS $users_edit$
|
||||
BEGIN
|
||||
IF _name = '' THEN
|
||||
_name := NULL;
|
||||
END IF;
|
||||
|
||||
UPDATE users SET user_email = _email , user_display_name = _name
|
||||
WHERE user_id = _id;
|
||||
RETURN ( CASE WHEN FOUND THEN 0 ELSE 2 END );
|
||||
EXCEPTION
|
||||
WHEN unique_violation THEN
|
||||
RETURN 1;
|
||||
END;
|
||||
$users_edit$;
|
||||
|
||||
REVOKE EXECUTE ON FUNCTION users_edit( INT , TEXT , TEXT ) FROM PUBLIC;
|
||||
GRANT EXECUTE ON FUNCTION users_edit( INT , TEXT , TEXT ) TO :webapp_user;
|
||||
|
||||
|
||||
--
|
||||
-- View that lists users and adds the string to use when displaying
|
||||
|
|
|
@ -15,6 +15,25 @@ class Dao_Users
|
|||
return $hash;
|
||||
}
|
||||
|
||||
private function hashNewPassword( $password )
|
||||
{
|
||||
$iterations = rand( 130 , 160 );
|
||||
|
||||
$randSource = array( );
|
||||
for ( $i = 0 ; $i < 26 ; $i ++ ) {
|
||||
array_push( $randSource , chr( $i + ord( 'a' ) ) );
|
||||
array_push( $randSource , chr( $i + ord( 'A' ) ) );
|
||||
if ( $i < 10 ) {
|
||||
array_push( $randSource , chr( $i + 48 ) );
|
||||
}
|
||||
}
|
||||
shuffle( $randSource );
|
||||
$salt = join( '' , array_splice( $randSource , 0 , 4 ) );
|
||||
|
||||
$hash = $this->hashPassword( $password , $salt , $iterations );
|
||||
return array( $iterations , $salt , $hash );
|
||||
}
|
||||
|
||||
|
||||
public function getUsers( )
|
||||
{
|
||||
|
@ -25,9 +44,20 @@ class Dao_Users
|
|||
}
|
||||
|
||||
|
||||
public function getUserById( $uid )
|
||||
{
|
||||
$query = $this->query( 'SELECT * FROM users_view WHERE user_id = $1' );
|
||||
$results = $query->execute( $uid );
|
||||
if ( empty( $results ) ) {
|
||||
return null;
|
||||
}
|
||||
return array_shift( $results );
|
||||
}
|
||||
|
||||
|
||||
public function getUser( $email )
|
||||
{
|
||||
$query = $this->query( 'SELECT * FROM users WHERE user_email = LOWER( $1 )' );
|
||||
$query = $this->query( 'SELECT * FROM users_view WHERE user_email = LOWER( $1 )' );
|
||||
$results = $query->execute( $email );
|
||||
if ( empty( $results ) ) {
|
||||
return null;
|
||||
|
@ -53,21 +83,7 @@ class Dao_Users
|
|||
|
||||
public function addUser( $email , $password , $name )
|
||||
{
|
||||
$iterations = rand( 130 , 160 );
|
||||
|
||||
$randSource = array( );
|
||||
for ( $i = 0 ; $i < 26 ; $i ++ ) {
|
||||
array_push( $randSource , chr( $i + ord( 'a' ) ) );
|
||||
array_push( $randSource , chr( $i + ord( 'A' ) ) );
|
||||
if ( $i < 10 ) {
|
||||
array_push( $randSource , chr( $i + 48 ) );
|
||||
}
|
||||
}
|
||||
shuffle( $randSource );
|
||||
$salt = join( '' , array_splice( $randSource , 0 , 4 ) );
|
||||
|
||||
$hash = $this->hashPassword( $password , $salt , $iterations );
|
||||
|
||||
list( $iterations , $salt , $hash ) = $this->hashNewPassword( $password );
|
||||
$result = $this->query( 'SELECT users_add( $1 , $2 , $3 , $4 , $5 ) AS error' )
|
||||
->execute( $email , $salt , $iterations , $hash , $name );
|
||||
return $result[ 0 ]->error;
|
||||
|
@ -79,4 +95,23 @@ class Dao_Users
|
|||
$result = $this->query( 'SELECT COUNT(*) AS n_users FROM users' )->execute( );
|
||||
return $result[0]->n_users > 0;
|
||||
}
|
||||
|
||||
|
||||
public function modify( $id , $email , $name )
|
||||
{
|
||||
$result = $this->query( 'SELECT users_edit( $1 , $2 , $3 ) AS error'
|
||||
)->execute( $id , $email , $name );
|
||||
return $result[0]->error;
|
||||
}
|
||||
|
||||
|
||||
public function setPassword( $id , $password )
|
||||
{
|
||||
list( $iterations , $salt , $hash ) = $this->hashNewPassword( $password );
|
||||
$this->query(
|
||||
'UPDATE users '
|
||||
. 'SET user_iterations = $1 , user_salt = $2 , user_hash = $3 '
|
||||
. 'WHERE user_id = $4'
|
||||
)->execute( $iterations , $salt , $hash , $id );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,5 +9,8 @@ $package[ 'pages' ][] = 'tasks_users';
|
|||
$package[ 'ctrls' ][] = 'users_list';
|
||||
$package[ 'ctrls' ][] = 'users_add';
|
||||
$package[ 'ctrls' ][] = 'users_add_form';
|
||||
$package[ 'ctrls' ][] = 'users_edit';
|
||||
$package[ 'ctrls' ][] = 'users_edit_form';
|
||||
$package[ 'ctrls' ][] = 'users_set_password';
|
||||
|
||||
$package[ 'views' ][] = 'users_list';
|
||||
|
|
|
@ -9,6 +9,7 @@ class Page_TasksUsers
|
|||
parent::__construct( array(
|
||||
'' => 'users_list' ,
|
||||
'add' => 'users_add_form' ,
|
||||
'edit' => 'users_edit_form' ,
|
||||
) );
|
||||
$this->setTitle( 'Users' );
|
||||
}
|
||||
|
@ -31,6 +32,56 @@ class Ctrl_UsersList
|
|||
}
|
||||
|
||||
|
||||
|
||||
class View_UsersList
|
||||
extends BaseURLAwareView
|
||||
{
|
||||
private $users;
|
||||
|
||||
public function __construct( $users )
|
||||
{
|
||||
$this->users = $users;
|
||||
}
|
||||
|
||||
public function render( )
|
||||
{
|
||||
$table = HTML::make( 'table' )
|
||||
->appendElement( HTML::make( 'tr' )
|
||||
->setAttribute( 'class' , 'header' )
|
||||
->appendElement( HTML::make( 'th' )
|
||||
->appendText( 'E-mail address' ) )
|
||||
->appendElement( HTML::make( 'th' )
|
||||
->appendText( 'Display name' ) ) );
|
||||
|
||||
foreach ( $this->users as $user ) {
|
||||
$table->appendElement( $this->makeUserRow( $user ) );
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function makeUserRow( $user )
|
||||
{
|
||||
$row = HTML::make( 'tr' )
|
||||
->appendElement( HTML::make( 'td' )
|
||||
->appendElement( $editLink = HTML::make( 'a' ) ) );
|
||||
|
||||
$editLink->setAttribute( 'href' , $this->base . '/users/edit?id=' . $user->user_id )
|
||||
->appendText( $user->user_email );
|
||||
|
||||
$nameColumn = HTML::make( 'td' );
|
||||
if ( $user->user_display_name !== null ) {
|
||||
$nameColumn->appendText( $user->user_display_name );
|
||||
} else {
|
||||
$nameColumn->appendElement( HTML::make( 'em' )->appendText( 'N/A' ) );
|
||||
}
|
||||
$row->appendElement( $nameColumn );
|
||||
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Ctrl_UsersAddForm
|
||||
extends Controller
|
||||
{
|
||||
|
@ -126,48 +177,121 @@ class Ctrl_UsersAdd
|
|||
}
|
||||
|
||||
|
||||
|
||||
class View_UsersList
|
||||
extends BaseURLAwareView
|
||||
class Ctrl_UsersEditForm
|
||||
extends Controller
|
||||
{
|
||||
private $users;
|
||||
|
||||
public function __construct( $users )
|
||||
public function handle( Page $page )
|
||||
{
|
||||
$this->users = $users;
|
||||
try {
|
||||
$userId = (int) $this->getParameter( 'id' );
|
||||
} catch ( ParameterException $e ) {
|
||||
return 'users';
|
||||
}
|
||||
$user = Loader::DAO( 'users' )->getUserById( $userId );
|
||||
if ( $user === null ) {
|
||||
return 'users';
|
||||
}
|
||||
|
||||
public function render( )
|
||||
$page->setTitle( 'Modify user ' . $user->user_view_name );
|
||||
|
||||
$details = Loader::Create( 'Form' , 'Modify user' , 'user-edit' , 'Account details' )
|
||||
->addField( Loader::Create( 'Field' , 'id' , 'hidden' )
|
||||
->setDefaultValue( $user->user_id ) )
|
||||
->addField( Loader::Create( 'Field' , 'email' , 'text' )
|
||||
->setDescription( 'E-mail address:' )
|
||||
->setValidator( Loader::Create( 'Validator_Email' , 'Invalid address.' ) )
|
||||
->setDefaultValue( $user->user_email ) )
|
||||
->addField( Loader::Create( 'Field' , 'display-name' , 'text' )
|
||||
->setDescription( 'Display name:' )
|
||||
->setMandatory( false )
|
||||
->setValidator( Loader::Create( 'Validator_StringLength' , 'This display name',
|
||||
5 , 256 , true ) )
|
||||
->setDefaultValue( $user->user_display_name ) )
|
||||
->addController( Loader::Ctrl( 'users_edit' ) )
|
||||
->setURL( 'users' );
|
||||
|
||||
$password = Loader::Create( 'Form' , 'Modify password' , 'user-set-password' , 'Account password' )
|
||||
->addField( Loader::Create( 'Field' , 'id' , 'hidden' )
|
||||
->setDefaultValue( $user->user_id ) )
|
||||
->addField( Loader::Create( 'Field' , 'pass' , 'password' )
|
||||
->setDescription( 'New password:' )
|
||||
->setValidator( Loader::Create( 'Validator_StringLength' , 'This password' , 8 ) ) )
|
||||
->addField( Loader::Create( 'Field' , 'pass2' , 'password' )
|
||||
->setDescription( 'Confirm new password:' ) )
|
||||
->addController( Loader::Ctrl( 'users_set_password' ) )
|
||||
->setSuccessURL( 'users' );
|
||||
|
||||
return array( $details->controller( ) , $password->controller( ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Ctrl_UsersEdit
|
||||
extends Controller
|
||||
implements FormAware
|
||||
{
|
||||
$table = HTML::make( 'table' )
|
||||
->appendElement( HTML::make( 'tr' )
|
||||
->setAttribute( 'class' , 'header' )
|
||||
->appendElement( HTML::make( 'th' )
|
||||
->appendText( 'E-mail address' ) )
|
||||
->appendElement( HTML::make( 'th' )
|
||||
->appendText( 'Display name' ) ) );
|
||||
private $form;
|
||||
|
||||
foreach ( $this->users as $user ) {
|
||||
$table->appendElement( $this->makeUserRow( $user ) );
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function makeUserRow( $user )
|
||||
public function setForm( Form $form )
|
||||
{
|
||||
$row = HTML::make( 'tr' )
|
||||
->appendElement( HTML::make( 'td' )
|
||||
->appendText( $user->user_email ) );
|
||||
$this->form = $form;
|
||||
}
|
||||
|
||||
$nameColumn = HTML::make( 'td' );
|
||||
if ( $user->user_display_name !== null ) {
|
||||
$nameColumn->appendText( $user->user_display_name );
|
||||
} else {
|
||||
$nameColumn->appendElement( HTML::make( 'em' )->appendText( 'N/A' ) );
|
||||
}
|
||||
$row->appendElement( $nameColumn );
|
||||
|
||||
return $row;
|
||||
public function handle( Page $page )
|
||||
{
|
||||
$id = $this->form->field( 'id' )->value( );
|
||||
$name = $this->form->field( 'display-name' )->value( );
|
||||
$emailField = $this->form->field( 'email' );
|
||||
$email = $emailField->value( );
|
||||
|
||||
$error = Loader::DAO( 'users' )->modify( $id , $email , $name );
|
||||
switch ( $error ) {
|
||||
|
||||
case 0:
|
||||
return true;
|
||||
|
||||
case 1:
|
||||
$email->putError( 'Duplicate address.' );
|
||||
break;
|
||||
|
||||
default:
|
||||
$email->putError( 'An unknown error occurred (' . $error . ')' );
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Ctrl_UsersSetPassword
|
||||
extends Controller
|
||||
implements FormAware
|
||||
{
|
||||
private $form;
|
||||
|
||||
|
||||
public function setForm( Form $form )
|
||||
{
|
||||
$this->form = $form;
|
||||
}
|
||||
|
||||
|
||||
public function handle( Page $page )
|
||||
{
|
||||
$p1 = $this->form->field( 'pass' );
|
||||
$p2 = $this->form->field( 'pass2' );
|
||||
if ( $p1->value( ) != $p2->value( ) ) {
|
||||
$p1->putError( 'Passwords did not match.' );
|
||||
return null;
|
||||
}
|
||||
|
||||
$id = $this->form->field( 'id' )->value( );
|
||||
Loader::DAO( 'users' )->setPassword( $id , $p1->value( ) );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue