Grails form field always null - forms

I want to add password confirmation to my project's registration page. But I'm having a problem with value of one of my fields. All the fields are ok but the password2 field, it's the confirmation password and is a transient field of User domain class. Here are my Domain, Controller and View codes
Domain class:
class User {
String fullName
String username
String email
String password
String password2
static transients = ['password2']
static constraints = {
username size: 5..15, blank: false, unique: true
email email: true, blank: false
password blank:false, size:5..15, matches:/[\S]+/, validator:{ val, obj ->
if (obj.password != obj.password2)
return 'user.password.dontmatch'
}
}
}
Part of the Controller:
if (request.method == 'POST') {
// create domain object and assign parameters using data binding
def u = new User(params)
if (! u.save()) {
// validation failed, render registration page again
flash.error = "error(s) creating user: Value of the confirmation password is: "+u.password2
//render(view:"/signup",model:[user:user])
return [user:u]
} else {
// validate/save ok, store user in session, redirect to homepage
session.user = u
redirect(controller:'home')
return
}
} else if (session.user) {
// don't allow registration while user is logged in
redirect(controller:'home')
return
}
And a part from the View:
<div><input class="pretty-input ${hasErrors(bean:user,field:'email','input-error')}" type="email" name="email" value="${user?.email}" ></input><span>— Enter email</span></div>
<div><input class="pretty-input ${hasErrors(bean:user,field:'password','input-error')}" type="password" name="password"></input><span>— Choose a password</span></div>
<div><input class="pretty-input ${hasErrors(bean:user,field:'password2','input-error')}" type="password" name="password2"></input><span>— Repeat the password</span></div>
My code works if I remove password's custom validation because password2's value is always null. I why this happens when all other fields works but password2 not.

Trasients fields are not bindables by default, thus you cannot pass params to fill it.
You can do this:
static constraints = {
... your code here
password2 bindable: true
}
But I recommend you to use a command object to validate that condition, it is clever.

Related

Getting user type in mvc using mongodb

I am trying to verify if a user belongs to the Admin group. If he/she does, the admin page can be visible from the browser. So far I have this:
#if (HttpContext.Current.Session["userName"] != null && !Session["userName"].Equals(""))
{
Admin page
}
It works as it is supposed to, displays this route only for people that are logged in, but what about checking the type and allowing only admin users to see it? I also have this method in my userDB.
public string getType(string username) {
var mongoClient = new MongoClient("mongodb://localhost");
var database = mongoClient.GetDatabase("SearchForKnowledge");
var coll = database.GetCollection<BsonDocument>("Users");
var filter = Builders<BsonDocument>.Filter.Eq("userName",username);
var results = coll.Find(filter).ToList().First();
return results["type"].ToString();
}
It just returns the type of the user.
You need to call the getType method by passing the user name as parameter. If return value of getType is Admin then redirect the users to admin page.
string userName= (string)(Session["userName"]);
string result = getType(userName);
if (result == "Admin")
//... redirect the user

Yii2 ActiveForm issue

I have a update user form with fields such as username, email, password, etc. I need the password field to be empty and to update the users.password field in the MySQL database only when the user has filled in the password field. Is it possible? I use the ActiveForm widget of Yii2.
First of all, it's not an Yii2 ActiveForm issue. It can be possible by following some simple steps.
Create two variables in your model, one for storing password, and another is for repeat password field.
public $REPEAT_PASSWORD;
public $INIT_PASSWORD;
then add afterFind function to set null value to your password field, so it wont be shown to user
public function afterFind()
{
//reset the password to null because we don't want password to be shown.
$this->INIT_PASSWORD = $this->PASSWORD;
$this->PASSWORD = null;
parent::afterFind();
}
and now, write beforeSave function to save user password if user has entered on
public function beforeSave()
{
// in this case, we will use the old hashed password.
if(empty($this->PASSWORD) && empty($this->REPEAT_PASSWORD) && !empty($this->INIT_PASSWORD)) {
$this->PASSWORD=$this->REPEAT_PASSWORD=$this->INIT_PASSWORD;
} elseif(!empty($this->PASSWORD) && !empty($this->REPEAT_PASSWORD) && ($this->PASSWORD == $this->REPEAT_PASSWORD)) {
$this->PASSWORD = md5($this->PASSWORD);
$this->REPEAT_PASSWORD = md5($this->REPEAT_PASSWORD);
}
return parent::beforeSave();
}

