Updating Model in dialog from fails

129 views
Skip to first unread message

The Black Pig

unread,
Nov 15, 2012, 8:41:23 AM11/15/12
to agile-too...@googlegroups.com
Hi,

I'm trying to create a reset password function.

My dialog (loaded by frameURL()) opens ok but when I try and save I get the 'Child element not found" error.

page that holds the CRUD snippet:

        $tc = $tab->add('CRUD',array('allow_add'=>$allow_add));
        $tc->setModel($this->api->auth->model,$fields['edit'],$fields['grid']);

        //if ($this->api->auth->model['is_super']) {
            $tc->grid->addColumn('Button','reset_password');

            if ($tc->grid){
                $tab->api->stickyGet('id');

                if($_GET['reset_password']){
                    $tab->js()->univ()
                        ->frameURL('Reset Password',$this->api->url('admin/resetpassword',array('id'=>$_GET['reset_password'])))
                    ->execute();
                }
            }
        //}

The admin/passwordreset.php page

class page_admin_resetpassword extends Page {
    function init(){
        parent::init();

        $this->api->addLocation('atk4-addons',array(
            'php'=>'misc/lib'
        ));

        $id = $_GET['id'];

        $m = $this->add($this->api->auth->model);
        $m->loadData($_GET['id']);


        $this->add('P')->setHTML('<strong>Resetting password for ' . $m['full_name'] . '</strong>');

        $f = $this->add('Form');

        //add fields to form - don't load via model as password field will display hashed value
        $f->addField('password','new_Password')->add('StrengthChecker',null,'after_field');
        $f->addField('password','password_confirm', 'Confirm password');
        $f->addSubmit('Change Password');

        $f->addClass('stacked');

        if($f->isSubmitted()){
            if($f->get('new_password') != $f->get('password_confirm')){
                $f->displayError('password','Passwords do not match!');
            } else {
                //we have a value so set the model and update
                $m->set('password', $f->get('new_password'));
                $m->save();
            }

            $f->js()->univ()->successMessage('Password Changed')->execute();
        }
    }

Th error is shown via a JS alert can bee seen in this screen grab

Thanks
BP

Romans Malinovskis

unread,
Nov 15, 2012, 8:44:42 AM11/15/12
to agile-too...@googlegroups.com
should be displayError(’new_Password’);

            } else {
                //we have a value so set the model and update
                $m->set('password', $f->get('new_password'));
                $m->save();
            }

            $f->js()->univ()->successMessage('Password Changed')->execute();
        }
    }

Th error is shown via a JS alert can bee seen in this screen grab

Thanks
BP


--
 
 

--
I am working with my team on a VERY URGENT project now. I apologize for the delay in answering your email(s).

Romans Malinovskis is the author of the revolutionary PHP Framework: the “Agile Toolkit” (www.agiletoolkit.org). Please show your support by raising awareness about Agile Toolkit.

Refer commercial web development projects towards our skilled developer team: http://www.agiletech.ie/company/


NEW: Learn Agile Toolkit with over 10 hours of practical screencast footage: htttp://agiletoolkit.org/tutorial 

Romans Malinovskis

unread,
Nov 15, 2012, 8:55:44 AM11/15/12
to agile-too...@googlegroups.com
BTW - i still see the cogs, are they being stuck even after you refresh the javascript?

Regards,
Romans
--

The Black Pig

unread,
Nov 15, 2012, 8:57:27 AM11/15/12
to agile-too...@googlegroups.com
Thanks Romans,

Now I'm getting a new window with following error:

Error in AJAX response: SyntaxError: Unexpected token <

BaseException

sha256 requires salt (2nd argument to encryptPassword and is normaly an email)

:

Stack trace:
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/BaseException.php:38 BaseExceptionBaseException->collectBasicData(Null, Null, Null)
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/AbstractObject.php:300 BaseExceptionBaseException->__construct("sha256 requires salt (2nd argument to encryptPassword and is normaly an email)", Null, Null, Null)
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/Auth/Basic.php:182 enjouanissonoffice_authAuth->exception("sha256 requires salt (2nd argument to encryptPassword and is normaly an email)")
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/Auth/Basic.php:129 enjouanissonoffice_authAuth->encryptPassword("a", Null)
/: Logger{closure}(Object(Model_User))
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/AbstractObject.php:435 Loggercall_user_func_array(Object(Closure), Array(1))
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/Model/Table.php:555 enjouanissonoffice_auth_model_userModel_User->hook("beforeSave")
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/page/admin/resetpassword.php:31 enjouanissonoffice_auth_model_userModel_User->save()
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/AbstractObject.php:197 enjouanissonoffice_admin_resetpasswordpage_admin_resetpassword->init()
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/ApiFrontend.php:122 enjouanissonofficeFrontend->add("page_admin_resetpassword", "admin_resetpassword", "Content")
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/ApiWeb.php:399 enjouanissonofficeFrontend->layout_Content()
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/ApiFrontend.php:37 enjouanissonofficeFrontend->addLayout("Content")
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/atk4/lib/ApiWeb.php:271 enjouanissonofficeFrontend->initLayout()
/Volumes/Data/Work/Black Pig/Enjouanisson/Office/index.php:15 enjouanissonofficeFrontend->main()


