Skip to content

fix: UserModel::save() can't update User's email/password #275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 15, 2022

Conversation

kenjis
Copy link
Member

@kenjis kenjis commented Jul 3, 2022

Fixes #254
Fixes #253

  • UserModel::save(), update() and insert() save Email Identity with Model Events
  • fix UserModel::findByCredentials()
  • fix RegisterController::registerAction()
  • fix User::saveEmailIdentity()
  • add ValidationException
  • update docs/quickstart.md

@kenjis kenjis added the bug Something isn't working label Jul 3, 2022
@kenjis kenjis marked this pull request as draft July 3, 2022 00:53
@kenjis kenjis force-pushed the fix-usermodel-save branch from 8cde372 to 19b44c2 Compare July 3, 2022 01:03
Copy link
Member

@MGatner MGatner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this works then let's go with it but I still have plans to add the original method parameters to the event data in the framework, which would make this much easier.

@MGatner
Copy link
Member

MGatner commented Jul 3, 2022

Sorry, I didn't mean to hit "approve" - I'm good with the approach but obviously will need to pass tests 😂

@datamweb
Copy link
Collaborator

datamweb commented Jul 3, 2022

Sorry, I didn't mean to hit "approve" - I'm good with the approach but obviously will need to pass tests 😂

@MGatner this PR is in position Draft. But you are in a hurry to improve Shield. This is great.

@kenjis kenjis requested a review from MGatner July 3, 2022 21:09
@kenjis
Copy link
Member Author

kenjis commented Jul 3, 2022

I removed the approval.

@kenjis
Copy link
Member Author

kenjis commented Jul 3, 2022

If this works then let's go with it but I still have plans to add the original method parameters to the event data in the framework, which would make this much easier.

The enhancement is good, but we need to wait for v4.3. So I think this PR is needed.

@kenjis kenjis marked this pull request as ready for review July 4, 2022 06:28
@kenjis
Copy link
Member Author

kenjis commented Jul 4, 2022

Okay, I think this is ready for reviews.

@kenjis
Copy link
Member Author

kenjis commented Jul 4, 2022

I think UserModel::save() should be renamed.

  1. It is confusing only save() is overridden and can save email/password. insert()/update() does not work.
  2. Can't change the method signature.

@MGatner
Copy link
Member

MGatner commented Jul 4, 2022

@kenjis I agree. I think the ultimate solution is to modify CodeIgniter\BaseModel::update() (and probably insert()) to preserve the original $data parameter and pass that as an additional key into the beforeInsert and afterInsert methods. That would give Shield access to the User Entity without needing a separate database query and it wouldn't need to override any model methods.
Since that will require a new framework release I like your solution for the meantime... something like UserModel::saveWithIdentities(User $user) right?

@kenjis kenjis force-pushed the fix-usermodel-save branch from c811ad5 to 057b221 Compare July 5, 2022 02:26
@kenjis
Copy link
Member Author

kenjis commented Jul 5, 2022

something like UserModel::saveWithIdentities(User $user) right?

Yes. I added a commit: 39aaf14

@kenjis kenjis force-pushed the fix-usermodel-save branch from 057b221 to 39aaf14 Compare July 5, 2022 02:31
@kenjis kenjis force-pushed the fix-usermodel-save branch from 4581609 to 76b15a5 Compare July 6, 2022 02:10
@kenjis kenjis requested a review from MGatner July 6, 2022 02:12
*/
public function save($data): bool
public function saveWithEmailIdentity(User $data): void
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we need to rename this for a specific reason? If so, or the team majority says we should then ok, but I'm in favor of keeping it as an override of Model::save.

I understand this is a more specific naming, but the whole purpose of the override was to make it as seamless as possible for the developer so they didn't have to think too much about it. This forces them to remember a new method for that single model, which is inconvenient and, as far as I can tell, unnecessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading back through I see the discussion between you two so I'm overruled here. Just going on the record to say I disagree :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👹 Contention noted!