Fill in boolean field in a form

I have a login form which checks if the user selected "remember me" and if the condition is met, it will automatically fill in the email field.
This is my Form object:
val loginForm = Form(
tuple(
"email" -> email,
"password" -> text(minLength = 3),
"remember" -> boolean
)
)
There may be a KV pair stored in the session ("remember" -> email: String). I have a working function which returns this email as an Option[String].
This is the function which renders the login page. views.html.login is a Template that accepts a Form object and an optional message: String which is used for relaying any authentication errors.
def login = Action {
request => {
logRequest(request)
if (UserInfo.isAuth(request.session)) {
Redirect(routes.Application.index())
}
else {
val email = UserInfo.getRememberedEmail(request.session)
if (email.isDefined) {
Ok(views.html.login(loginForm.fill(email.get, "", true)))
}
else {
Ok(views.html.login(loginForm))
}
}
}
}
I think the problem occurs at Ok(views.html.login(loginForm.fill(email.get, "", true))). When checking the form for errors, this is what I found:
{"remember":["error.boolean"]}

CI - forgot password form validation to check if email address exists in DB

I'm new to working with Codeigniter and need to set a form validation rule and custom validation message for checking if the email address exists in the database that is submitted in a forgot password form. If the email address exists it sends an email, if it doesn't it should reload the form, set the field value to what the user entered and provide an error that the email address doesn't exist.
I've got the following in the controller...
public function forgot_password()
{
$this->form_validation->set_rules('email_address','Email Address','trim|required|valid_email');
if($this->form_validation->run() == FALSE)
{
$this->forgot_password_form();
}
else
{
$this->load->model('membership_model');
if($query = $this->membership_model->val_forgot_password())
{
$data['main_content'] = 'forgot_password_sent';
$this->load->view('includes/template', $data);
}
else
{
$this->form_validation->set_message('email_address','The email address you provided does not exist.');
$this->forgot_password_form();
}
}
}
and in the model...
public function val_forgot_password()
{
$this->db->where('email_address', $this->input->post('email_address'));
$query = $this->db->get($this->members);
if($query->num_rows == 1)
{
return true;
}
else
{
return false;
}
}
and the form is...
<?php
echo form_open('login/forgot_password');
echo "Email Address: " . form_input('email_address', set_value('email_address', ''));
echo br(2);
echo form_submit('submit','Send Email');
echo form_close();
echo br(1);
echo validation_errors('<p>Error: ');
?>
When the form is submitted with a valid email address it correctly goes to the success page but if the email address doesn't exist, it appears to reload the form but does not give an error.
Help pls! :D
You should use a callback to check the email exists. So your controller would be something like...
public function forgot_password()
{
$this->form_validation->set_rules('email_address','Email Address','trim|required|valid_email|callback__check_email_exists');
if($this->form_validation->run() == FALSE)
{
// VALIDATION ERRORS, SHOW VIEWS
}
else
{
// ALL IS GOOD, UPDATE EMAIL, AND REDIRECT TO CURRENT URL
}
}
And your callback (still in your controller) would be something like...
public function _check_email_exists($email)
{
// LOAD AND USE YOUR MODEL TO CHECK EMAIL EXISTS HERE
if ( ! $email_exists )
{
$this->form_validation->set_message('email_address', 'That email address don\'t exist, sucka!');
return FALSE;
}
else
{
return TRUE;
}
}
All this is spelled out in the excellent CI docs here, and I would recommend sticking to the CI conventions if you are new to it.
http://codeigniter.com/user_guide/libraries/form_validation.html
EDIT: There is also another problem i was facing while doing this in codeigniter3. You have to named the message field name to the callback. So instead of $this->form_validation->set_message('email_address', 'That email address don\'t exist, sucka!');
This should be
$this->form_validation->set_message('_check_email_exists', 'That email address don\'t exist, sucka!');
You should extend MY_Form_validation, this way your function can be used on any form, not just those that reside in your controller.