But the page has already loaded the model and the model has called loadData() - so why can't it get a handle to the email?

The Black Pig

unread,
Nov 15, 2012, 8:59:50 AM11/15/12
to agile-too...@googlegroups.com
Yep I get the cogs on an Ajax load - they never disappear even after the content has loaded.

I've cleared my cache but I haven't pulled the latest version from Git. At the moment it's not a show stopper for me - something I can look once I have the core functionality finished.

Romans Malinovskis

unread,
Nov 15, 2012, 9:03:56 AM11/15/12
to agile-too...@googlegroups.com
Possibly you don’t have the ‘email’ field in your user model. You need to use some other field as salt:

    function setModel($model,$login_field='email',$password_field='password'){

(second argument)

It makes sure that two different users with same password won’t have the same password hash. 


--
 
 

--
I am working with my team on a VERY URGENT project now. I apologize for the delay in answering your email(s).

Romans Malinovskis is the author of the revolutionary PHP Framework: the “Agile Toolkit” (www.agiletoolkit.org). Please show your support by raising awareness about Agile Toolkit.

Refer commercial web development projects towards our skilled developer team: http://www.agiletech.ie/company/

Romans Malinovskis

unread,
Nov 15, 2012, 9:08:50 AM11/15/12
to agile-too...@googlegroups.com
Ok, if that’s an issue, I’d like to hear more about it. 

file ui.atk4_loader.js


        if(this.options.cogs){
            var l=$(this.options.cogs);
l.prependTo(self.element);
            l.hide();
            self.loader=l;
        }

and then in line 254 after loading is done, it hides itself:

},function(){ // second callback, which is always called, when loading is completed
            self.loader.hide();
self.loading=false;
});


If that is not working, you can try moving the loader.hide() method to line 177, after $.atk4.get(), which will hide cogs sooner, before the content is ready to be displayed still.


The Black Pig

unread,
Nov 15, 2012, 9:12:26 AM11/15/12
to agile-too...@googlegroups.com

The email is defined in the model (its a mandatory field) and it is being loaded as I have just output it to the form.

I don't understand why the model, which has loaded the data, is not automatically referencing the email field?

The Black Pig

unread,
Nov 15, 2012, 12:47:32 PM11/15/12
to agile-too...@googlegroups.com

Something screwy is going on here, it seems to be losing a reference to the model.

If I set the email before the update:

$m->set('password', $f->get('new_password'));

$$m
->set('email', $email);
$m
->update();


Then I get the same sha256 requires salt (2nd argument to encryptPassword and is normaly an email)

If I make the email dirty:
$m->set('password', $f->get('new_password'));
$$m->set('email', $email."dirty");
$m->update();

Then it inserts a new blank record - but the email address just consists of 'dirty' not em...@email.comdirty

I don't know why but I am losing the handle or reference to the model data.

here's the page code again

class page_admin_resetpassword extends Page {
    function init(){
        parent::init();

        $this->api->addLocation('atk4-addons',array(
            'php'=>'misc/lib'
        ));

        $id = $_GET['id'];

        $m =$this->api->auth->model;
        $m->loadData($id);

        $email = $m['email'];


        $this->add('P')->setHTML('<strong>Resetting password for ' . $m['email'] . '</strong>');  //shoes email in form, data is retrieved

        $f = $this->add('Form');
        $f->addField('password','new_password')->add('StrengthChecker',null,'after_field');
        $f->addField('password','password_confirm', 'Confirm password');

        $f->addSubmit('Change Password');

        $f->addClass('stacked');

        if($f->isSubmitted()){
            if($f->get('new_password') != $f->get('password_confirm')){
                $f->displayError('new_password','Passwords do not match!');
            } else {
                $m->set('password', $f->get('new_password'));
                $m->set('email', $email);  //shouldn't be required - testing for sticky update
                $m->update();
            }
        }
    }
}


