web2py check password in form - passwords

I am trying to create a change password form in web2py. I am using db.auth_user table. I want to create a form with fields ['current_password', 'new_password', 'repeat_password']
Form should give a warning to user if the password is not entered correctly.
My code is:
request.vars.current_password = request.vars.current_password if request.vars.current_password else 'xxx'
user_password_form = SQLFORM.factory(Field('current_password', 'password',
requires=IS_EQUAL_TO(db(db.auth_user.id == auth.user_id).select('password').first().password)(
str(db.auth_user.password.validate(request.vars.current_password)[0]))),
Field('new_password', 'password'),
Field('repeat_password', 'password',
requires=IS_EQUAL_TO(request.vars.new_password,
'Passwords do not match')))
I have tested the validation for the following code and it sets a=1 if password is entered correctly. But on the form validation I couldn't figure it out how to implement it
if request.vars.current_password:
if db.auth_user.password.validate(request.vars.current_password)[0] == db(
db.auth_user.id == auth.user_id).select('password').first().password:
a=1
Any ideas how password validation can be achieved?

The web2py Auth system includes a built-in password change action. If you are using the default user action in the default.py controller, you access this form via /myapp/default/user/change_password.
If you prefer to create a separate controller action just for this purpose, you can simply do:
def change_password():
return dict(form=auth.change_password())
and in the associated view:
{{=form}}
Regarding your custom code, you cannot use the IS_EQUAL_TO validator alone, as it takes an expression that must be equal to the value submitted with the form (you cannot call the validator with a transformed value as you have, as that will return a tuple, but the requires attribute must be a callable object that takes a field and a value).
Instead, you could use the CRYPT validator followed by the IS_EQUAL_TO validator in a list -- the first validator will transform the submitted password to a hash, and the second will then test for equality with the stored password hash.
Alternatively, you could use:
def check_password(password):
new_hash = db.auth_user.password.validate(password)[0]
return new_hash == auth.user.password
form = SQLFORM.factory(Field('current_password', 'password')
requires=IS_EXPR(check_password)),
...)
The IS_EXPR validator can take a function that will be passed the value, and the function should return True or False (note, this usage is not documented -- the book only shows the alternative usage, where you provide Python code as a string, which will be exec'ed).

Related

Dynamically create variable in Thymeleaf

I have an object in ${object} and a string in ${attribute}.
for example, the object may be a "user" and the attribute may be "email"
Now I want to access ${user.email}. However this needs to be dynamic as it should also work for ${article.name} and whatever else.
I tried following concatenations, but none of them worked
${__${object.attribute}__}
${__${object}__.__${attribute}__}
${__${object}__+'.'+__${attribute}__}
${${object}+'.'+${attribute}}
You can use this:
<div th:text="${object.__${attribute}__}"></div>
Assuming you have a model containing the following test data:
User user = new User("John", "john.jones#foo.com"); // user has name and email
model.put("object", user);
model.put("attribute", "email");
That will generate:
<div>john.foo#bar.com</div>
The only place where you need to use the preprocessor __${...)__ is the attribute variable.
After preprocessing has been performed, you will be left with the following Thymeleaf expression:
<div th:text="${object.email}"></div>
That will then be processed in the usual way to generate the HTML you need.

How to store logged user in Odoo14

I am trying to store the currently logged user into a many2one field using compute method. It's working fine if i define the Mnay2one field without the store="True" parameter. Actually, i need to save it.
Here is the code:
def get_logged_user(self):
for rec in self:
print('inside get_logged_user---------------',rec.env.user.name)
rec.logged_user_id = rec.env.user.id
logged_user_id = fields.Many2one('res.users',string="Logged user",store=True,compute="get_logged_user")
EDIT:
If you only need to control visibility of a field/button inside QWeb view you could archive this without dedicated field. You could use context.get('uid') to get current user like this:
<button ... invisible="context.get('uid') == assigned_user_id">
But if you need to store logged-in user inside a field you could use default instead of compute.
Something like this:
logged_user_id = fields.Many2one('res.users', string="Logged user", default=lambda self: self.env.user)
Note usage of lambda function.
If you really need to use compute field with store=True you need to specify when to compute it. By using api.depends decorator you can trigger it when your_field is changed.
#api.depends('your_field')
def get_logged_user(self):
But I would ask a question why do you need to store logged-in user inside a field? If you could provide more context maybe we could suggest different solution.

Phalcon working with MySQL routines

I have a MySQL database which has GUID's stored as binary(16) for the primary keys. I'm using a MySQL user defined routine when inserting and selecting to convert the id's to and from GUID's (GUIDToBinary() and BinaryToGUID()).
In order to use my routines in Phalcon, I am setting the 'columns' parameter for the find() and findFirst() model functions which now means i'm working with incomplete objects as the functions return an instance of Phalcon\Mvc\Model\Row.
The docs state when using the columns parameter the following occurs;
Return specific columns instead of the full columns in the model. When
using this option an incomplete object is returned
UserController.php
// Returns Phalcon\Mvc\Model\Row
$incompleteUser = User::find(['columns' => 'BinaryToGUID(id) as id, status, username, password, .....']);
// Create a new user object to update
$user = new User();
// Populate with existing data
$user->assign($incompleteUser->toArray());
// Assign new changes requested by the user
$user->assign($this->request->getPost());
// Update
$user->updateUser();
User.php
public function updateUser()
{
$manager = $this->getModelsManager();
return $manager->executeQuery("UPDATE User SET ..... WHERE id = GUIDToBinary(".$this->getDI()->get('db')->escapeString($this->id).")");
}
Irrespective of the fact that I've explicitly defined an update, an insert is performed due to the Model being in a transient state.
One solution I thought of was to move the binary to GUID conversion into Phalcon by using Model events however I can't find a suitable method for performing the conversion when selecting. Updating/Inserting is possible by using the beforeSave() and beforeUpdate() events. Perhaps I could just have different properties getId() and getIdGuid() within the model but I would prefer to avoid this if possible.
Is there a way to use MySQL user defined routines in Phalcon and hydrate my model so that it remains in a persistent state? Or do i need to go down the raw SQL route for my updates and avoid PHQL?
Thanks in advance for your time.

how do I separate user params vs Action Pack params?

I have a Rails application where user parameters are all provided via a RESTful API with JSON parameters. Specifically, there is no client-side HTML form from which the user posts data: it's raw JSON.
So to create a new Car entry, the user might:
POST www.mysite.com/api/car
model=Ford&year=2012
In my app, by the time I receive this, the Action Pack values are intermingled with the user values in the params[] hash, so I get:
params = {:model=>"Ford", :year=>"2012", :format=>"json", :action=>"create", :controller=>"api/cars"}
What's the best way to separate the user-generated parameters from parameters generated by Action Pack? The best I can think of is to delete the latter:
car_params = params.reject {|k,v| [:format, :action, :controller].member?(k)}
car = car.new(car_params)
but that doesn't smell right. Is there a better way? (For example, can I get Action Pack to encapsulate the user supplied params into a single hash and pass that as a single element of params[]?)
Don't know if it can help, but I'd just create a method in application_controller :
def user_params
return params.reject {|k,v| [:format, :action, :controller].member?(k)}
end
So throughout the code, you can just use user_params when you don't want ActionPack params

Overload of actions in the controller

Is it possible to do an overload of the actions in the controller? I haven't found any info about it and when I tried, I got this error:
The current request for action 'Create' on controller type 'InterviewController' is >ambiguous between the following action methods:
System.Web.Mvc.ViewResult Create() on type >MvcApplication4.MvcApplication4.InterviewController
System.Web.Mvc.ViewResult Create(Int32) on type >MvcApplication4.MvcApplication4.InterviewController
I've tried to do this on another way and I also get a new error that I can't fix. In fact, I created a new action (called create_client instead of create)
I need 2 ways of creating an "opportunite".
I just call the action, and I receive an empty formular in which I just have to insert data.
From a client's page, I must create an "opportunite" with the client that's already completed when the form is displayed to the user. (there is a need of productivity, the user must perform actions as fast as possible).
In the table "opportunite", I've got a column called "FK_opp_client", which is equal to the column "idClient" from the client's table.
I don't get how I can do the second way.
I've created a new action in the controller.
'
' GET: /Opportunite/Create_client
Function Create_client(idclient) As ViewResult
'Dim FK_Client = (From e In db.client
'Where(e.idClient = idclient)
' Select e.nomCompteClient).ToString()
'ViewBag.FK_client = New SelectList(db.client, "idClient", "nomCompteClient", idclient)
Dim opportunite As opportunite = db.opportunite.Single(Function(o) o.idOpportunite = 5)
opportunite.FK_Client = idclient
ViewBag.FK_Client = New SelectList(db.client, "idClient", "nomCompteClient", opportunite.FK_Client)
Return View(opportunite)
End Function
I've tried a few things to get what I wanted, the last one was to copy what was done in the "Edit" action, but for an empty rank. (so I created an empty rank in my DB). I don't think it was a good idea (imagine someone wants to update the DB where idOpportunite = 5...)
Any better ideas?
If you want to keep those two methods under the same name, you will have to implement an ActionSelectionAttribute to decorate them, or use them with different verbs (for example POST and PUT). Please read more details on action method selection process here (old but still true).
Different approach might be making your parameter optional and make action to check if it has been passed or not (through nullable type).