Specflow with MVC Model Validation Issue

I am using Specflow, nunit and moq to test the default MVC2 application registration as I learn SpecFlow.
I have the following steps for checking if the username and password have not been entered.
Steps
[Given(#"The user has not entered the username")]
public void GivenTheUserHasNotEnteredTheUsername()
{
_registerModel = new RegisterModel
{
UserName = null,
Email = "test#dummy.com",
Password = "test123",
ConfirmPassword = "test123"
};
}
[Given(#"The user has not entered the password")]
public void GivenTheUserHasNotEnteredThePassword()
{
_registerModel = new RegisterModel
{
UserName = "user" + new Random(1000).NextDouble().ToString(),
Email = "test#dummy.com",
Password = string.Empty,
ConfirmPassword = "test123"
};
}
[When(#"He Clicks on Register button")]
public void WhenHeClicksOnRegisterButton ()
{
_controller.ValidateModel(_registerModel);
_result = _controller.Register(_registerModel);
}
[Then(#"He should be shown the error message ""(.*)"" ""(.*)""")]
public void ThenHeShouldBeShownTheErrorMessage(string errorMessage, string field)
{
Assert.IsInstanceOf<ViewResult>(_result);
var view = _result as ViewResult;
Assert.IsNotNull(view);
Assert.IsFalse(_controller.ModelState.IsValid);
Assert.IsFalse(view.ViewData.ModelState.IsValidField(field));
Assert.IsTrue(_controller.ViewData.ModelState.ContainsKey(field));
Assert.AreEqual(errorMessage,
_controller.ModelState[field].Errors[0].ErrorMessage);
}
Extension method to force validation
public static class Extensions
{
public static void ValidateModel<T> ( this Controller controller, T modelObject )
{
if (controller.ControllerContext == null)
controller.ControllerContext = new ControllerContext();
Type type = controller.GetType();
MethodInfo tryValidateModelMethod =
type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(
mi => mi.Name == "TryValidateModel" && mi.GetParameters().Count() == 1).First();
tryValidateModelMethod.Invoke(controller, new object[] { modelObject });
}
}`
I do not understand why the password missing test fails on the following lines.
Assert.IsFalse(view.ViewData.ModelState.IsValidField(field));
Assert.IsTrue(_controller.ViewData.ModelState.ContainsKey(field));
I have noticed that the error message being returned is for the Password and ConfirmPassword not matching but I dont understand why for all the other tests, including the Missing Confirm Password test (Identical to the missing Password test) they work fine.
Any ideas?
Features
Scenario: Register should return error if username is missing
Given The user has not entered the username
When He Clicks on Register button
Then He should be shown the error
message "The Username field is required." "username"
Scenario: Register should return error if password is missing
Given The user has not entered the
password
When He Clicks on Register button
Then He should be shown the error message "'Password' must be at least
6 characters long." "Password"
UPDATE
Ok seems the ValidatePasswordLengthAttribute in the Account Model couldn't initilise Membership.Provider as I did not have the connectionstring in my app.config. Is the Pembership.Provider connecting to the membership DB now?
I have added the connection string but now the test passes 50% of the time as it returns two errors:
Password required
Password must be 6 chars long.
The problem is that they are not returned in the same order every time so the test is flaky.
How can I rewrite my scenario and test to account for this? Can I still keep the one "Then" method or do I need to create a new method?
Thanks.
I had to add the connection string the the AccountService to the App.config which nunit uses. This was causing an error on the ValidatePasswordLengthAttribure.
I have updated the Assert which checks for the correct error message to:
Assert.AreEqual(errorMessage,
_controller.ModelState[field].Errors.First(e => e.ErrorMessage == errorMessage).ErrorMessage);
Still unsure about whether the Membership.Provider is hitting the DB