and this is a variation, where I just deal with $form object but I get the same SHA error listed above

class page_admin_resetpassword extends Page {
    function init(){
        parent::init();

        $this->api->addLocation('atk4-addons',array(
            'php'=>'misc/lib'
        ));

        $id = $_GET['id'];

        $m =$this->api->auth->model;
        $m->loadData($id);

        $this->add('P')->setHTML('<strong>Resetting password for ' . $m['full_name'] . '</strong>');

        $f = $this->add('Form');
        $f->setModel($this->api->auth->model,array('password'));
        $f->getElement('password')->set(null)->add('StrengthChecker',null,'after_field');
        $f->addField('password','password_confirm', 'Confirm password');

        $f->addSubmit('Change Password');

        $f->addClass('stacked');

        if($f->isSubmitted()){

            if($f->get('password') != $f->get('password_confirm')){
                $f->displayError('password','Passwords do not match!');
            } else {
                $f->update();
            }
        }
    }
}


This is driving me nuts :)  

Maybe there is another way that I can change the user password (available to Admins only).

Imants Horsts

unread,
Nov 15, 2012, 1:46:58 PM11/15/12
to agile-too...@googlegroups.com
Sorry have no time this week to read everything and test these cases, but probably small mistake I see in your code is double $$ in here:

$$m->set('email', $email);




The Black Pig

unread,
Nov 21, 2012, 7:04:16 AM11/21/12
to agile-too...@googlegroups.com
Ok,

So this is till a problem but it's changed a bit, as I've modified my approach a little.

The issue now is that the change password form loads ok - but when it saves it creates a New user record - it doesn't update the existing record and the password isn't encrypted.

Also, this is also a bit strange - the Add button the CUD grid - always loads and updates the currently logged-in user - it doesn't create a new user.

Heres' all teh relevant code again:

Admin page:

 function init(){
        parent::init();

        $tabs = $this->add('Tabs');

        // Users tab
        $tab = $tabs->addTab("Users");
        $fields['grid'] = array('full_name','email', 'is_admin');
        $fields['edit'] = array('first_name','last_name','email');

        if ($this->api->auth->model['is_super']) {
            $fields['edit'][] = "is_admin";
            $fields['edit'][] = "is_super";
            $allow_add = true;
        } else {
            $allow_add = false;
        }

        $tc = $tab->add('CRUD',array('allow_add'=>$allow_add));
        $tc->setModel($this->api->auth->model,$fields['edit'],$fields['grid']);



        if ($tc->grid){
            $tc->grid->addColumn('Button','reset_password');
            $tc->grid->addOrder()
                ->move('reset_password','before','edit')
                ->now();
        }

        if ($this->api->auth->model['is_super']) {

            if ($tc->grid){
                $this->api->stickyGet('id');

                if($_GET['reset_password']){
                    $tab->js()->univ()
                        ->frameURL('Reset Password',$this->api->url('admin/resetpassword',array('id'=>$_GET['reset_password'])))
                    ->execute();
                }
            }

        }


The resetpassword page 
        parent::init();

        $this->api->addLocation('atk4-addons',array(
            'php'=>'misc/lib'
        ));

        $id = $_GET['id'];

        $m = $this->setModel("User");  //have also tried $this->api->auth->model - makes no diffrence

        $m->loadData($id);

        $this->add('P')->setHTML('<strong>Resetting password for ' . $m['full_name'] . '</strong>');

        $f = $this->add('Form');
        $f->setModel("User",array('password'));  //have also tried adding id to the load array
        $f->loadData($id);  //I don't actually think I need this line anyway
        $f->getElement('password')->set(null)->add('StrengthChecker',null,'after_field');
        $f->addField('password','password_confirm', 'Confirm password');
        $f->addField('hidden','id')->set($id); //trying anything now to get it to update the record and not create new one!

        $f->addSubmit('Change Password');

        $f->addClass('stacked');

        if($f->isSubmitted()){

            if($f->get('password') != $f->get('password_confirm')){
                 $f->displayError('password','Passwords do not match!');
            } else {
                 $f->update();
                 $f->js()->univ(null,$this->js()->_selector('.autoreload')->trigger('autoreload'))
                     ->closeDialog()->execute();
            }
        }
    }
}

the user model

class Model_User extends Model_Table
{
    public $table="users";

