Hey guys, we finally got into the point where we can actually finish off all of the features for our 1
secrets application. 2
We've done a lot in terms of building up the authentication levels, making sure that it's secure, 3
giving users lots of different ways of signing in, and discovering a secret. 4
Now, this secret at the moment lives in the secrets.ejs file, which is just a piece of text at 5
the moment, and you can see it if you go into the Views, secrets.ejs. 6
It's just a paragraph element. 7
Now we're going to change all of that. 8
We're going to use EJS to insert a user's secret, and the user should be able to submit their own secrets. 9
There is a page called submit.ejs, where we can allow users to make a POST request to a route in 10
our server which is at "/submit" in order to submit some text that corresponds to their secret, 11
and that secret then will get displayed here, and we'll keep it in our database in the same user's 12
table. 13
Just to keep things simple. 14
So your job is to complete this as a challenge by yourself. 15
The first thing that you're going to need to do is to add a new column to the users table, which has 16
a name of secret, and it's going to hold data of type text. 17
And once you're done, the user should be able to log in to the website and click to submit a secret. 18
This brings up the submit.ejs page, and the user can type a secret, 19
for example, 20
"What are some of my secrets?" 21
I'm scared of clowns, which is a weird one. 22
But also, despite learning surfing for so many years, I'm still kind of bad at it, 23
which is a secret. 24
Please don't tell anyone. 25
And once I hit Submit, I'm going to save that secret into the database under that user in the same 26
row as that user. 27
And then when secrets gets rerendered, that secret gets displayed here instead of the default message. 28
So that is essentially the functionality that we want. 29
So you could keep something secret from other people, and you would be able to authenticate yourself 30
as a user to be able to add it 31
and then you need to be authenticated in order to view that secret. 32
There are a number of things that you need to do to achieve this. 33
The first to do is of course adding in that column. 34
And if I update this user's table, refresh it, 35
you'll see that brand new secret that I added just now going in right there. 36
And if you go ahead and open up the extracted 9.6 Secrets Project, and you take a look through the 37
index.ejs, you'll see that I've put in some TODO's for you. 38
There's three TODO's here. 39
You need to update the GET route for secrets in order to pull in the secret that belongs to the user 40
if they have one. 41
And then you need to think about how to create a GET route so that we can show people the submit.ejs 42
page and think about how we should only allow authenticated users to view that, Submit a Secret page, 43
and if they're not authenticated, they should be asked to log in. 44
And then finally, we need to create the POST route for submit so that when a user does submit their 45
secret from here, that secret gets saved in the database and replaces anything that exists there before, 46
and finally makes sure that all of that process went through smoothly. 47
Now, a couple of things to note. 48
If you get confused, the SQL command that's required to update the column is in here. 49
But of course, given that you've already done the database module, you should already know how to 50
do that. 51
And this is a good point to test your knowledge, 52
and even if you don't remember, I recommend googling before looking at the solution. 53
See if you can figure it out first. 54
And the solution code, which we'll run through together, includes all of the TODOs that needs to 55
happen before this code is going to work. 56
Final reminder in the .env file, you need to replace "YOUR CLIENT SECRET" and "YOUR CLIENT ID" with 57
your own "GOOGLE_CLIENT_ID" and "SECRET". 58
That way the Google login part will actually work. 59
So you should have this from the previous lesson and you can simply go and paste it in. 60
So now I'm going to leave you to it in your own capable hands, to struggle and to figure things out 61
and see if you can get this to work. 62
And finally, complete the Secrets Project. 63
I'll wait here, and once you come back, we'll talk through the solution together. 64
All right. 65
So the first thing I'm going to do is to put in my own values for the "GOOGLE_CLIENT_ID" and 66
"GOOCLE CLIENT SECRET". 67
Next I'm going to go into the secrets.ejs page 68
and I'm going to update it so that instead of having that plain text, I'm replacing it with an EJS tag. 69
So this is the angle bracket percentage equal (<%=), 70
and this is going to be sent in here programmatically. 71
If you don't know what I'm talking about in terms of EJS in terms of partials, then be sure that you 72
haven't skipped a module on that in the course. 73
So now that I've done that, I can close that file down and I can focus on the TODO's here. 74
The first thing I'm going to work on is creating a GET route so that we can actually display the submit 75
page. 76
And this is going to be triggered when the user is on the secrets page and they click on this button, 77
Submit a Secret, that's going to hit up the submit route. 78
And this is what it looks like in the browser. 79
So this is the button we're going to hook up to our server. 80
So we've got our app.get("/submit"). 81
And then we're going to add our callback req, res. 82
And then inside here we're going to think about how we're going to prevent an unauthorized user from 83
seeing the submit page. 84
So we know that the submit page is under submit.ejs, 85
but we should only render this if they are already logged in. 86
But thankfully, we know from our secrets route that we can simply use the request object to check to 87
see if the user is authenticated 88
because we're using Passport, and because we're using sessions and the user detail is saved in those 89
requests, that gets passed around. 90
So we can do the same thing and say if (req.isAuthenticated), 91
well, in that case we're going to res.render(submit.ejs), 92
but otherwise, we're going to res.redirect and take them back over to the "/login" page. Like so. That 93
is that TODO done. 94
So I'm going to check that off. 95
Next I'm going to set up the POST route for submit. 96
Once the user is on this submit page and they type a secret when they hit that Submit button, it's 97
going to hit up our POST route in our server because the form action goes to "/submit", making 98
the request POST. 99
So we have to write this right here. 100
And I'm going to write app.post. 101
And the route is ("/submit"). 102
And then we add our req, res et cetera. 103
And now inside this route we need to handle the submitted data and add it to the database. 104
We've already got body-parser enabled in this, so we can simply set the secret to a const as the 105
req.body. 106
And if we check here for that input, what is the name of that input? 107
Well, it's just called secret. 108
So request.body.secret is going to equal whatever the user types in here. 109
And then we're going to submit that into our database. 110
Now how do we know under which user to submit this secret to in the database. 111
How do we know that it's this user that's logged in, 112
and we need to put the secret under their record? 113
Well, remember what I said previously about using Passport? 114
One of the great benefits is we can get access to the user through req.user. 115
And this is because when we do our login local strategy or when we do our Google login strategy, in 116
both cases, we return the user and all of their data in the callback, which gets serialized, and 117
then deserialized so that we can access them right here under req.user. 118
So if you want, you can console.log() and see the result of that. 119
Now I know that I can simply access the req.user.email and query it in my database. 120
So I'm going to do a try catch. 121
And I'm going to use my await and then db.query(). 122
And the query that I'm going to use is "UPDATE users". 123
So update the table called users and "SET" the field 124
that's called "secret" to equal $1. 125
And I need to make sure that I'm only setting this for one user. 126
And that's where their email is equal to the second input $2. 127
So now let's put in $1, $2. $1 is going to be equal to the secret, 128
and $2 is going to be the request.user.email. 129
Now because this is asynchronous. 130
Let's go ahead and change this to async 131
so that that works. 132
After all of that's done we're waiting for this to finish, 133
hence the await. 134
And after that then we go ahead and do res.redirect and take the user to see their secret. 135
So we're going to redirect them to the secret route which is of course the GET route, which means they 136
get to view the secrets .ejs, which we have one more TODO to pull up their secret from the database. 137
So we've saved all of this and we have caught our error. 138
And I'm just going to, for simplicity sake, console.log() that error as my error handling for now. 139
So I'm done with the second TODO 140
and I'm going to replace my TODO with a comment for you so you know how to find it. 141
And the last TODO here is to change the app.get() route for secrets, so that we actually pull in the 142
user's secret, so that we can render it in the secret.ejs. 143
Remember, we already changed our secrets.ejs, so that it now uses an EJS tag to receive under 144
secret. 145
We have to get hold of that by passing it in, in the same sentence as we do our res.render(), our 146
res.render() happens and then we get to add some things to pass over. 147
In our case it's called secret, 148
and what is the secret that we're going to pass? 149
Well, we're going to have to get hold of that from our database. 150
Again, 151
we're going to do a try catch. 152
And what we're going to try to do is to create a const called result. 153
We're going to do await. 154
And then we do db.query(). 155
And the query that we're going to make is "SELECT" the column called "secret FROM" the table called "users". 156
And then the condition is "WHERE email = $1". 157
And the email is again going to come from our Passport authentication req.user.email. 158
And it's really neat being able to access the user's details at any point because of this whole Passport 159
session thing that we've already set up. 160
So that's pretty neat. 161
And because we're using await, let's go ahead and change this to async as well 162
and make sure that req.user.email is in an array. 163
I think I missed that out just now, so make sure you check yours. 164
So once we get the result, we're going to console.log() the result just so that you can see it, 165
but I know that it should contain a secret for the user that I just logged in. 166
I'm going to go ahead and continue to fetch that secret out of the result. 167
So it's going to be result.rows[0] at the row zero, 168
and then it's under the column called secret. 169
So this should allow me to access the secret. 170
If the secret exists we're going to go ahead and do what we plan to do, which is to res.render that secret 171
and pass it over like so. 172
But what if it's a user who doesn't have a secret yet? 173
They just joined the website, 174
they don't have one. 175
Well, in this case we're going to res.render() secrets.ejs. 176
And we can put in the default which is "Jack Bauer is my hero." 177
Alternatively you can just have a placeholder. 178
You should submit a secret. 179
It can be anything that you want. 180
And finally, I'm going to catch the error here with just a consolelog(). 181
And that should complete this to do. 182
Let me put a marker here. 183
And now let's go ahead and try it out. 184
So I'm going to log in as my user. 185
And you can see that the secret that I submitted previously still shows right here. 186
I'm going to click on Submit a Secret and let's try a new one. 187
Click Submit and goes to Test. 188
Let's try logging out and logging in again. 189
And you can see it's still persisted because it's pulling it in from our database. 190
So I hope you had fun building this application and in the process, learning all about authentication. 191
I've kept this project as simple as possible so that we can focus on the important things, which is 192
already complicated enough. 193
But this is a good time to try practicing what you've learned by applying these authentication steps 194
and knowledge to a previous project of your own. 195
So have a think about what you might want to do. 196
Brainstorm some projects and if you build anything cool, 197
as always, post in the Q&A, 198
I would love to hear about it.