So finally,
now that we've got the basic all flow into sessions, set up,
let's work on the validation side, off the user input.
And of course, just to be clear,
if you try to submit the form,
we got some validation here already built into the browser
thanks to the special HTML attributes we added to our form
input elements in the signup and login forms.
We did add the mid-length max length
and required attributes here.
So we got some basic validation here, but for one,
this can easily be disabled.
If we have a user who knows how to use the dev tools like
you, for example,
that user can simply edit the loaded content here.
I could remove the required attribute and all of a sudden
I'm not getting a warning for that field anymore.
And I could do that for all fields and then submit
the empty form.
And if we have a backend that's not prepared for this and
that doesn't validate the user data on the backend,
then this empty data, could be stored in a database,
which is typically not what we want.
That's why we should never trust our users.
And always also validate the user input on the backend.
On the front end,
we just have the validation and those validation attributes
to provide a better user experience to the majority of our
users who will then see that they forgot to fill in a value
in some fields,
but it's not there to protect us
against malicious or tricky users.
So that's one reason why we want to have service side
validation.
But in addition, there are also a certain checks,
which we can't run on the front end. For example,
checking if a email address already exists,
if we try to create a user with an email address that
already exists in a database,
that is something we don't know in the browser,
that is something we have to check on the server instead,
because that is where we communicate with the database.
And therefore we need to add validation on the backend and
the off controller in the signup function here
before we call user signup and we store all that data.
We want to validate that user input,
and we want to perform various checks here. For example, I,
first of all, want to check if all these fields are valid.
Now we could write all the validation logic here
in the controller,
but as so often I'll work with a separate file
in the util folder here, which I'll name validation JS,
which should hold my validation related logic simply so that
the auth controller can stay leaner.
That's always the reason for splitting up our code,
as you can tell by now.
So in there I'll add a new function.
UserDetailsAreValid sounds like a fitting name
because that function should return true.
If the provided data is valid and false otherwise.
And here, I then expect to get the email, the password,
the name, the street, the postal code, and the city,
because that's the user data we're working with.
And now it's up to you how you want to validate this.
Here I will just return a Boolean value,
which I derived by checking all these different parameter
values for certain aspects. You could say, for example,
an email is valid if it's set.
So if it's truthy and email includes a @ symbol, let's say
I'm checking if the email includes a @ symbol,
which to me tells me that it's valid.
So if we have email,
if this is not undefined or anything like this,
and it includes a @ symbol, I am happy.
Of course a user could then still send something like just
hi@unknown.com, which might not be
a valid, existing email address.
Bu this is something we can't check here.
We would have to send a test email to that address
to do that.
But at least we ensure that some value was provided
and that it looks like a email address.
Then I also want to check if the password is set and
password.trim.length is greater than five characters.
The trim method when called on a string, which password is,
will remove any excess white space at the beginning
and the end of the string.
And then length is a property we can call on any array
and string to get the number of characters
in the case of a string.
And then I want to ensure that the password is
at least six characters long.
So I'm looking for a length greater than five
or alternatively greater or equal than six.
With that, I checked the two main credentials for validity.
I also want to ensure the name street,
postal and city are valid.
So therefore next,
I'll use the and operator to add another condition to this
overall Boolean, which I'm deriving here,
where I check that name is truthy and name.trim is not
equal to an empty string, which means that is set.
Now, if I temporarily reformat this,
this is already getting really long.
And for example,
I'm going to repeat this logic for the name,
for the street, postal and city fields.
Therefore I'll add a utility function in here,
which I'll name is Empty, where I get any value,
no matter if it's a name or a street
and I've returned true here, if not value.
So if it's undefined
or if value.trim equals an empty string.
So the opposite logic of what I have down there.
And with that is empty function.
Instead of checking my name like this,
I can check if not is empty for name.
The exclamation mark is important because I want to have a
name that's not fulfilling these conditions.
And now we can quickly do the same with is empty street
and so on.
And therefore, we save a lot of time here
because now we can just repeat
this utility function and execute this utility function
instead of writing the entire logic over and over again.
And we can also take this logic
and add another utility function,
which will name userCredentialsAreValid.
And here I return what I just cut and I get my email
and password here.
And then here and user details are valid.
I will first check if user credentials are valid by calling
this newly edit function and passing email and password
to it. But now we have less code in here.
And instead we distributed it
across multiple other utility functions.
And therefore here,
we have quite readable code, I would say.
Now it's this user details are valid function,
which I want to expose outside of this file.
And actually here there for all export this here,
this function. User details are valid.
And in the auth controller,
we can get our user credentials are valid constant here
by requiring going up one level util validation.
And this is now a function which we can execute here
to check the entered credentials.
So here in the signup function,
I will now check if user credentials are valid
and I want to forward all the data I'm getting here.
And if that's not the case, hence the exclamation mark.
Then I know that we got incorrect input
and then I want to return.
So that no other code executes.
And I want to redirect back to the signup page
so that the user is able to enter correct data.
Again, all the entered data will be lost with that,
but we'll work on that in a second.
For the moment, let's make sure we pass all the data
that is expected by user credentials are valid
to that function and therefore here,
I now pass rec body email as a first value,
then rec body password as a second value,
rec body full name as a third value.
And so on for all the values I'm getting here,
postal and rec body city.
Lets reformat this.
And that's now how I called this utility function
to validate whether we got correct credentials.
And if we don't, I redirect.
And actually user details are valid,
is the more fitting name here
because I'm not just verifying
the credentials, but all the user data.
So let's all the rename it here.
Of course we could've kept the old name,
but you want to use names that are as clear as possible.
Now with that, we're almost there,
but one important check is missing.
The email address entered here in the first field has to
match the confirm email address.
And we're not checking for this right now.
To check for this invalidation JS. I'll add a new function.
Email is confirmed we could say,
and here we get the email and the confirm email
as parameter values and there returned true,
if email is equal to confirm email, just like that.
Now I also want to use this function outside of this file.
And therefore instead of
just exporting user details are valid.
I'll export an object,
which has a user details are valid key,
which points at the user details are valid function.
But which now alls in addition gets
an email is confirmed key,
which points that the email is confirmed function.
Like this.
And now back in the auth controller,
we are actually importing the validation object
with various validation functions that are part of it.
And hence here I now call validation.UserDetailsAreValid,
but I want to combine this check with a number check.
If not user details are valid, we make it in here,
but I also want to make it in there as an alternative
and hence combined with the or operator
if validation, email is confirmed fails.
So if not validation, email is confirmed
and here the exclamation mark is always important.
And here I then pass in a rec.body.email and direct.body.
And then with square brackets, confirm email.
Why square brackets?
Because in the signup EJS file in that form,
this confirm email field has a name of confirmed dash email.
So that's the key which we can use to get access
to the entered data, to the entered value.
The problem with that is that dashes are not allowed
in JavaScript property names. Or they are allowed,
but not when extracting them with the dot notation.
Hence we can't use .confirm-email.
This would not be allowed,
but as an alternative to the dot notation,
you can also use square brackets.
And then the property name, which you want to access.
So this is totally fine.
And this will give us access
to the confirm email that was entered.
So with that,
we added some validation to this sign up action.
It's not all though.
Even if the enter data is correct,
we want to ensure that the user did not try to sign up
with an email address that's already stored in the database.
To ensure this,
we can go to our user model,
and there already have the get user with same email method.
This returns us any user that is identified that has
the same email address we can build up on this method
with another method.
For example, named exists already, which returns true,
if the user we're trying to create exists already
in the database.
For this in here with the, this keyword,
we can call get user with same email.
You can use the, this keyword,
not just to access properties,
but also to access and call methods
that exist on an object.
Here I'm calling this method
and this year we'll look for a user
with that email address.
Now it will return a promise and I'm interested
in the result of that promise.
So we can use async here and then a weight,
the result of this, and we get our existing user here then.
Now if we do find an existing user,
we want to return true here because then a user
with that email exists already.
If we don't find an existing user, we want to return false.
So here I will check if existing user, if this is truthy,
if we have a user, then I'll return true.
Else if we don't make it into this,
if check here all returned false.
So then we don't have a user.
Now back in the off controller,
after verifying the general input, before we call, sign up,
I want to use my user object,
which was already created here.
And actually we might want to cut it and only created after
we validated all the input.
So we created here now after the input validation,
and then on this user, before we sign up,
I want to call exists already.
Now this yields a promise.
So I want to await it and store the result in a constant
that can be named exists already.
Like this.
And if exists already as true,
then we know that we don't want to continue with signup
because we already have a user with that email
in the database.
So then I want to return so that no other code executes
and just as before we want to redirect back to /sign up.
So that the user has to enter a new data there.
Now in exists already,
we under the hood reach out to the database
and that could fail so we'll actually grab all that code
and move it into this try catch block here.
So that'd be handle any errors that might occur
with that existing try-catch block.
We could have also added a new block,
but since we have that block anyways, we can just reuse it.
So now with that, we're checking for user existence
and that's all good and nice, but at the moment,
we're not providing any feedback on our forms here.
If validation fails outside of the front end validation,
if I try to log in, for example,
with the incorrect password,
then this page is just reload it, but I get no feedback.
And my input data is lost and that's of course not good.
So in the next lecture,
we'll make sure that we show such a error message here
and that we keep the user input.
As always, and as before,
and in the future of this section,
definitely try this on your own first,
before we implement it together.