I think this does two good things for us:

  1. It lets us still use save() without messing with identities.
  2. It allows us to force the User type parameter which makes this method much easier to handle.

Also just to say it again: this should just be a temporary measure until we get better Model event parameters in place.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I overrode save() again.

After all, if save() is going to be used in the future, it is better for users to use save() now.

It is confusing only save() can save Email Identity, but users do not need to use insert() or update().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative idea...

The whole reason we override this method is that afterInsert and afterUpdate receive the data as an array, not the original User entity, and that array is filtered by $allowedFields so the credentials are stripped. What if we override insert() and update() to store credentials in a new private property before calling parent::method() and then still use the after____ methods to handle the identities, just using the stored versions instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added UserModel::saveEmailIdentity() and the Model Events call it when afterInsert and afterUpdate.

Copy link
Member

@MGatner MGatner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@manukieli
Copy link

I try de update the password to existent user and it not working, when the user try to login with new password he get this error message: "Please check your password."
I can update the username, the email, but the password not working to update.

@datamweb
Copy link
Collaborator

datamweb commented Jul 8, 2022

hi @manukieli,
Please see #280.

@kenjis kenjis force-pushed the fix-usermodel-save branch from 4d4ce9d to ed7ff5e Compare July 12, 2022 07:02
@kenjis kenjis requested review from MGatner and lonnieezell July 12, 2022 07:09
@kenjis
Copy link
Member Author

kenjis commented Jul 12, 2022

I rewrote UserModel::save() (and update(), insert()) with the Model Events.
Review please.

Copy link
Member

@MGatner MGatner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking a pass at this @kenjis! It didn't end up being quite as clean as I hoped but I still think it is a big improvement. I wish we had the allowEmpty() method, but what can you do 🤷‍♂️

One of the strengths to this approach is that we can support "normal" model operations instead of relying on special use cases with save(). To that end I think that we should still support array parameters, and just have the callback events skip identity updates whenever there is no $tempUser. I'm happy to hear an alternate opinion but I think that improves the transparency of these methods, which I believe was @lonnieezell's original intent.

* Override the BaseModel's `save()` method to allow
* updating of user email, password, or password_hash
* fields if they've been modified.
* @param User $data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should still support arrays, and the callback events would just ignore them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly, I am not sure why it is necessary to accept arrays, but I implemented it that way to try it out.

@kenjis kenjis requested a review from MGatner July 14, 2022 00:56
@kenjis kenjis force-pushed the fix-usermodel-save branch from bc7b647 to d9410fe Compare July 14, 2022 00:59
Comment on lines 292 to 301
$user->saveEmailIdentity();

return $data;
}

// Update
$this->tempUser->saveEmailIdentity();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know $tempUser is reset on each call but I would feel better if it were also reset after the identity update, unless there is some logical reason to keep it around.

Suggested change
$user->saveEmailIdentity();
return $data;
}
// Update
$this->tempUser->saveEmailIdentity();
$this->tempUser = $user;
}
// Update and reset
$this->tempUser->saveEmailIdentity();
$this->tempUser = null;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added $this->tempUser = null.

@kenjis kenjis force-pushed the fix-usermodel-save branch from d9410fe to 1ecdbdd Compare July 15, 2022 08:32
@kenjis kenjis requested a review from MGatner July 15, 2022 08:34
Copy link
Member

@MGatner MGatner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one has been a long road! Thanks for all your work on it @kenjis. I believe it's ready!

@kenjis kenjis merged commit 93f607f into codeigniter4:develop Jul 15, 2022
@kenjis kenjis deleted the fix-usermodel-save branch July 15, 2022 22:32
@kenjis
Copy link
Member Author

kenjis commented Jul 15, 2022

@MGatner Thank you for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

UserModel::save() can't update User's email/password UserModel::save() can't save new User email/password
5 participants