    function init(){
        parent::init();
        //$this->debug();
        $err = "This is a required field";
        $this->addField('first_name')->mandatory($err);
        $this->addField('last_name')->mandatory($err);
        $this->addField('email')->mandatory($err);
        $this->addField('password')->type('password')->mandatory($err);
        $this->addField('is_admin')->listData(array(1=>"Yes",0=>"No"))->defaultValue(0);
        $this->addField('is_super')->listData(array(1=>"Yes",0=>"No"))->defaultValue(0);

        $this->addExpression('full_name','CONCAT (`first_name`, " " , `last_name`)');

        $this->setOrder('last_name')->setOrder('first_name');

    }
}

and finally the frontend to see that auth is being set

class Model_User extends Model_Table
{
    public $table="users";

    function init(){
        parent::init();
        //$this->debug();
        $err = "This is a required field";
        $this->addField('first_name')->mandatory($err);
        $this->addField('last_name')->mandatory($err);
        $this->addField('email')->mandatory($err);
        $this->addField('password')->type('password')->mandatory($err);
        $this->addField('is_admin')->listData(array(1=>"Yes",0=>"No"))->defaultValue(0);
        $this->addField('is_super')->listData(array(1=>"Yes",0=>"No"))->defaultValue(0);

        $this->addExpression('full_name','CONCAT (`first_name`, " " , `last_name`)');

        $this->setOrder('last_name')->setOrder('first_name');

    }
}

When the resetpassword dialog is loaded the correct record is being loaded (form $this->debug() in the model)

select `id`,`first_name`,`last_name`,`email`,`password`,`is_admin`,`is_super`,CONCAT (`first_name`, " " , `last_name`) `full_name` from `users` where `id` = "6" order by `users`.`last_name`, `users`.`first_name` limit 0, 1 [:a]

but after the submit is pressed this is what gets sent to the db

insert into `users` (`password`,`is_admin`,`is_super`) values ("pass",NULL,NULL) [:a_3, :a_2, :a]
select `id`,`first_name`,`last_name`,`email`,`password`,`is_admin`,`is_super`,CONCAT (`first_name`, " " , `last_name`) `full_name` from `users` where `id` = "18" order by `users`.`last_name`, `users`.`first_name` limit 0, 1 [:a]

I'm at a complete loss with this.

Stuart


The Black Pig

unread,
Nov 21, 2012, 11:04:07 AM11/21/12
to agile-too...@googlegroups.com
Ok,

so the solution is setting stickyGet in the correct place.

For anyone googling for answers - I thought that stickyGet was applied to the frontendapi scope - so once set was available to all objects within that scope.  This isn't correct, the scope of stickyGet is only for the object it is called on.

So  I had called stickyGet on my page and therefore believed that the parameter would be available across subsequent objects called in the page.

amended code below for competeness

<?php
class page_admin_resetpassword extends Page {
    function init(){
        parent::init();



        $this->api->addLocation('atk4-addons',array(
            'php'=>'misc/lib'
        ));

        $id = $_GET['id'];

        $m = $this->add("Model_User");

        $m->loadData($id);

        $this->add('P')->setHTML('<strong>Resetting password for ' . $m['full_name'] . '</strong>');

        $f = $this->add('Form');
        $f->setModel($this->api->auth->model,array("password"))->loadData($id);
        $f->api->stickyGet('id'); //need to call stickyGet here so that the id value will passed with form/submit url

        $f->getElement('password')->set(null)->add('StrengthChecker',null,'after_field');
        $f->addField('password','password_confirm', 'Confirm password');

        $f->addSubmit('Change Password');

        $f->addClass('stacked');

        $f->onSubmit(function($f){

            if($f->get('password') != $f->get('password_confirm')){
                 $f->displayError('password','Passwords do not match!');
            } else {
                 $f->update();
                 $f->js()->univ(null,$f->js()->_selector('.autoreload')->trigger('autoreload'))
                     ->closeDialog()->execute();
            }
        });
    }
}

Thanks to Romans and Jancha for showing me the error of my ways

Imants Horsts

unread,
Nov 22, 2012, 9:00:30 AM11/22/12
to agile-too...@googlegroups.com
I'm not sure this is fully correct.

Is this form for changing password for only yourself (logged in user) or changing password for any user (if you're admin for example)?

If it's first case, then I don't see need for loading user model one more time in $m. You can memorize user[fullname] in session on login if you can't access it trough $this->api->auth->model['fullname'].

If it's second case, then you probably should replace $this->api->auth->model with just $m.

And probably don't need ->loadData($id) after crud->setModel, because model is already loaded (isn't it?).


Sorry, have not tested this, but ... it's just what came first in my mind when reading your code.
Reply all
Reply to author
Forward
0 new messages