title
Node.js App From Scratch | Express, MongoDB & Google OAuth

description
This is a full application build of the StoryBooks app which uses Node.js, Express, MongoDB, Passport with a Google OAuth strategy and more. Full Code: https://github.com/bradtraversy/storybooks 💖 Become a Patron: Show support & get perks! http://www.patreon.com/traversymedia Website & Udemy Course Links: https://www.traversymedia.com Follow Traversy Media: https://www.twitter.com/traversymedia https://www.instagram.com/traversymedia https://www.facebook.com/traversymedia TimeStamps: Intro - 00:00 Database Setup - 3:41 Install Dependencies - 6:10 Initial Express Setup - 10:26 Connect Database - 14:00 Morgan Logger - 17:27 Template Engine & Layouts - 18:22 Index Routes & Views - 21:44 Materialize & Font Awesome - 25:54 Set Static Folder - 26:55 Login Layout - 29:13 Login Page Template - 31:55 Start Google Login - 33:57 Passport Intro - 36:46 Passport Config & Sessions - 39:00 User Model - 42:49 Passport Google Strategy - 45:41 Auth Routes - 49:50 Save Google Profile Data - 55:06 Logout - 59:54 Navigation - 1:01:11 Auth Middleware - 1:03:22 Store Sessions In Database - 1:08:36 Story Model - 1:12:27 Dashboard Stories - 1:14:44 Add Story - 1:21:57 Format Date Handlebar Helper - 1:33:35 Public Stories - 1:36:40 Truncate & StripTags Helpers - 1:44:10 Edit Icon Helper - 1:47:04 Edit Story - 1:54:21 Method Override For PUT Requests - 2:02:30 Method Override For DELETE Requests - 2:10:56 Single Story Page - 2:18:46 User Stories - 2:24:36

detail
{'title': 'Node.js App From Scratch | Express, MongoDB & Google OAuth', 'heatmap': [{'end': 451.899, 'start': 352.911, 'weight': 0.808}, {'end': 625.568, 'start': 534.045, 'weight': 0.723}, {'end': 896.652, 'start': 802.314, 'weight': 0.921}, {'end': 1078.932, 'start': 979.187, 'weight': 0.85}, {'end': 1613.745, 'start': 1426.74, 'weight': 0.946}, {'end': 1885.83, 'start': 1781.481, 'weight': 0.778}, {'end': 2147.692, 'start': 1959.455, 'weight': 0.792}, {'end': 3310.531, 'start': 3212.119, 'weight': 0.729}, {'end': 3841.353, 'start': 3747.677, 'weight': 0.701}, {'end': 4296.693, 'start': 4189.915, 'weight': 0.838}], 'summary': 'Tutorial covers building a crud application with google oauth using passport, sessions, and cookies, storing data in mongodb, utilizing handlebars as the template engine, and demonstrating various functionalities over a two and a half hour long video. it also includes setting up mongodb atlas, initializing a node.js server, connecting to mongodb, implementing google oauth for authentication, integrating google authentication in a node.js application, creating protected routes, dashboard functionality, formatting dates and story display, and updating web application functionalities.', 'chapters': [{'end': 221.192, 'segs': [{'end': 100.794, 'src': 'embed', 'start': 66.473, 'weight': 2, 'content': [{'end': 71.036, 'text': 'This is from that, although I did completely redo it and update it.', 'start': 66.473, 'duration': 4.563}, {'end': 76.079, 'text': "So basically we can this is the landing page and we can't do anything without logging in.", 'start': 71.716, 'duration': 4.363}, {'end': 81.668, 'text': 'You know, slash stories or anything.', 'start': 78.181, 'duration': 3.487}, {'end': 83.211, 'text': "It's just going to bounce me back here.", 'start': 81.748, 'duration': 1.463}, {'end': 84.213, 'text': 'So I need to log in.', 'start': 83.271, 'duration': 0.942}, {'end': 87.319, 'text': 'And if you have multiple Google accounts, you can choose one.', 'start': 84.233, 'duration': 3.086}, {'end': 89.483, 'text': "I'm going to choose my wife's dummy account here.", 'start': 87.359, 'duration': 2.124}, {'end': 100.794, 'text': "So, once we log in, it takes us to the dashboard and basically it'll save your Google data in the database, just like your name and your image,", 'start': 90.791, 'duration': 10.003}], 'summary': 'After updating the landing page, logging in allows access to the dashboard and saves google data in the database.', 'duration': 34.321, 'max_score': 66.473, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY66473.jpg'}, {'end': 143.313, 'src': 'embed', 'start': 114.258, 'weight': 0, 'content': [{'end': 117.899, 'text': "If you don't want others to see it on the public page you can set it to private.", 'start': 114.258, 'duration': 3.641}, {'end': 126.551, 'text': "I'll just say this is my story and save and also we're using a WYSIWYG editor here.", 'start': 118.789, 'duration': 7.762}, {'end': 129.952, 'text': 'This is a CK editor so we can save that.', 'start': 126.591, 'duration': 3.361}, {'end': 131.413, 'text': 'You can see that shows up here.', 'start': 129.991, 'duration': 1.422}, {'end': 134.413, 'text': 'And if I go to public stories.', 'start': 132.333, 'duration': 2.08}, {'end': 138.409, 'text': 'You can see that it shows right here.', 'start': 136.647, 'duration': 1.762}, {'end': 143.313, 'text': "Now, whichever stories are mine, you can see actually three out of the four of the account that I'm logged in with.", 'start': 138.429, 'duration': 4.884}], 'summary': 'Using the ck editor, 3 out of 4 stories appear on the public page.', 'duration': 29.055, 'max_score': 114.258, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY114258.jpg'}, {'end': 206.201, 'src': 'embed', 'start': 179.159, 'weight': 1, 'content': [{'end': 186.966, 'text': "there's not a ton of functionality, but there's actually quite a bit that goes into this in terms of, you know, authentication and stuff like that,", 'start': 179.159, 'duration': 7.807}, {'end': 191.83, 'text': 'protecting routes and creating all the story routes and stuff like that.', 'start': 186.966, 'duration': 4.864}, {'end': 192.691, 'text': 'We can log out.', 'start': 191.89, 'duration': 0.801}, {'end': 195.052, 'text': "And I mean, that's pretty much it.", 'start': 193.591, 'duration': 1.461}, {'end': 197.674, 'text': "So it'll take, you know, the video.", 'start': 195.172, 'duration': 2.502}, {'end': 200.296, 'text': 'The recording was about two and a half hours long.', 'start': 197.894, 'duration': 2.402}, {'end': 200.817, 'text': 'I do.', 'start': 200.436, 'duration': 0.381}, {'end': 206.201, 'text': 'I will warn you, I start to get tired at the end because I did this all straight through.', 'start': 201.057, 'duration': 5.144}], 'summary': 'The functionality is limited, but the process involves authentication, route protection, logout, and the tutorial is about two and a half hours long.', 'duration': 27.042, 'max_score': 179.159, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY179159.jpg'}], 'start': 7.264, 'title': 'Building storybooks app with google oauth', 'summary': 'Covers building a crud application with google oauth using passport, sessions, and cookies, storing data in mongodb, utilizing handlebars as the template engine, and demonstrating various functionalities, spanning over a two and a half hour long video tutorial.', 'chapters': [{'end': 221.192, 'start': 7.264, 'title': 'Building storybooks app with google oauth', 'summary': 'Covers building a crud application with google oauth using passport, sessions, and cookies, storing data in mongodb, utilizing handlebars as the template engine, and demonstrating various functionalities, spanning over a two and a half hour long video tutorial.', 'duration': 213.928, 'highlights': ['The application build spans a two and a half hour long video tutorial, covering a CRUD application with Google OAuth using Passport, sessions, and cookies, and storing data in MongoDB. The video tutorial is approximately two and a half hours long, encompassing the development of a CRUD application with Google OAuth using Passport, sessions, cookies, and MongoDB for data storage.', 'Utilization of handlebars as the template engine is showcased, with a focus on server-side development and functionality demonstrations. The tutorial emphasizes the use of handlebars as the template engine, highlighting server-side development and demonstrating various functionalities.', 'The application includes functionalities such as user authentication, protecting routes, creating story routes, and utilizing a WYSIWYG editor for creating and editing stories. The application encompasses user authentication, route protection, story route creation, and the use of a WYSIWYG editor for creating and editing stories.']}], 'duration': 213.928, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY7264.jpg', 'highlights': ['The application build spans a two and a half hour long video tutorial, covering a CRUD application with Google OAuth using Passport, sessions, and cookies, and storing data in MongoDB.', 'The application includes functionalities such as user authentication, protecting routes, creating story routes, and utilizing a WYSIWYG editor for creating and editing stories.', 'Utilization of handlebars as the template engine is showcased, with a focus on server-side development and functionality demonstrations.']}, {'end': 943.355, 'segs': [{'end': 262.302, 'src': 'embed', 'start': 221.912, 'weight': 2, 'content': [{'end': 229.716, 'text': "okay. so we're going to get started on our storybooks application and i think the first thing that i want to do is just set up our database and get that out of the way.", 'start': 221.912, 'duration': 7.804}, {'end': 236.8, 'text': "so we're using mongodb, which is a no sql database, and you can certainly download it and install it on your local machine if you want.", 'start': 229.716, 'duration': 7.084}, {'end': 241.663, 'text': "however, i'm going to be using mongodb atlas, which is a cloud version of the database.", 'start': 236.8, 'duration': 4.863}, {'end': 243.884, 'text': "so the data isn't actually stored on our machine.", 'start': 241.663, 'duration': 2.221}, {'end': 247.626, 'text': "it's stored on in atlas on a cloud server.", 'start': 243.884, 'duration': 3.742}, {'end': 250.268, 'text': 'So you want to go to MongoDB.com.', 'start': 248.246, 'duration': 2.022}, {'end': 252.651, 'text': "if you don't have an account, you can just click on.", 'start': 250.268, 'duration': 2.383}, {'end': 257.555, 'text': 'try free sign up, do all that stuff, register your email and then go ahead and sign in.', 'start': 252.651, 'duration': 4.904}, {'end': 262.302, 'text': "So I'm just going to sign into one of my kind of dummy accounts.", 'start': 258.117, 'duration': 4.185}], 'summary': 'Setting up storybooks application with mongodb atlas for cloud storage.', 'duration': 40.39, 'max_score': 221.912, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY221912.jpg'}, {'end': 451.899, 'src': 'heatmap', 'start': 352.911, 'weight': 0.808, 'content': [{'end': 360.177, 'text': "If we go back and we click connect and you click connect to your application, you'll get this connection string,", 'start': 352.911, 'duration': 7.266}, {'end': 364.66, 'text': "which is what we're going to use later on, when we're ready to connect our application.", 'start': 360.177, 'duration': 4.483}, {'end': 369.064, 'text': "So right now I'm just going to leave this tab open and we're going to jump into VS code.", 'start': 364.74, 'duration': 4.324}, {'end': 375.714, 'text': "Now, from here, what I'm going to do first, of course, is npm init, which will generate a package.json file.", 'start': 369.611, 'duration': 6.103}, {'end': 378.076, 'text': 'Of course, you need Node.js installed.', 'start': 376.315, 'duration': 1.761}, {'end': 382.178, 'text': "If you don't have it, just go to nodejs.org and download and install it.", 'start': 378.556, 'duration': 3.622}, {'end': 389.042, 'text': 'So description will say app to create public and private stories.', 'start': 382.538, 'duration': 6.504}, {'end': 393.189, 'text': "And the entry point I'm going to make app.js.", 'start': 390.666, 'duration': 2.523}, {'end': 401.437, 'text': "Usually how I do it is if I'm if I'm building like, you know, an app with a front end using reactive view or something, I'll call this server.js.", 'start': 393.629, 'duration': 7.808}, {'end': 407.783, 'text': "But if it's a complete back end server side rendered application, I'll use app.js.", 'start': 401.877, 'duration': 5.906}, {'end': 408.924, 'text': "It's just preference.", 'start': 408.043, 'duration': 0.881}, {'end': 411.126, 'text': "So it's the author.", 'start': 409.925, 'duration': 1.201}, {'end': 413.008, 'text': "You can put your own name here if you'd like.", 'start': 411.166, 'duration': 1.842}, {'end': 415.17, 'text': 'And then MIT for the license.', 'start': 413.188, 'duration': 1.982}, {'end': 423.339, 'text': "OK so we are a package that Jason now there's quite a few dependencies that we're going to be using quite a few packages.", 'start': 416.294, 'duration': 7.045}, {'end': 430.103, 'text': "So I figure we can just install them now and that'll give you a good idea of what we'll be doing what we'll be working with.", 'start': 423.999, 'duration': 6.104}, {'end': 432.205, 'text': "So let's install our dependencies.", 'start': 430.584, 'duration': 1.621}, {'end': 437.709, 'text': 'So first thing we want, of course, is express, which is our web framework to create routes and stuff like that.', 'start': 432.805, 'duration': 4.904}, {'end': 443.253, 'text': 'We also need Mongoose to work with our database, create models and so on.', 'start': 438.169, 'duration': 5.084}, {'end': 451.899, 'text': "We're going to use something called Connect Mongo, which is going to allow us to store our sessions in our database so that when we reset the server,", 'start': 443.273, 'duration': 8.626}], 'summary': 'Setting up application dependencies with npm init and installing express, mongoose, and connect mongo for database and routing.', 'duration': 98.988, 'max_score': 352.911, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY352911.jpg'}, {'end': 486.148, 'src': 'embed', 'start': 460.202, 'weight': 5, 'content': [{'end': 466.105, 'text': "We want express dash handlebars, which is what we're using as a template engine.", 'start': 460.202, 'duration': 5.903}, {'end': 470.466, 'text': 'If you want to use Pug or EJS or something like that, you can.', 'start': 466.285, 'duration': 4.181}, {'end': 476.048, 'text': 'or even if you wanted to just output Jason and use reactor view or something, you can do that as well.', 'start': 470.466, 'duration': 5.582}, {'end': 477.749, 'text': "But we're going with handlebars for this.", 'start': 476.088, 'duration': 1.661}, {'end': 481.966, 'text': "Let's see, we want .env for our config.", 'start': 478.824, 'duration': 3.142}, {'end': 486.148, 'text': 'So d.env, so we can put our environment variables in there.', 'start': 482.426, 'duration': 3.722}], 'summary': 'Using express dash handlebars as a template engine and .env for environment variables.', 'duration': 25.946, 'max_score': 460.202, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY460202.jpg'}, {'end': 625.568, 'src': 'heatmap', 'start': 511.107, 'weight': 0, 'content': [{'end': 513.729, 'text': "We're going to use passport for authentication.", 'start': 511.107, 'duration': 2.622}, {'end': 526.639, 'text': "And since we're using Google for our login, we need the passport dash, Google dash off to zero package, because we're using a lot of 2.0,", 'start': 513.828, 'duration': 12.811}, {'end': 527.7, 'text': "and I think that's it.", 'start': 526.639, 'duration': 1.061}, {'end': 531.763, 'text': 'So go ahead and run this and all those should get installed.', 'start': 528.881, 'duration': 2.882}, {'end': 540.206, 'text': "Now, I do have just a couple of dev dependencies, so we're going to NPM install dash uppercase D node mon.", 'start': 534.045, 'duration': 6.161}, {'end': 548.368, 'text': "So node model just continuously watch our server so we don't have to restart it every time we make a change and then cross ENV.", 'start': 540.727, 'duration': 7.641}, {'end': 553.63, 'text': "I'm going to use this because I want to put inside our scripts, our start script and dev script.", 'start': 548.849, 'duration': 4.781}, {'end': 559.051, 'text': 'I want to have a global and a global variable or an environment variable for our server.', 'start': 553.67, 'duration': 5.381}, {'end': 560.472, 'text': 'node environment.', 'start': 559.591, 'duration': 0.881}, {'end': 564.534, 'text': "And it's different depending on if you're on Windows or Mac or Linux or whatever.", 'start': 561.092, 'duration': 3.442}, {'end': 565.914, 'text': "So we're going to just use that.", 'start': 564.654, 'duration': 1.26}, {'end': 571.237, 'text': "So there's no, you know, confusion now.", 'start': 567.495, 'duration': 3.742}, {'end': 573.058, 'text': 'Yeah, everything is installed.', 'start': 571.858, 'duration': 1.2}, {'end': 575.9, 'text': "So for scripts, let's create our start script.", 'start': 573.138, 'duration': 2.762}, {'end': 578.721, 'text': "So this is basically what we what we'll be using in production.", 'start': 575.94, 'duration': 2.781}, {'end': 580.582, 'text': 'I may deploy this.', 'start': 578.741, 'duration': 1.841}, {'end': 582.523, 'text': 'I may deploy it to something like Heroku.', 'start': 580.602, 'duration': 1.921}, {'end': 583.404, 'text': "I'm not sure yet.", 'start': 582.583, 'duration': 0.821}, {'end': 587.646, 'text': 'But here we want to run, first of all, crossing and V.', 'start': 584.524, 'duration': 3.122}, {'end': 596.133, 'text': 'so that we can set an environment variable here because I want to explicitly set the node environment here to production.', 'start': 588.689, 'duration': 7.444}, {'end': 603.017, 'text': "You want to set that to production and then we'll just run node and then the file which is going to be called app JS.", 'start': 596.153, 'duration': 6.864}, {'end': 607.62, 'text': "And then what we'll do here is this will be the dev.", 'start': 603.677, 'duration': 3.943}, {'end': 609.841, 'text': "So this is what we'll be running most the time.", 'start': 607.96, 'duration': 1.881}, {'end': 616.605, 'text': 'And we want this to be the development environment and we want to run node mon instead of just node.', 'start': 610.221, 'duration': 6.384}, {'end': 617.683, 'text': 'All right.', 'start': 617.363, 'duration': 0.32}, {'end': 618.584, 'text': "So we'll save that.", 'start': 617.703, 'duration': 0.881}, {'end': 625.568, 'text': 'We can close this file up and we can create our app J.S., which is basically our entry point.', 'start': 619.264, 'duration': 6.304}], 'summary': 'Using passport for authentication, setting up dev dependencies, and creating start and dev scripts for production and development environments.', 'duration': 29.099, 'max_score': 511.107, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY511107.jpg'}, {'end': 616.605, 'src': 'embed', 'start': 584.524, 'weight': 1, 'content': [{'end': 587.646, 'text': 'But here we want to run, first of all, crossing and V.', 'start': 584.524, 'duration': 3.122}, {'end': 596.133, 'text': 'so that we can set an environment variable here because I want to explicitly set the node environment here to production.', 'start': 588.689, 'duration': 7.444}, {'end': 603.017, 'text': "You want to set that to production and then we'll just run node and then the file which is going to be called app JS.", 'start': 596.153, 'duration': 6.864}, {'end': 607.62, 'text': "And then what we'll do here is this will be the dev.", 'start': 603.677, 'duration': 3.943}, {'end': 609.841, 'text': "So this is what we'll be running most the time.", 'start': 607.96, 'duration': 1.881}, {'end': 616.605, 'text': 'And we want this to be the development environment and we want to run node mon instead of just node.', 'start': 610.221, 'duration': 6.384}], 'summary': 'Setting node environment to production, running app.js using node, and using nodemon for development.', 'duration': 32.081, 'max_score': 584.524, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY584524.jpg'}, {'end': 896.652, 'src': 'heatmap', 'start': 802.314, 'weight': 0.921, 'content': [{'end': 804.735, 'text': "So let's save that and we should be able to run this.", 'start': 802.314, 'duration': 2.421}, {'end': 812.337, 'text': "So let's say NPM run dev and we get server running in development mode on port 3000.", 'start': 804.775, 'duration': 7.562}, {'end': 813.837, 'text': "So we know it's coming from here.", 'start': 812.337, 'duration': 1.5}, {'end': 817.475, 'text': "I'm just going to change this to 3000.", 'start': 813.857, 'duration': 3.618}, {'end': 822.879, 'text': 'And then I want to stop it and run NPM start and make sure that it runs in production mode.', 'start': 817.475, 'duration': 5.404}, {'end': 827.763, 'text': "OK, so it's running production mode port 3000, but we want to run it in development mode.", 'start': 822.899, 'duration': 4.864}, {'end': 828.924, 'text': 'I just wanted to test that out.', 'start': 827.783, 'duration': 1.141}, {'end': 832.071, 'text': 'OK, so that takes care of that.', 'start': 830.41, 'duration': 1.661}, {'end': 840.315, 'text': 'I think the next thing that I would like to do is just connect to our database just to just to get that whole rigmarole over with.', 'start': 832.091, 'duration': 8.224}, {'end': 846.239, 'text': "So what I'm going to do is in config, let's create a file called DB.js.", 'start': 840.476, 'duration': 5.763}, {'end': 855.544, 'text': 'And if you took my Node.js API course on Udemy or a lot of my Node.js videos, I basically do this the same way all the time.', 'start': 846.839, 'duration': 8.705}, {'end': 857.325, 'text': "So we're going to bring in Mongoose.", 'start': 855.824, 'duration': 1.501}, {'end': 873.536, 'text': "Choir, Mongoose, and then I have a function here called Connect DB, and we're going to call this async, because when you work with,", 'start': 859.704, 'duration': 13.832}, {'end': 878.9, 'text': "when you work with MongoDB sorry, Mongoose, you're working with promises.", 'start': 873.536, 'duration': 5.364}, {'end': 884.963, 'text': "OK so like Mongoose dot connect returns a promise and I don't want to use dot then I don't like that syntax.", 'start': 878.92, 'duration': 6.043}, {'end': 890.347, 'text': "I want to use a single way if you want to use dot then that's fine but I prefer a single way.", 'start': 885.083, 'duration': 5.264}, {'end': 896.652, 'text': "So here I'm just going to put a try catch and we want to try to connect.", 'start': 891.127, 'duration': 5.525}], 'summary': 'Developing and testing server on port 3000, setting up database connection with mongoose in node.js', 'duration': 94.338, 'max_score': 802.314, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY802314.jpg'}], 'start': 221.912, 'title': 'Setting up mongodb atlas and node.js server', 'summary': 'Covers setting up mongodb atlas including creating a new cluster, adding a database user, and configuring network access, and initializing a node.js server, installing dependencies such as express, mongoose, connect mongo, and configuring scripts for production and development environments.', 'chapters': [{'end': 369.064, 'start': 221.912, 'title': 'Setting up mongodb atlas for storybooks app', 'summary': 'Covers setting up mongodb atlas for the storybooks application, including creating a new cluster, adding a database user, and configuring network access, enabling users to connect to the cloud database.', 'duration': 147.152, 'highlights': ['Creating a new cluster The process involves navigating to MongoDB.com, signing in, and creating a new cluster, which may take three to four minutes to set up.', 'Adding a database user Users are guided through the process of adding a new database user, including setting a username and password, and providing read permissions to any database.', "Configuring network access The tutorial explains the option to add an IP address for security or allow access from anywhere, providing flexibility based on the user's requirements."]}, {'end': 943.355, 'start': 369.611, 'title': 'Setting up node.js server with dependencies', 'summary': 'Covers the process of initializing a node.js server, installing dependencies such as express, mongoose, connect mongo, and configuring scripts for production and development environments, as well as connecting to a mongodb database.', 'duration': 573.744, 'highlights': ['Node.js server is initialized by generating a package.json file using npm init, and installing dependencies such as Express, Mongoose, Connect Mongo, and others. Node.js server initialization, dependency installation', 'Configuration of start and dev scripts for production and development environments respectively, along with the use of node mon to continuously watch the server. Script configuration for production and development, utilization of node mon', 'Connection to a MongoDB database is established using Mongoose, with the use of async function to handle promises and setting necessary options to avoid warnings. Establishing connection to MongoDB database, async function usage, setting options for Mongoose']}], 'duration': 721.443, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY221912.jpg', 'highlights': ['Creating a new cluster The process involves navigating to MongoDB.com, signing in, and creating a new cluster, which may take three to four minutes to set up.', 'Adding a database user Users are guided through the process of adding a new database user, including setting a username and password, and providing read permissions to any database.', "Configuring network access The tutorial explains the option to add an IP address for security or allow access from anywhere, providing flexibility based on the user's requirements.", 'Node.js server is initialized by generating a package.json file using npm init, and installing dependencies such as Express, Mongoose, Connect Mongo, and others. Node.js server initialization, dependency installation', 'Configuration of start and dev scripts for production and development environments respectively, along with the use of node mon to continuously watch the server. Script configuration for production and development, utilization of node mon', 'Connection to a MongoDB database is established using Mongoose, with the use of async function to handle promises and setting necessary options to avoid warnings. Establishing connection to MongoDB database, async function usage, setting options for Mongoose']}, {'end': 1997.483, 'segs': [{'end': 1078.932, 'src': 'heatmap', 'start': 979.187, 'weight': 0.85, 'content': [{'end': 984.413, 'text': 'And then finally, we just outside of here, we just module exports.', 'start': 979.187, 'duration': 5.226}, {'end': 989.509, 'text': 'connect DB so that we can use this, we can run this in the app JS file.', 'start': 985.407, 'duration': 4.102}, {'end': 992.711, 'text': 'OK, so pretty simple, simple connection.', 'start': 990.229, 'duration': 2.482}, {'end': 1000.415, 'text': "Let's go to app JS now and let's bring that connect DB function in.", 'start': 993.551, 'duration': 6.864}, {'end': 1012.701, 'text': "So we'll say const connect DB and we're going to take that from the config slash DB file.", 'start': 1000.555, 'duration': 12.146}, {'end': 1018.217, 'text': 'Right Config the DB.', 'start': 1015.376, 'duration': 2.841}, {'end': 1020.458, 'text': 'Yes So we need to call this.', 'start': 1018.777, 'duration': 1.681}, {'end': 1026.44, 'text': "I'm going to go right here and it's only a comment.", 'start': 1021.458, 'duration': 4.982}, {'end': 1028.16, 'text': "Actually, we'll just say connect DB.", 'start': 1026.579, 'duration': 1.581}, {'end': 1029.681, 'text': "It's pretty self-explanatory.", 'start': 1028.22, 'duration': 1.461}, {'end': 1031.801, 'text': "So now I'm going to run and save this.", 'start': 1030.3, 'duration': 1.501}, {'end': 1038.084, 'text': "And down here in the console, you'll see MongoDB connected and it shows my my host cluster and all that.", 'start': 1031.962, 'duration': 6.122}, {'end': 1041.444, 'text': 'OK, so now that we have that out of the way.', 'start': 1039.204, 'duration': 2.24}, {'end': 1043.981, 'text': "Let's see what we want to do next.", 'start': 1042.618, 'duration': 1.363}, {'end': 1047.244, 'text': "Let's set up Morgan for logging, which is pretty simple.", 'start': 1044.622, 'duration': 2.622}, {'end': 1050.209, 'text': "So we're just going to bring in Morgan.", 'start': 1047.945, 'duration': 2.264}, {'end': 1061.221, 'text': "I just want it so that when there's a request to a page or any kind of request at all, that it just shows down in the console.", 'start': 1053.436, 'duration': 7.785}, {'end': 1066.064, 'text': "So I'm going to go right under where we initialized our app.", 'start': 1061.761, 'duration': 4.303}, {'end': 1069.866, 'text': 'And I only want to run this in development mode.', 'start': 1066.924, 'duration': 2.942}, {'end': 1078.932, 'text': "So we'll just check process.env.nodeenv if that's equal to development.", 'start': 1069.906, 'duration': 9.026}], 'summary': 'Setting up mongodb connection and implementing logging using morgan in app js.', 'duration': 99.745, 'max_score': 979.187, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY979187.jpg'}, {'end': 1061.221, 'src': 'embed', 'start': 1030.3, 'weight': 2, 'content': [{'end': 1031.801, 'text': "So now I'm going to run and save this.", 'start': 1030.3, 'duration': 1.501}, {'end': 1038.084, 'text': "And down here in the console, you'll see MongoDB connected and it shows my my host cluster and all that.", 'start': 1031.962, 'duration': 6.122}, {'end': 1041.444, 'text': 'OK, so now that we have that out of the way.', 'start': 1039.204, 'duration': 2.24}, {'end': 1043.981, 'text': "Let's see what we want to do next.", 'start': 1042.618, 'duration': 1.363}, {'end': 1047.244, 'text': "Let's set up Morgan for logging, which is pretty simple.", 'start': 1044.622, 'duration': 2.622}, {'end': 1050.209, 'text': "So we're just going to bring in Morgan.", 'start': 1047.945, 'duration': 2.264}, {'end': 1061.221, 'text': "I just want it so that when there's a request to a page or any kind of request at all, that it just shows down in the console.", 'start': 1053.436, 'duration': 7.785}], 'summary': 'Configured mongodb connection and set up morgan for logging.', 'duration': 30.921, 'max_score': 1030.3, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1030300.jpg'}, {'end': 1204.817, 'src': 'embed', 'start': 1180.851, 'weight': 10, 'content': [{'end': 1188.673, 'text': "And then I think we have to put the default layout, because how this works if you've never dealt with a template engine?", 'start': 1180.851, 'duration': 7.822}, {'end': 1191.054, 'text': 'we have a layout that wraps around everything.', 'start': 1188.673, 'duration': 2.381}, {'end': 1196.875, 'text': "That layout has like the HTML head and body tags and stuff that you don't want to repeat in different views.", 'start': 1191.134, 'duration': 5.741}, {'end': 1199.316, 'text': 'And then it basically just wraps around those views.', 'start': 1196.915, 'duration': 2.401}, {'end': 1203.777, 'text': "So I think it's default layout.", 'start': 1200.976, 'duration': 2.801}, {'end': 1204.817, 'text': 'Let me just check.', 'start': 1203.797, 'duration': 1.02}], 'summary': 'Default layout wraps around views to avoid repeating html head and body tags.', 'duration': 23.966, 'max_score': 1180.851, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1180851.jpg'}, {'end': 1613.745, 'src': 'heatmap', 'start': 1399.426, 'weight': 7, 'content': [{'end': 1404.771, 'text': "So we'll just send some text to the client and we'll just say log in.", 'start': 1399.426, 'duration': 5.345}, {'end': 1407.712, 'text': "And then I'll do the same for dashboard.", 'start': 1405.97, 'duration': 1.742}, {'end': 1409.053, 'text': "That's also going to go in here.", 'start': 1407.832, 'duration': 1.221}, {'end': 1412.697, 'text': 'So this is going to be the dashboard.', 'start': 1410.294, 'duration': 2.403}, {'end': 1418.722, 'text': "And it's going to get request to slash dashboard.", 'start': 1412.717, 'duration': 6.005}, {'end': 1424.068, 'text': 'And of course, we need to change this.', 'start': 1418.742, 'duration': 5.326}, {'end': 1426.62, 'text': 'All right.', 'start': 1426.38, 'duration': 0.24}, {'end': 1433.803, 'text': 'Now, in order to use this file, we need to go to AppJS and we need to basically link our routing files.', 'start': 1426.74, 'duration': 7.063}, {'end': 1441.645, 'text': "So here let's say routes and let's do app dot use.", 'start': 1433.923, 'duration': 7.722}, {'end': 1451.329, 'text': "So anything that's just slash is going to link to that file we just created, which is dot slash route slash index.", 'start': 1442.046, 'duration': 9.283}, {'end': 1467.384, 'text': 'OK so now if I open up a browser and I go to HTTP local host port 3000 I see log in if I go to slash dashboard I spelled it wrong.', 'start': 1453.268, 'duration': 14.116}, {'end': 1479.529, 'text': "Dashboard We see dashboard now it's not rendering any any views or templates or anything it's just sending the text.", 'start': 1471.829, 'duration': 7.7}, {'end': 1487.535, 'text': 'So what we want to do now is create inside views not in the layouts but just in the views folder.', 'start': 1480.11, 'duration': 7.425}, {'end': 1502.345, 'text': "I'm going to create a file called let's create dashboard dot HBS and let's also create inside views a full not a folder a file.", 'start': 1488.055, 'duration': 14.29}, {'end': 1506.378, 'text': 'called login dot HBS.', 'start': 1503.737, 'duration': 2.641}, {'end': 1513.16, 'text': "So in login, let's just put each ones for now just so we can make sure that these render.", 'start': 1508.058, 'duration': 5.102}, {'end': 1514.801, 'text': 'So dashboard, another H1.', 'start': 1513.26, 'duration': 1.541}, {'end': 1520.523, 'text': "OK, so we'll save that now in order to render these is simple.", 'start': 1514.941, 'duration': 5.582}, {'end': 1523.364, 'text': 'We just need to go back to our routing, our index route.', 'start': 1520.543, 'duration': 2.821}, {'end': 1530.206, 'text': 'And instead of send, we want to change both of these to render and just make this lowercase this to.', 'start': 1523.924, 'duration': 6.282}, {'end': 1536.543, 'text': "And it's going to look for templates or views called login and dashboards.", 'start': 1532.14, 'duration': 4.403}, {'end': 1546.228, 'text': "Now if I go back and reload now we see the H1 if I go to dashboard we see the H1 and it's wrapped in that main layout.", 'start': 1536.603, 'duration': 9.625}, {'end': 1547.469, 'text': 'You can see the title here.', 'start': 1546.268, 'duration': 1.201}, {'end': 1554.052, 'text': "So let's start to add some of the stuff to the layout like materialize.", 'start': 1548.946, 'duration': 5.106}, {'end': 1561.68, 'text': "So I'm going to go to the main HBS layout and let's search for materialize.", 'start': 1554.072, 'duration': 7.608}, {'end': 1568.708, 'text': "So if we go to get started I'm going to grab the CDN here.", 'start': 1565.624, 'duration': 3.084}, {'end': 1574.36, 'text': 'And put this here.', 'start': 1571.858, 'duration': 2.502}, {'end': 1578.382, 'text': 'And then we also want the JavaScript, the materialized JavaScript.', 'start': 1574.52, 'duration': 3.862}, {'end': 1583.226, 'text': "What's really cool about this framework is you don't need jQuery like a lot of others.", 'start': 1579.243, 'duration': 3.983}, {'end': 1588.029, 'text': "So that we're going to put right here, right above the ending body tag.", 'start': 1584.426, 'duration': 3.603}, {'end': 1590.03, 'text': "I'm also going to be using Font Awesome.", 'start': 1588.349, 'duration': 1.681}, {'end': 1594.193, 'text': "So I'm going to go to CDNJS.com and search for Font Awesome.", 'start': 1590.05, 'duration': 4.143}, {'end': 1597.915, 'text': 'And grab the this right.', 'start': 1595.814, 'duration': 2.101}, {'end': 1599.876, 'text': "I'm actually going to use the CSS.", 'start': 1598.335, 'duration': 1.541}, {'end': 1601.697, 'text': 'So all dot min dot CSS.', 'start': 1599.936, 'duration': 1.761}, {'end': 1605.96, 'text': "I'm going to copy that link tag and put that right below materialize.", 'start': 1601.717, 'duration': 4.243}, {'end': 1613.745, 'text': "So if I save this and I go back to this page here, you can see it's using materialize now.", 'start': 1606.82, 'duration': 6.925}], 'summary': 'Creating routes for login and dashboard, rendering views, and adding materialize framework to the layout.', 'duration': 34.377, 'max_score': 1399.426, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1399426.jpg'}, {'end': 1561.68, 'src': 'embed', 'start': 1508.058, 'weight': 0, 'content': [{'end': 1513.16, 'text': "So in login, let's just put each ones for now just so we can make sure that these render.", 'start': 1508.058, 'duration': 5.102}, {'end': 1514.801, 'text': 'So dashboard, another H1.', 'start': 1513.26, 'duration': 1.541}, {'end': 1520.523, 'text': "OK, so we'll save that now in order to render these is simple.", 'start': 1514.941, 'duration': 5.582}, {'end': 1523.364, 'text': 'We just need to go back to our routing, our index route.', 'start': 1520.543, 'duration': 2.821}, {'end': 1530.206, 'text': 'And instead of send, we want to change both of these to render and just make this lowercase this to.', 'start': 1523.924, 'duration': 6.282}, {'end': 1536.543, 'text': "And it's going to look for templates or views called login and dashboards.", 'start': 1532.14, 'duration': 4.403}, {'end': 1546.228, 'text': "Now if I go back and reload now we see the H1 if I go to dashboard we see the H1 and it's wrapped in that main layout.", 'start': 1536.603, 'duration': 9.625}, {'end': 1547.469, 'text': 'You can see the title here.', 'start': 1546.268, 'duration': 1.201}, {'end': 1554.052, 'text': "So let's start to add some of the stuff to the layout like materialize.", 'start': 1548.946, 'duration': 5.106}, {'end': 1561.68, 'text': "So I'm going to go to the main HBS layout and let's search for materialize.", 'start': 1554.072, 'duration': 7.608}], 'summary': 'Updating login and dashboard rendering to include materialize in main layout.', 'duration': 53.622, 'max_score': 1508.058, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1508058.jpg'}, {'end': 1721.25, 'src': 'embed', 'start': 1691.288, 'weight': 9, 'content': [{'end': 1696.809, 'text': 'And the first argument is going to be double underscore der name, which just means the current directory.', 'start': 1691.288, 'duration': 5.521}, {'end': 1698.97, 'text': 'So an absolute path to the current directory.', 'start': 1696.909, 'duration': 2.061}, {'end': 1701.29, 'text': 'And then we want to go into public.', 'start': 1699.43, 'duration': 1.86}, {'end': 1703.531, 'text': "That's going to be our static folder.", 'start': 1701.99, 'duration': 1.541}, {'end': 1704.571, 'text': "So let's create that.", 'start': 1703.591, 'duration': 0.98}, {'end': 1715.403, 'text': "So in the route we want to create public and then in here let's create a folder called CSS and then in there let's create a file called style dot CSS.", 'start': 1705.831, 'duration': 9.572}, {'end': 1721.25, 'text': "And just to test things out I'm just going to say body background black.", 'start': 1715.843, 'duration': 5.407}], 'summary': "Creating a static folder 'public' with a 'css' folder and a 'style.css' file for a web application.", 'duration': 29.962, 'max_score': 1691.288, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1691288.jpg'}, {'end': 1781.461, 'src': 'embed', 'start': 1753.809, 'weight': 1, 'content': [{'end': 1756.93, 'text': 'Now the login, as I said, I want that to use a different layout.', 'start': 1753.809, 'duration': 3.121}, {'end': 1758.691, 'text': 'I want that to use the login layout.', 'start': 1756.97, 'duration': 1.721}, {'end': 1768.652, 'text': 'So the last thing I want to do for now in the main layout is just put a container class of materialized container class around the body,', 'start': 1759.666, 'duration': 8.986}, {'end': 1770.594, 'text': 'which will just, you know, push everything to the middle.', 'start': 1768.652, 'duration': 1.942}, {'end': 1774.256, 'text': "And then I'm going to copy everything here and go to log in.", 'start': 1771.214, 'duration': 3.042}, {'end': 1776.658, 'text': 'OK, this is the log in layout.', 'start': 1774.276, 'duration': 2.382}, {'end': 1781.461, 'text': "I'm sorry, this is not this is I know this might be a little confusing.", 'start': 1777.538, 'duration': 3.923}], 'summary': 'Updating layout for login and main page with materialized container class.', 'duration': 27.652, 'max_score': 1753.809, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1753809.jpg'}, {'end': 1885.83, 'src': 'heatmap', 'start': 1781.481, 'weight': 0.778, 'content': [{'end': 1787.025, 'text': 'I mean, you could call this something different, but we want to be in layouts, log in HBS.', 'start': 1781.481, 'duration': 5.544}, {'end': 1789.241, 'text': "I'm going to paste that in.", 'start': 1788.24, 'duration': 1.001}, {'end': 1791.141, 'text': "I'll just say storybooks login.", 'start': 1789.541, 'duration': 1.6}, {'end': 1800.246, 'text': "And the main reason I'm doing this is because we want to format this page a little different on the main layout.", 'start': 1792.242, 'duration': 8.004}, {'end': 1805.488, 'text': "We're going to have a partial for the nav bar and we don't want that in the login.", 'start': 1800.266, 'duration': 5.222}, {'end': 1808.91, 'text': 'We also want want this to be like, you know, a thin little box.', 'start': 1805.528, 'duration': 3.382}, {'end': 1814.413, 'text': "So what we'll do here is in addition to container, let's say login.", 'start': 1810.151, 'duration': 4.262}, {'end': 1817.955, 'text': 'container that we can we can style that on our own.', 'start': 1815.393, 'duration': 2.562}, {'end': 1824.1, 'text': 'And I also want this to be in a card class and then card content.', 'start': 1818.015, 'duration': 6.085}, {'end': 1827.623, 'text': "OK And we'll move the body up into there.", 'start': 1824.12, 'duration': 3.503}, {'end': 1831.966, 'text': 'And that should do it.', 'start': 1830.405, 'duration': 1.561}, {'end': 1835.069, 'text': "So right now it's still not using that.", 'start': 1832.166, 'duration': 2.903}, {'end': 1836.09, 'text': 'If I go back here.', 'start': 1835.129, 'duration': 0.961}, {'end': 1844.093, 'text': "If you don't see the card or anything, because we have to specifically say that we want that route to use this layout.", 'start': 1837.071, 'duration': 7.022}, {'end': 1847.274, 'text': 'And the way we do that is by going back to our index route file.', 'start': 1844.113, 'duration': 3.161}, {'end': 1855.417, 'text': "And as a second argument to render, we'll pass in an object with layout and we want to use the login layout.", 'start': 1848.175, 'duration': 7.242}, {'end': 1860.599, 'text': 'So now if I go back to the login and I reload, now we can see the card and so on.', 'start': 1856.017, 'duration': 4.582}, {'end': 1870.586, 'text': "OK, now I do, like I said, want this to be really thin, so I'm going to just go to our style sheet style CSS, which is being included in both layouts.", 'start': 1861.804, 'duration': 8.782}, {'end': 1882.609, 'text': "And let's say log in container and we'll set the width to 400 pixels, the margin to let's do 50 pixels.", 'start': 1871.506, 'duration': 11.103}, {'end': 1885.83, 'text': "I'm sorry, margin top because you want to push it down.", 'start': 1882.629, 'duration': 3.201}], 'summary': 'Adjusting layout for login page to include thin box and specific styling, using 400px width and 50px margin.', 'duration': 104.349, 'max_score': 1781.481, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1781481.jpg'}, {'end': 1940.691, 'src': 'embed', 'start': 1914.275, 'weight': 8, 'content': [{'end': 1918.958, 'text': "OK, so next thing, let's let's I guess style this.", 'start': 1914.275, 'duration': 4.683}, {'end': 1920.919, 'text': "We'll just style the login page.", 'start': 1919.018, 'duration': 1.901}, {'end': 1921.84, 'text': "It's not much.", 'start': 1920.979, 'duration': 0.861}, {'end': 1923.321, 'text': "It's really just a Google button.", 'start': 1921.86, 'duration': 1.461}, {'end': 1924.761, 'text': "So we'll go now.", 'start': 1923.821, 'duration': 0.94}, {'end': 1932.166, 'text': 'We can close the layouts, can actually close both the main layout and the login layout and the style sheet.', 'start': 1924.781, 'duration': 7.385}, {'end': 1935.928, 'text': "And we'll go actually close dashboard.", 'start': 1933.347, 'duration': 2.581}, {'end': 1940.691, 'text': 'So now we just want to go into login HBS, but not the layout, the view.', 'start': 1936.689, 'duration': 4.002}], 'summary': 'Styling the login page with a google button, closing layouts, and focusing on login hbs view.', 'duration': 26.416, 'max_score': 1914.275, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1914275.jpg'}, {'end': 1997.483, 'src': 'embed', 'start': 1966.877, 'weight': 6, 'content': [{'end': 1973.02, 'text': "And then let's have a class of section which is a materialized class and then a paragraph with the class of lead.", 'start': 1966.877, 'duration': 6.143}, {'end': 1983.746, 'text': "And we're just going to say create create public and private stories from your life.", 'start': 1973.541, 'duration': 10.205}, {'end': 1991.931, 'text': 'OK And then we want a class of divider which will just give us like a little border and then another section.', 'start': 1983.766, 'duration': 8.165}, {'end': 1995.143, 'text': 'And in this section, we want a button.', 'start': 1993.362, 'duration': 1.781}, {'end': 1997.483, 'text': 'So we want this to have a class of BTN.', 'start': 1995.323, 'duration': 2.16}], 'summary': 'Transcript covers creating materialized class, paragraph with lead class, and adding a button with class btn.', 'duration': 30.606, 'max_score': 1966.877, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1966877.jpg'}], 'start': 944.281, 'title': 'Mongodb connection, logging, and routing in node.js', 'summary': 'Covers connecting to mongodb, handling errors, exporting connection function, setting up morgan for logging, configuring handlebars template engine, creating layouts, setting default layout, setting up node.js routes, rendering views, linking routing files, including external libraries, and customizing layouts.', 'chapters': [{'end': 1029.681, 'start': 944.281, 'title': 'Connect to mongodb and export connection function', 'summary': 'Covers the process of connecting to mongodb, including console logging the successful connection with the host, handling errors with console error and stopping the process, and exporting the connect db function to be used in the app js file.', 'duration': 85.4, 'highlights': ['Console log MongoDB connected with the host when connecting to MongoDB. MongoDB connected', 'Handle connection errors by console logging the error and stopping the process with an exit code of 1. exit with failure (1)', 'Export the connect DB function to be used in the app JS file for connecting to MongoDB. exported connect DB function']}, {'end': 1284.487, 'start': 1030.3, 'title': 'Setting up morgan for logging and handlebars template engine', 'summary': "Covers setting up morgan for logging requests and configuring the handlebars template engine for the application, including creating layouts and setting default layout to 'main.hbs'. it also mentions using 'dot hbs' as the file extension for handlebars templates.", 'duration': 254.187, 'highlights': ["Setting up Morgan for logging requests The chapter discusses adding Morgan middleware to log requests in development mode using 'app.use Morgan'.", "Configuring Handlebars template engine The transcript details the process of configuring the Handlebars template engine, including setting the default layout to 'main.hbs' and using 'dot HBS' as the file extension for Handlebars templates.", "Creating layouts for different pages It mentions creating two layouts, 'main.HBS' and 'log in HBS', for different pages and defining the structure for the 'main.HBS' layout."]}, {'end': 1997.483, 'start': 1285.287, 'title': 'Node.js routing and view rendering', 'summary': 'Covers creating routes and rendering views using node.js and express, including setting up routes, rendering views, linking routing files, including external libraries like materialize and font awesome, creating a static folder for public assets, and customizing layouts for different routes.', 'duration': 712.196, 'highlights': ['Creating routes and rendering views using Node.js and Express The chapter covers creating routes and rendering views using Node.js and Express.', 'Setting up routes and linking routing files The process of setting up routes and linking routing files is explained in detail.', 'Including external libraries like Materialize and Font Awesome The chapter demonstrates including external libraries like Materialize and Font Awesome for front-end development.', 'Creating a static folder for public assets The process of creating a static folder for public assets is outlined, including using the path module for defining the static folder.', 'Customizing layouts for different routes The chapter covers customizing layouts for different routes, including using different layout files and styling specific route pages.']}], 'duration': 1053.202, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY944281.jpg', 'highlights': ['Export the connect DB function to be used in the app JS file for connecting to MongoDB. exported connect DB function', 'Console log MongoDB connected with the host when connecting to MongoDB. MongoDB connected', 'Handle connection errors by console logging the error and stopping the process with an exit code of 1. exit with failure (1)', "Setting up Morgan for logging requests The chapter discusses adding Morgan middleware to log requests in development mode using 'app.use Morgan'", "Configuring Handlebars template engine The transcript details the process of configuring the Handlebars template engine, including setting the default layout to 'main.hbs' and using 'dot HBS' as the file extension for Handlebars templates", 'Creating routes and rendering views using Node.js and Express The chapter covers creating routes and rendering views using Node.js and Express', 'Setting up routes and linking routing files The process of setting up routes and linking routing files is explained in detail', 'Including external libraries like Materialize and Font Awesome The chapter demonstrates including external libraries like Materialize and Font Awesome for front-end development', 'Creating a static folder for public assets The process of creating a static folder for public assets is outlined, including using the path module for defining the static folder', "Creating layouts for different pages It mentions creating two layouts, 'main.HBS' and 'log in HBS', for different pages and defining the structure for the 'main.HBS' layout", 'Customizing layouts for different routes The chapter covers customizing layouts for different routes, including using different layout files and styling specific route pages']}, {'end': 2690.095, 'segs': [{'end': 2029.183, 'src': 'embed', 'start': 1997.523, 'weight': 3, 'content': [{'end': 2000.664, 'text': "We're going to make it red and darken dash one.", 'start': 1997.523, 'duration': 3.141}, {'end': 2008.486, 'text': "The link is going to go to slash off slash Google, which is a route that we're going to create in a little bit.", 'start': 2002.164, 'duration': 6.322}, {'end': 2014.808, 'text': "And then in here, let's put the Google icon using font awesome.", 'start': 2009.586, 'duration': 5.222}, {'end': 2018.549, 'text': "So it's FAB for a class and then F a dash Google.", 'start': 2014.848, 'duration': 3.701}, {'end': 2023.419, 'text': 'OK And then we also want a class of left which will float it to the left.', 'start': 2020.196, 'duration': 3.223}, {'end': 2029.183, 'text': 'And then next to that icon will say log in with Google.', 'start': 2023.959, 'duration': 5.224}], 'summary': 'Creating a red button with google icon for logging in, with a route to /google.', 'duration': 31.66, 'max_score': 1997.523, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1997523.jpg'}, {'end': 2110.452, 'src': 'embed', 'start': 2051.303, 'weight': 0, 'content': [{'end': 2056.186, 'text': 'So the way that we do this, you want to go to your Google Cloud console.', 'start': 2051.303, 'duration': 4.883}, {'end': 2059.549, 'text': "I don't know the exact URL, so we'll just search for cloud console.", 'start': 2056.206, 'duration': 3.343}, {'end': 2061.31, 'text': 'We want to go right here.', 'start': 2060.208, 'duration': 1.102}, {'end': 2068.838, 'text': 'And you need to see you need to have a project.', 'start': 2063.851, 'duration': 4.987}, {'end': 2071.04, 'text': 'So you can see I already have one called dev one.', 'start': 2069.018, 'duration': 2.022}, {'end': 2074.043, 'text': "If you don't just go ahead and click new project and create one.", 'start': 2071.08, 'duration': 2.963}, {'end': 2077.868, 'text': 'And then we want to go to API and services.', 'start': 2075.125, 'duration': 2.743}, {'end': 2082.648, 'text': 'and then enable APIs and services.', 'start': 2080.106, 'duration': 2.542}, {'end': 2085.051, 'text': 'And we want Google Plus.', 'start': 2083.629, 'duration': 1.422}, {'end': 2088.833, 'text': 'If you scroll down, it should be right here.', 'start': 2085.61, 'duration': 3.223}, {'end': 2094.92, 'text': 'OK, so we want to click on that and then we want to you want to click enable.', 'start': 2088.853, 'duration': 6.067}, {'end': 2097.482, 'text': "Mine's already enabled, so I'm going to click manage.", 'start': 2095.239, 'duration': 2.243}, {'end': 2102.547, 'text': "And let's see, you want to go down to credentials.", 'start': 2099.384, 'duration': 3.163}, {'end': 2110.452, 'text': "This is a little confusing because you have create credentials here, but we don't have the OAuth option.", 'start': 2104.246, 'duration': 6.206}], 'summary': 'Go to google cloud console, create a project, enable google plus api, and manage credentials.', 'duration': 59.149, 'max_score': 2051.303, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY2051303.jpg'}, {'end': 2314.778, 'src': 'embed', 'start': 2286.477, 'weight': 7, 'content': [{'end': 2290.18, 'text': "So what we're going to do is save the user in our database.", 'start': 2286.477, 'duration': 3.703}, {'end': 2296.385, 'text': "OK, once they verify with Google, we'll save that stuff in our database and then they can use that as a login.", 'start': 2290.52, 'duration': 5.865}, {'end': 2297.746, 'text': 'All right.', 'start': 2296.405, 'duration': 1.341}, {'end': 2301.429, 'text': "And then the routes we're going to need these two routes off Google.", 'start': 2297.846, 'duration': 3.583}, {'end': 2305.332, 'text': 'And then we just call our Google strategy and then our callback.', 'start': 2302.149, 'duration': 3.183}, {'end': 2309.936, 'text': 'which again we use our Google strategy and we set a failure.', 'start': 2306.155, 'duration': 3.781}, {'end': 2314.778, 'text': "So if if it you know they don't log in correctly it'll redirect them here.", 'start': 2310.076, 'duration': 4.702}], 'summary': 'Implement user authentication using google, with 2 routes and a callback for failure.', 'duration': 28.301, 'max_score': 2286.477, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY2286477.jpg'}], 'start': 1997.523, 'title': 'Implementing and using google oauth for authentication', 'summary': 'Covers the implementation of google oauth for login, including creating api key and secret, enabling google plus api, and obtaining oauth client id and client secret for implementation. additionally, it discusses using google oauth 2.0 for authentication with passport, covering the creation of a google strategy, saving user data in a database, setting up passport middleware, and creating a user model with mongoose.', 'chapters': [{'end': 2199.327, 'start': 1997.523, 'title': 'Implementing google oauth for login', 'summary': 'Covers the implementation of google oauth for login, including creating api key and secret, enabling google plus api, and obtaining oauth client id and client secret for implementation.', 'duration': 201.804, 'highlights': ['The chapter covers the implementation of Google OAuth for login', 'The process involves creating an API key and an API secret', 'Enabling Google Plus API is a part of the process', 'Obtaining OAuth client ID and client secret is crucial for the implementation', 'Creating a web app and setting the redirect URIs are essential steps for OAuth client ID']}, {'end': 2690.095, 'start': 2199.767, 'title': 'Using google oauth for authentication', 'summary': 'Discusses using google oauth 2.0 for authentication with passport, covering the creation of a google strategy, saving user data in a database, setting up passport middleware, and creating a user model with mongoose.', 'duration': 490.328, 'highlights': ['Using Google OAuth 2.0 for authentication with Passport The chapter primarily focuses on using Google OAuth 2.0 for authentication with Passport, emphasizing the importance of this strategy.', 'Creating a Google strategy and passing client ID, secret, and callback URI It explains the process of creating a Google strategy and passing client ID, secret, and callback URI as essential steps in setting up the authentication system.', 'Saving user data in the database for login It mentions the importance of saving user data in the database for login purposes, highlighting the significance of this step in the authentication process.', 'Setting up passport middleware and implementing express session The chapter details the setup of passport middleware and the implementation of express session, highlighting the significance of these steps for the authentication system to work with sessions.', 'Creating a user model with Mongoose for database interaction It emphasizes the creation of a user model with Mongoose for database interaction, illustrating the importance of this model in handling user data.']}], 'duration': 692.572, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY1997523.jpg', 'highlights': ['The chapter covers the implementation of Google OAuth for login', 'Using Google OAuth 2.0 for authentication with Passport', 'Creating a Google strategy and passing client ID, secret, and callback URI', 'Saving user data in the database for login', 'Setting up passport middleware and implementing express session', 'Creating a user model with Mongoose for database interaction', 'Obtaining OAuth client ID and client secret is crucial for the implementation', 'Creating a web app and setting the redirect URIs are essential steps for OAuth client ID', 'Enabling Google Plus API is a part of the process', 'The process involves creating an API key and an API secret']}, {'end': 3512.846, 'segs': [{'end': 2718.705, 'src': 'embed', 'start': 2690.135, 'weight': 3, 'content': [{'end': 2693.237, 'text': "But I'm just going to get everything it gives us and then the image.", 'start': 2690.135, 'duration': 3.102}, {'end': 2695.098, 'text': 'So it also gives us an image.', 'start': 2693.597, 'duration': 1.501}, {'end': 2695.939, 'text': 'This is going to be.', 'start': 2695.118, 'duration': 0.821}, {'end': 2698.18, 'text': "Yeah, that'll be a string as well.", 'start': 2695.959, 'duration': 2.221}, {'end': 2700.321, 'text': "I'm going to take required away from that.", 'start': 2698.22, 'duration': 2.101}, {'end': 2705.505, 'text': "And then let's just add a created at.", 'start': 2702.843, 'duration': 2.662}, {'end': 2718.705, 'text': "So created at is going to be type date and we'll set a default of date dot now, which will just automatically put the date and time in.", 'start': 2707.839, 'duration': 10.866}], 'summary': 'Creating a data structure with an image and date field.', 'duration': 28.57, 'max_score': 2690.135, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY2690135.jpg'}, {'end': 3000.866, 'src': 'embed', 'start': 2974.887, 'weight': 1, 'content': [{'end': 2980.07, 'text': 'Alright, so it just looks a little cleaner.', 'start': 2974.887, 'duration': 5.183}, {'end': 2986.937, 'text': "So now we need to before we do anything here, this is I mean, we're just logging the profile data.", 'start': 2981.894, 'duration': 5.043}, {'end': 2989.239, 'text': 'We will ultimately we want to save it in the database.', 'start': 2986.977, 'duration': 2.262}, {'end': 2993.261, 'text': 'But I just want to set up our route so that we can actually use this strategy.', 'start': 2989.599, 'duration': 3.662}, {'end': 2999.305, 'text': "So to do that, let's go to routes and let's create a new file called off dot J.S.", 'start': 2993.821, 'duration': 5.484}, {'end': 3000.866, 'text': 'for any authentication routes.', 'start': 2999.345, 'duration': 1.521}], 'summary': 'Setting up authentication routes for saving profile data in the database.', 'duration': 25.979, 'max_score': 2974.887, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY2974887.jpg'}, {'end': 3119.806, 'src': 'embed', 'start': 3073.599, 'weight': 0, 'content': [{'end': 3074.76, 'text': "So that's for local.", 'start': 3073.599, 'duration': 1.161}, {'end': 3079.702, 'text': "Actually, let's go to the specific strategy.", 'start': 3075.38, 'duration': 4.322}, {'end': 3087.906, 'text': 'Google So the scope is like this.', 'start': 3080.903, 'duration': 7.003}, {'end': 3089.767, 'text': 'So scope profile.', 'start': 3088.566, 'duration': 1.201}, {'end': 3092.568, 'text': "So basically we're just asking for profile data.", 'start': 3089.787, 'duration': 2.781}, {'end': 3099.65, 'text': "So we'll just copy that and put that right in here like that.", 'start': 3093.846, 'duration': 5.804}, {'end': 3101.332, 'text': 'And that should do it.', 'start': 3099.671, 'duration': 1.661}, {'end': 3103.854, 'text': 'And of course, we need to bring in passport.', 'start': 3101.552, 'duration': 2.302}, {'end': 3114.602, 'text': "OK, that's that.", 'start': 3111.96, 'duration': 2.642}, {'end': 3117.784, 'text': 'Now, the second route that we want here is the callback.', 'start': 3114.722, 'duration': 3.062}, {'end': 3119.806, 'text': 'So say Google.', 'start': 3118.125, 'duration': 1.681}], 'summary': 'Developing a local strategy for google, focusing on profile data and integrating passport for authentication.', 'duration': 46.207, 'max_score': 3073.599, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY3073599.jpg'}, {'end': 3187.227, 'src': 'embed', 'start': 3158.266, 'weight': 2, 'content': [{'end': 3164.369, 'text': 'And then second will be an object and we can specify a failure redirect.', 'start': 3158.266, 'duration': 6.103}, {'end': 3169.733, 'text': 'So what do we want to happen if it fails we want it to redirect to slash which is the login.', 'start': 3164.469, 'duration': 5.264}, {'end': 3178.983, 'text': 'And then we want to go after the passport authenticate, which ends right here and put a comma.', 'start': 3170.518, 'duration': 8.465}, {'end': 3182.625, 'text': 'And then we have our function request response.', 'start': 3179.043, 'duration': 3.582}, {'end': 3187.227, 'text': "And all we're going to do is read redirect.", 'start': 3183.925, 'duration': 3.302}], 'summary': 'Configuring a failure redirect to /login after passport authentication.', 'duration': 28.961, 'max_score': 3158.266, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY3158266.jpg'}, {'end': 3310.531, 'src': 'heatmap', 'start': 3212.119, 'weight': 0.729, 'content': [{'end': 3214.7, 'text': "And if it passes, it'll redirect to the dashboard.", 'start': 3212.119, 'duration': 2.581}, {'end': 3221.636, 'text': 'OK, hopefully that makes sense and then of course in our app JS we need to bring that route file in.', 'start': 3216.431, 'duration': 5.205}, {'end': 3230.424, 'text': "So where is it? Where did I put the routes right here? So I'm just going to copy that down and let's say off.", 'start': 3221.656, 'duration': 8.768}, {'end': 3235.829, 'text': 'And any route that is slash off is going to be linked to that.', 'start': 3231.745, 'duration': 4.084}, {'end': 3238.491, 'text': "So we shouldn't have errors down here.", 'start': 3236.69, 'duration': 1.801}, {'end': 3241.114, 'text': 'Just keep going down.', 'start': 3238.511, 'duration': 2.603}, {'end': 3247.081, 'text': 'Okay, so it looks like we still have some kind of error here.', 'start': 3244.258, 'duration': 2.823}, {'end': 3251.064, 'text': 'Requires a client ID option.', 'start': 3247.101, 'duration': 3.963}, {'end': 3254.887, 'text': 'I did put in a client ID.', 'start': 3251.164, 'duration': 3.723}, {'end': 3258.471, 'text': 'Oh, I forgot the T.', 'start': 3257.67, 'duration': 0.801}, {'end': 3262.365, 'text': 'OK, so no more errors.', 'start': 3261.064, 'duration': 1.301}, {'end': 3265.148, 'text': 'You guys probably saw that a while ago.', 'start': 3262.986, 'duration': 2.162}, {'end': 3267.07, 'text': "So let's try it out.", 'start': 3266.209, 'duration': 0.861}, {'end': 3270.934, 'text': 'And what should happen is we should just console log the profile.', 'start': 3267.35, 'duration': 3.584}, {'end': 3276.379, 'text': 'It should it should show us the the page to, you know, choose a Google account or whatever.', 'start': 3271.234, 'duration': 5.145}, {'end': 3278.661, 'text': "But let's let's just try it out.", 'start': 3277.02, 'duration': 1.641}, {'end': 3280.781, 'text': "So I'm going to go to the login and just reload.", 'start': 3278.701, 'duration': 2.08}, {'end': 3284.443, 'text': 'So this is the route, the home page login.', 'start': 3281.182, 'duration': 3.261}, {'end': 3294.467, 'text': "Now, if you have one Google account, I believe it just uses that, you know, obviously, if you're logged into Google, if not, you'll have to log in.", 'start': 3285.623, 'duration': 8.844}, {'end': 3297.808, 'text': 'But if you have multiple accounts, as I do, you should have an option here.', 'start': 3294.827, 'duration': 2.981}, {'end': 3300.669, 'text': "So I'm going to use just Jennifer Sheehan account.", 'start': 3297.828, 'duration': 2.841}, {'end': 3306.602, 'text': 'Now this here is going to hang because we never called the callback within our Google strategy.', 'start': 3301.289, 'duration': 5.313}, {'end': 3310.531, 'text': "However we did console log the profile and that's what I want you guys to see.", 'start': 3306.682, 'duration': 3.849}], 'summary': 'Debugging route issues and testing google account login functionality.', 'duration': 98.412, 'max_score': 3212.119, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY3212119.jpg'}], 'start': 2690.135, 'title': 'Integrating and implementing google authentication in node.js', 'summary': 'Discusses integrating google authentication with a mongoose model, including defining schema properties, exporting the model, and creating a google strategy. it also details implementing google authentication in a node.js application using passport.js, setting up routes, callback functions, and saving user profile data in the database.', 'chapters': [{'end': 2846.844, 'start': 2690.135, 'title': 'Integrating google authentication with mongoose model', 'summary': 'Discusses the process of integrating google authentication with a mongoose model, including defining schema properties, exporting the model, bringing the user model into passport config, and creating a google strategy using client id, client secret, and callback url.', 'duration': 156.709, 'highlights': ['Defining schema properties including type, default values, and required fields.', 'Exporting the Mongoose model for use in passport config to interact with the database.', 'Bringing the user model into passport config to enable interaction with the database.', 'Creating a Google strategy using client ID, client secret, and callback URL for authentication.', 'Using an arrow function with async/await for dealing with Mongoose during the creation of a Google strategy.']}, {'end': 3512.846, 'start': 2846.864, 'title': 'Implementing google authentication', 'summary': 'Details the process of implementing google authentication in a node.js application using passport.js, including setting up the necessary routes and callback functions, and extracting and storing user profile data from google, with the ultimate goal of saving it in the database.', 'duration': 665.982, 'highlights': ['The chapter explains the process of implementing Google authentication in a Node.js application using Passport.js, emphasizing the setup of routes and callback functions, and the extraction and storage of user profile data from Google.', 'The author details the steps to set up the necessary routes and callback functions for Google authentication in a Node.js application using Passport.js, ensuring the inclusion of scope, strategy, and redirect options.', "The chapter demonstrates the extraction and storage of user profile data from Google, including the user's ID, display name, first and last name, image, and the process of checking for existing users and creating new ones in the database using Mongoose."]}], 'duration': 822.711, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY2690135.jpg', 'highlights': ['Creating a Google strategy using client ID, client secret, and callback URL for authentication.', 'The chapter explains the process of implementing Google authentication in a Node.js application using Passport.js, emphasizing the setup of routes and callback functions, and the extraction and storage of user profile data from Google.', "The chapter demonstrates the extraction and storage of user profile data from Google, including the user's ID, display name, first and last name, image, and the process of checking for existing users and creating new ones in the database using Mongoose.", 'Defining schema properties including type, default values, and required fields.', 'Exporting the Mongoose model for use in passport config to interact with the database.']}, {'end': 4247.374, 'segs': [{'end': 3537.912, 'src': 'embed', 'start': 3513.106, 'weight': 6, 'content': [{'end': 3519.072, 'text': 'So we should be able to authenticate now and it should get saved in the database.', 'start': 3513.106, 'duration': 5.966}, {'end': 3526.54, 'text': "So let's go back here and reload and click log in with Google and click Jennifer.", 'start': 3519.133, 'duration': 7.407}, {'end': 3531.426, 'text': 'So we get redirected to the dashboard which is exactly what should happen.', 'start': 3527.902, 'duration': 3.524}, {'end': 3537.912, 'text': "But let's go to our database and we should be able to check out our data by going to collections.", 'start': 3532.591, 'duration': 5.321}], 'summary': 'Successful authentication with google, data saved in database.', 'duration': 24.806, 'max_score': 3513.106, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY3513106.jpg'}, {'end': 3841.353, 'src': 'heatmap', 'start': 3700.607, 'weight': 3, 'content': [{'end': 3706.489, 'text': 'We have the logo which is centered and then we have a link here with the data target of mobile demo.', 'start': 3700.607, 'duration': 5.882}, {'end': 3709.791, 'text': 'And then this UL has an ID of mobile demo.', 'start': 3707.069, 'duration': 2.722}, {'end': 3716.554, 'text': 'So when you click on this which is the bars icon basically a hamburger menu it will open this up.', 'start': 3711.011, 'duration': 5.543}, {'end': 3723.161, 'text': "Now I'm going to save this and go to my main layout and I want to insert this.", 'start': 3717.458, 'duration': 5.703}, {'end': 3728.923, 'text': "So I'm going to go right above the container and we can insert a partial like this.", 'start': 3723.181, 'duration': 5.742}, {'end': 3732.765, 'text': 'OK I believe is it to.', 'start': 3728.943, 'duration': 3.822}, {'end': 3737.067, 'text': 'We just double check that.', 'start': 3732.785, 'duration': 4.282}, {'end': 3739.228, 'text': 'Yeah So that should insert the header.', 'start': 3737.127, 'duration': 2.101}, {'end': 3742.089, 'text': "So I'm going to save that and then we'll go back.", 'start': 3739.248, 'duration': 2.841}, {'end': 3745.491, 'text': 'Now we want to go to the dashboard and reload.', 'start': 3742.369, 'duration': 3.122}, {'end': 3748.297, 'text': 'And there we go.', 'start': 3747.677, 'duration': 0.62}, {'end': 3755, 'text': "Now this if I click this, it doesn't work, because with materialize, if you want to use this sliding nav bar,", 'start': 3748.517, 'duration': 6.483}, {'end': 3757.622, 'text': 'you actually have to initialize it in the JavaScript.', 'start': 3755, 'duration': 2.622}, {'end': 3760.583, 'text': 'So we want to go to the main still in the main layout.', 'start': 3757.662, 'duration': 2.921}, {'end': 3764.805, 'text': "Let's go under under here and put in some script tags.", 'start': 3761.043, 'duration': 3.762}, {'end': 3770.528, 'text': 'And since we brought in materialize, we can use this M dot and then side nav.', 'start': 3765.265, 'duration': 5.263}, {'end': 3773.309, 'text': 'And we want to call a net.', 'start': 3771.708, 'duration': 1.601}, {'end': 3777.227, 'text': 'And then we need to select the class.', 'start': 3774.304, 'duration': 2.923}, {'end': 3780.07, 'text': 'So document query selector.', 'start': 3777.267, 'duration': 2.803}, {'end': 3782.553, 'text': 'And it has a class of side nav.', 'start': 3780.511, 'duration': 2.042}, {'end': 3784.415, 'text': 'So dot side nav.', 'start': 3782.573, 'duration': 1.842}, {'end': 3787.418, 'text': 'So this should initialize it.', 'start': 3785.896, 'duration': 1.522}, {'end': 3792.283, 'text': 'And then if we go back here and reload and I click that, there we go.', 'start': 3787.718, 'duration': 4.565}, {'end': 3802.931, 'text': 'All right now if I click log out this goes to off log out and remember that route logs us out and brings us back here.', 'start': 3794.807, 'duration': 8.124}, {'end': 3809.295, 'text': "Now if I go up here and I type in dashboard without logging in I can still go to it which I don't want.", 'start': 3803.492, 'duration': 5.803}, {'end': 3814.378, 'text': "So we're going to create a piece of middleware to make sure that we can't do that.", 'start': 3809.955, 'duration': 4.423}, {'end': 3817.641, 'text': "Also, if we are logged in, I don't want to see this page.", 'start': 3814.898, 'duration': 2.743}, {'end': 3819.703, 'text': 'I want to be booted back to the dashboard.', 'start': 3817.701, 'duration': 2.002}, {'end': 3821.644, 'text': 'So this is actually pretty easy.', 'start': 3820.163, 'duration': 1.481}, {'end': 3826.549, 'text': "I'm just going to collapse these and create a folder called Middleware.", 'start': 3821.664, 'duration': 4.885}, {'end': 3832.374, 'text': "And in here, we'll create auth.js.", 'start': 3829.652, 'duration': 2.722}, {'end': 3833.335, 'text': 'So this is..', 'start': 3832.915, 'duration': 0.42}, {'end': 3841.353, 'text': 'Off middleware and middleware is just a function that has access to the request and response objects.', 'start': 3834.326, 'duration': 7.027}], 'summary': 'Adding a mobile demo link with materialize, initializing a sliding nav bar, and creating a middleware function for authentication.', 'duration': 47.69, 'max_score': 3700.607, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY3700607.jpg'}, {'end': 4042.574, 'src': 'embed', 'start': 4008.658, 'weight': 0, 'content': [{'end': 4017.806, 'text': "This is the login, which should be insured guest because only a guest, someone that's not logged in should be able to see this.", 'start': 4008.658, 'duration': 9.148}, {'end': 4020.108, 'text': 'However, the dashboard is insure off.', 'start': 4018.166, 'duration': 1.942}, {'end': 4023.899, 'text': 'all right.', 'start': 4023.539, 'duration': 0.36}, {'end': 4024.92, 'text': "so we'll save that.", 'start': 4023.899, 'duration': 1.021}, {'end': 4025.781, 'text': "let's try it out.", 'start': 4024.92, 'duration': 0.861}, {'end': 4031.886, 'text': "so now, if i try to go to dashboard, i can't.", 'start': 4025.781, 'duration': 6.105}, {'end': 4042.574, 'text': "it just boots me back, but if i log in with google, i'm at my dashboard and if i try to go back to just the login page, i can't.", 'start': 4031.886, 'duration': 10.688}], 'summary': 'Login should be insured for guests only. dashboard is off limits. google login grants access.', 'duration': 33.916, 'max_score': 4008.658, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4008658.jpg'}, {'end': 4156.453, 'src': 'embed', 'start': 4125.381, 'weight': 5, 'content': [{'end': 4127.743, 'text': "So let me just close up what I don't need here.", 'start': 4125.381, 'duration': 2.362}, {'end': 4133.004, 'text': "And let's go into our app JS.", 'start': 4130.859, 'duration': 2.145}, {'end': 4141.979, 'text': "So in our app JS, we're going to go up to the top here and bring in, say, I call this Mongo.", 'start': 4134.126, 'duration': 7.853}, {'end': 4154.412, 'text': "store and we want to set this to require, and we're using connect mongo.", 'start': 4145.527, 'duration': 8.885}, {'end': 4156.453, 'text': 'now we just want to add on to this.', 'start': 4154.412, 'duration': 2.041}], 'summary': 'In the app js, the speaker is adding the connect mongo and setting it to require.', 'duration': 31.072, 'max_score': 4125.381, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4125381.jpg'}, {'end': 4247.374, 'src': 'embed', 'start': 4216.103, 'weight': 4, 'content': [{'end': 4219.726, 'text': "So now let's save that and we're going to try this again.", 'start': 4216.103, 'duration': 3.623}, {'end': 4221.487, 'text': "Let's reload and log in.", 'start': 4219.766, 'duration': 1.721}, {'end': 4228.631, 'text': "So now I'm logged in and I'm going to reload the page and notice it didn't put me out.", 'start': 4224.329, 'duration': 4.302}, {'end': 4237.978, 'text': "And that's because if I go to my database and I reload here, you can see sessions and there's our session.", 'start': 4229.572, 'duration': 8.406}, {'end': 4241.38, 'text': 'So the cookie and if we just see this.', 'start': 4238.078, 'duration': 3.302}, {'end': 4244.831, 'text': 'Right here.', 'start': 4244.491, 'duration': 0.34}, {'end': 4245.793, 'text': 'So passport.', 'start': 4244.932, 'duration': 0.861}, {'end': 4247.374, 'text': 'So it just shows our cookie.', 'start': 4245.953, 'duration': 1.421}], 'summary': 'Successfully logged in without being logged out due to the presence of the session in the database and the cookie.', 'duration': 31.271, 'max_score': 4216.103, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4216103.jpg'}], 'start': 3513.106, 'title': 'Google authentication integration and protected routes', 'summary': 'Outlines the successful integration of google authentication, enabling login/register via google account and storing data in the database. it also discusses creating protected routes, implementing middleware, and storing user sessions to prevent unauthorized access and enhance user experience.', 'chapters': [{'end': 3566.363, 'start': 3513.106, 'title': 'Google authentication integration', 'summary': 'Outlines the successful integration of google authentication, leading to the ability to log in/register using a google account and the data being saved in the database.', 'duration': 53.257, 'highlights': ['The successful integration of Google authentication, enabling users to log in/register using a Google account and the data being saved in the database.', 'The redirection to the dashboard upon logging in with Google, demonstrating the expected functionality of the authentication process.', 'The confirmation of the saved user data in the database, indicating the successful storage and retrieval of user information.', "The clear visualization of the user data within the 'users' collection of the 'storybooks' database, affirming the successful implementation of the Google authentication feature."]}, {'end': 4247.374, 'start': 3567.524, 'title': 'Creating protected routes and middleware', 'summary': 'Discusses creating a logout route, implementing a navigation bar, protecting routes using middleware, and storing user sessions in a database, resulting in the prevention of unauthorized access and providing a seamless user experience.', 'duration': 679.85, 'highlights': ["Implemented a logout route using 'router.get' and 'res.redirect' to log out the user, resulting in a '/off/logout' route and preventing unauthorized access.", 'Created a navigation bar as a partial, utilizing a hamburger menu with a logo link and dashboard link, providing a seamless user experience.', "Implemented middleware functions 'ensureAuthenticated' and 'ensureGuest' to protect routes and manage user access, resulting in the prevention of unauthorized access and seamless redirection based on user status.", "Stored user sessions in a database using 'connect-mongo' package, preventing automatic logouts upon server reload and providing a persistent user session."]}], 'duration': 734.268, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY3513106.jpg', 'highlights': ['The successful integration of Google authentication, enabling users to log in/register using a Google account and the data being saved in the database.', 'The confirmation of the saved user data in the database, indicating the successful storage and retrieval of user information.', "The clear visualization of the user data within the 'users' collection of the 'storybooks' database, affirming the successful implementation of the Google authentication feature.", 'The redirection to the dashboard upon logging in with Google, demonstrating the expected functionality of the authentication process.', "Stored user sessions in a database using 'connect-mongo' package, preventing automatic logouts upon server reload and providing a persistent user session.", "Implemented middleware functions 'ensureAuthenticated' and 'ensureGuest' to protect routes and manage user access, resulting in the prevention of unauthorized access and seamless redirection based on user status.", "Implemented a logout route using 'router.get' and 'res.redirect' to log out the user, resulting in a '/off/logout' route and preventing unauthorized access.", 'Created a navigation bar as a partial, utilizing a hamburger menu with a logo link and dashboard link, providing a seamless user experience.']}, {'end': 5539.017, 'segs': [{'end': 4371.352, 'src': 'embed', 'start': 4343.479, 'weight': 7, 'content': [{'end': 4349.403, 'text': "So in our index JS, we'll actually, before we do this, we need to create our story model,", 'start': 4343.479, 'duration': 5.924}, {'end': 4353.465, 'text': "because whenever we're dealing with a new resource in the database, we need a model for it.", 'start': 4349.403, 'duration': 4.062}, {'end': 4357.788, 'text': "Right So let's go to models and let's create.", 'start': 4353.545, 'duration': 4.243}, {'end': 4362.73, 'text': 'Story dot J.S.', 'start': 4359.509, 'duration': 3.221}, {'end': 4371.352, 'text': "And I'm going to just copy my user schema here, paste that in and change this to story.", 'start': 4362.73, 'duration': 8.622}], 'summary': 'Creating a new story model for a database resource in index.js.', 'duration': 27.873, 'max_score': 4343.479, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4343479.jpg'}, {'end': 4558.717, 'src': 'embed', 'start': 4533.979, 'weight': 6, 'content': [{'end': 4545.027, 'text': 'Now you have in order to pass in data to a template into a handlebars template and render it loop through it and all that we need to call dot lean.', 'start': 4533.979, 'duration': 11.048}, {'end': 4547.849, 'text': 'And this actually will tell us what this does.', 'start': 4545.907, 'duration': 1.942}, {'end': 4555.234, 'text': 'So documents returned from queries with the lean option enabled are plain JavaScript objects not Mongoose documents.', 'start': 4548.569, 'duration': 6.665}, {'end': 4558.717, 'text': "And that's what we need in order to pass it in and use it in a template.", 'start': 4555.394, 'duration': 3.323}], 'summary': 'Using dot lean allows passing plain javascript objects in mongoose templates.', 'duration': 24.738, 'max_score': 4533.979, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4533979.jpg'}, {'end': 4744.692, 'src': 'embed', 'start': 4711.611, 'weight': 5, 'content': [{'end': 4713.512, 'text': "So let's first just construct the table.", 'start': 4711.611, 'duration': 1.901}, {'end': 4720.297, 'text': "So we'll say table and give it a class of striped and then let's create the heading.", 'start': 4714.193, 'duration': 6.104}, {'end': 4727.823, 'text': 'So the T head with the table row of table headings of title.', 'start': 4720.477, 'duration': 7.346}, {'end': 4733.165, 'text': 'So I have title will have.', 'start': 4731.624, 'duration': 1.541}, {'end': 4736.067, 'text': 'The date.', 'start': 4733.185, 'duration': 2.882}, {'end': 4740.11, 'text': "And we'll have the status.", 'start': 4737.788, 'duration': 2.322}, {'end': 4744.692, 'text': 'And then this is just for like the delete, edit and delete buttons.', 'start': 4741.31, 'duration': 3.382}], 'summary': "Creating a table with class 'striped' and headings for title, date, and status.", 'duration': 33.081, 'max_score': 4711.611, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4711611.jpg'}, {'end': 4962.258, 'src': 'embed', 'start': 4933.087, 'weight': 2, 'content': [{'end': 4940.91, 'text': "So in views, we'll have a stories folder and let's create a file in stories called add HBS.", 'start': 4933.087, 'duration': 7.823}, {'end': 4943.171, 'text': 'So this will be our ad form.', 'start': 4941.73, 'duration': 1.441}, {'end': 4947.772, 'text': "And I'm just going to grab this because it's not it's not much.", 'start': 4943.211, 'duration': 4.561}, {'end': 4948.933, 'text': "It's not difficult.", 'start': 4948.073, 'duration': 0.86}, {'end': 4949.973, 'text': "So it's just a form.", 'start': 4949.033, 'duration': 0.94}, {'end': 4954.275, 'text': "It's going to make a post request to slash stories.", 'start': 4950.253, 'duration': 4.022}, {'end': 4958.277, 'text': 'And we have a title as a name and ID.', 'start': 4955.676, 'duration': 2.601}, {'end': 4960.457, 'text': 'We have a select field here.', 'start': 4958.877, 'duration': 1.58}, {'end': 4962.258, 'text': "We actually don't need unpublished.", 'start': 4960.738, 'duration': 1.52}], 'summary': 'Creating an ad form in the stories folder to make a post request with a title and select field.', 'duration': 29.171, 'max_score': 4933.087, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4933087.jpg'}, {'end': 5317.151, 'src': 'embed', 'start': 5285.153, 'weight': 1, 'content': [{'end': 5287.314, 'text': 'We want to create the story.', 'start': 5285.153, 'duration': 2.161}, {'end': 5289.836, 'text': 'So remember request dot body.', 'start': 5287.975, 'duration': 1.861}, {'end': 5297.54, 'text': "If you've worked with express, you know this request dot body is going to give us the data that sent in from the form.", 'start': 5290.656, 'duration': 6.884}, {'end': 5302.583, 'text': "However, in order to use request dot body, we need to add a piece of middleware which we haven't done yet.", 'start': 5297.6, 'duration': 4.983}, {'end': 5305.785, 'text': "So in our app JS file, let's go.", 'start': 5303.203, 'duration': 2.582}, {'end': 5310.888, 'text': 'Right after we initialize this and we need to.', 'start': 5307.306, 'duration': 3.582}, {'end': 5317.151, 'text': 'Add the body parser middleware, which is app to use to accept form data.', 'start': 5313.028, 'duration': 4.123}], 'summary': 'Adding body parser middleware to accept form data for story creation.', 'duration': 31.998, 'max_score': 5285.153, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY5285153.jpg'}, {'end': 5415.927, 'src': 'embed', 'start': 5373.184, 'weight': 0, 'content': [{'end': 5386.711, 'text': "So we want to wait and we'll use our story model and we want to just call create and we're going to pass in request dot body.", 'start': 5373.184, 'duration': 13.527}, {'end': 5388.392, 'text': "So that'll create it.", 'start': 5387.511, 'duration': 0.881}, {'end': 5394.495, 'text': "And then we just want to redirect to let's redirect to the dashboard.", 'start': 5388.472, 'duration': 6.023}, {'end': 5399.512, 'text': "All right, so we'll save that and then let's go back.", 'start': 5396.169, 'duration': 3.343}, {'end': 5403.416, 'text': "Let's reload this ad page and I'll say.", 'start': 5400.853, 'duration': 2.563}, {'end': 5407.039, 'text': "Let's say Jen story one.", 'start': 5403.436, 'duration': 3.603}, {'end': 5412.264, 'text': "And public and then I'll just say this is.", 'start': 5407.059, 'duration': 5.205}, {'end': 5415.927, 'text': 'My story.', 'start': 5414.786, 'duration': 1.141}], 'summary': "Using the story model, a new story 'jen story one' was created and made public on the dashboard.", 'duration': 42.743, 'max_score': 5373.184, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY5373184.jpg'}, {'end': 5468.842, 'src': 'embed', 'start': 5443.441, 'weight': 4, 'content': [{'end': 5451.888, 'text': "I'm just going off screen here and I'm just going to paste it in sublime text real quick and then copy it again just so there's no formatting to it.", 'start': 5443.441, 'duration': 8.447}, {'end': 5458.315, 'text': "And then I'll paste that in here and hopefully that gets rid of any formatting.", 'start': 5454.352, 'duration': 3.963}, {'end': 5465.22, 'text': "I mean, usually you're not going to paste stuff in here, but we'll go ahead and save this.", 'start': 5460.616, 'duration': 4.604}, {'end': 5466.461, 'text': 'So we get redirected.', 'start': 5465.3, 'duration': 1.161}, {'end': 5468.842, 'text': 'Wait, something went wrong.', 'start': 5467.401, 'duration': 1.441}], 'summary': 'Transcript pasted into sublime text, then pasted again to remove formatting. redirected but encountered error.', 'duration': 25.401, 'max_score': 5443.441, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY5443441.jpg'}], 'start': 4247.394, 'title': 'Dashboard functionality', 'summary': 'Focuses on integrating user authentication, creating and displaying stories, error handling, and handling form data, resulting in successful submission and display of the form on the dashboard.', 'chapters': [{'end': 4645.922, 'start': 4247.394, 'title': 'Dashboard stories and error handling', 'summary': 'Focuses on integrating user authentication to the dashboard, passing user name to the dashboard view, creating a story model with title, body, status, and user reference fields, querying and rendering stories data, and implementing error handling with 404 and 500 templates.', 'duration': 398.528, 'highlights': ['The user name is passed to the dashboard view to display a personalized welcome message and prepare for listing user-specific stories.', "A story model is created with fields for title, body, status, and user reference, where status is set as public by default and limited to 'public' or 'private' values.", 'Querying all stories belonging to the logged-in user and rendering the data in the dashboard view is implemented with error handling using 404 and 500 templates.']}, {'end': 5211.758, 'start': 4646.742, 'title': 'Looping through and displaying stories', 'summary': "Covers looping through and displaying stories in a table, adding an 'ad story' button, creating an ad form for new stories, and implementing ck editor for text areas.", 'duration': 565.016, 'highlights': ['Looping through and displaying stories in a table The chapter discusses looping through stories, checking for existing stories, and constructing a table to display story details, such as title, date, and status.', "Adding an 'ad story' button Instructions for creating an 'ad story' button that leads to a form for creating new stories, with a simple design and functionality explanation.", 'Creating an ad form for new stories The process involves creating a form for adding new stories, including fields for title, status, body, and options for implementing CK editor.', "Implementing CK editor for text areas The chapter explains the use of CK editor to convert a text area into a WYSIWYG editor, with instructions for integrating CK editor scripts and customizing the editor's features."]}, {'end': 5539.017, 'start': 5213.84, 'title': 'Creating a post request and handling form data', 'summary': 'Demonstrates the process of creating a post request to handle form data using express and mongodb, including setting up middleware for parsing form data, accessing request body and user data, and handling errors, resulting in successful submission and display of the form on the dashboard.', 'duration': 325.177, 'highlights': ['The process involves setting up middleware for parsing form data using Express dot URL encoded and accepting JSON data using Express dot JSON. Middleware setup for parsing form data and accepting JSON data to facilitate access to request body.', 'Accessing request body using request dot body to obtain the data sent from the form. Demonstrates the use of request dot body to retrieve form data.', 'Accessing user data from request dot user and adding it to the story schema. Incorporating the user data from request dot user into the story schema.', 'Handling errors by implementing a try-catch block and rendering an error page in case of an error. Implementation of error handling using try-catch block and rendering error page in case of an error.', 'Successful submission and display of the form on the dashboard after creating a post request and handling form data. Shows the successful submission and display of the form on the dashboard after the complete process.']}], 'duration': 1291.623, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY4247394.jpg', 'highlights': ['Querying all stories belonging to the logged-in user and rendering the data in the dashboard view is implemented with error handling using 404 and 500 templates.', 'Creating an ad form for new stories, including fields for title, status, body, and options for implementing CK editor.', 'Handling errors by implementing a try-catch block and rendering an error page in case of an error.', 'Looping through and displaying stories in a table, checking for existing stories, and constructing a table to display story details, such as title, date, and status.', "Implementing CK editor for text areas, explaining the use of CK editor to convert a text area into a WYSIWYG editor, with instructions for integrating CK editor scripts and customizing the editor's features.", 'The process involves setting up middleware for parsing form data using Express dot URL encoded and accepting JSON data using Express dot JSON.', 'Accessing request body using request dot body to obtain the data sent from the form.', 'Accessing user data from request dot user and adding it to the story schema.', 'The user name is passed to the dashboard view to display a personalized welcome message and prepare for listing user-specific stories.', "A story model is created with fields for title, body, status, and user reference, where status is set as public by default and limited to 'public' or 'private' values."]}, {'end': 6424.038, 'segs': [{'end': 5575.278, 'src': 'embed', 'start': 5539.257, 'weight': 3, 'content': [{'end': 5542.898, 'text': 'So we see the title, the date, which I want to format and then public.', 'start': 5539.257, 'duration': 3.641}, {'end': 5545.586, 'text': 'OK and if we go to our database.', 'start': 5543.985, 'duration': 1.601}, {'end': 5551.891, 'text': 'Stories And there it is.', 'start': 5549.029, 'duration': 2.862}, {'end': 5555.855, 'text': "So yeah so it's formatted with paragraphs which it should be.", 'start': 5552.912, 'duration': 2.943}, {'end': 5560.098, 'text': "But yeah it shouldn't have any styling or anything good.", 'start': 5557.216, 'duration': 2.882}, {'end': 5563.961, 'text': "And the user is that's the user I.D.", 'start': 5561.679, 'duration': 2.282}, {'end': 5564.522, 'text': 'right there.', 'start': 5564.001, 'duration': 0.521}, {'end': 5568.365, 'text': "So now we're able to add stories.", 'start': 5566.103, 'duration': 2.262}, {'end': 5570.326, 'text': "Let's just add one more say.", 'start': 5568.765, 'duration': 1.561}, {'end': 5575.278, 'text': 'Jen story to.', 'start': 5573.737, 'duration': 1.541}], 'summary': 'Database displays stories with proper formatting, allowing addition of user-generated stories.', 'duration': 36.021, 'max_score': 5539.257, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY5539257.jpg'}, {'end': 6084.389, 'src': 'embed', 'start': 6056.473, 'weight': 1, 'content': [{'end': 6062.537, 'text': 'And this is going to be this is going to go to slash stories slash and then the ID of the story.', 'start': 6056.473, 'duration': 6.064}, {'end': 6067.019, 'text': "So underscore ID because it's just going to go to the single story page.", 'start': 6062.597, 'duration': 4.422}, {'end': 6068.941, 'text': "So here we'll just say read more.", 'start': 6067.099, 'duration': 1.842}, {'end': 6071.282, 'text': 'And I think that should do it.', 'start': 6070.061, 'duration': 1.221}, {'end': 6072.243, 'text': "So we'll save that.", 'start': 6071.342, 'duration': 0.901}, {'end': 6076.187, 'text': 'Just go down here, make sure we have no errors.', 'start': 6074.326, 'duration': 1.861}, {'end': 6080.028, 'text': "So we'll save that and then let's go to our stories routes.", 'start': 6076.747, 'duration': 3.281}, {'end': 6084.389, 'text': 'So I want to go to routes and then stories J.S.', 'start': 6081.008, 'duration': 3.381}], 'summary': 'Creating a link to a story with id on the single story page.', 'duration': 27.916, 'max_score': 6056.473, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY6056473.jpg'}, {'end': 6171.788, 'src': 'embed', 'start': 6144.038, 'weight': 0, 'content': [{'end': 6146.959, 'text': 'Now on the try, we want to fetch the stories.', 'start': 6144.038, 'duration': 2.921}, {'end': 6155.883, 'text': "So we want to wait, take our model and call find and we're going to get all the public stories.", 'start': 6148.36, 'duration': 7.523}, {'end': 6157.324, 'text': "So let's say we're a status.", 'start': 6155.943, 'duration': 1.381}, {'end': 6160.324, 'text': 'is equal to public.', 'start': 6158.363, 'duration': 1.961}, {'end': 6163.065, 'text': "And then I'm going to populate.", 'start': 6161.764, 'duration': 1.301}, {'end': 6170.247, 'text': 'So I want to add on to that populate with the user models because I want that user data like the name and stuff like that.', 'start': 6163.125, 'duration': 7.122}, {'end': 6171.788, 'text': "That's not part of the story.", 'start': 6170.327, 'duration': 1.461}], 'summary': 'Fetching all public stories and populating user data.', 'duration': 27.75, 'max_score': 6144.038, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY6144038.jpg'}, {'end': 6269.671, 'src': 'embed', 'start': 6239.102, 'weight': 4, 'content': [{'end': 6240.102, 'text': "So let's try that again.", 'start': 6239.102, 'duration': 1}, {'end': 6243.584, 'text': "Let's reload and let's go public stories.", 'start': 6240.122, 'duration': 3.462}, {'end': 6244.985, 'text': 'And there we go.', 'start': 6244.425, 'duration': 0.56}, {'end': 6247.407, 'text': 'Now, right off the bat, you can see the problem here.', 'start': 6245.085, 'duration': 2.322}, {'end': 6254.214, 'text': "So this one I mean these are just short text but this body has a bunch of text in it and it's just way too long.", 'start': 6248.147, 'duration': 6.067}, {'end': 6256.356, 'text': "Also it's showing us the tags.", 'start': 6254.634, 'duration': 1.722}, {'end': 6258.558, 'text': "So I'm going to create two new helpers.", 'start': 6256.436, 'duration': 2.122}, {'end': 6262.602, 'text': 'One is going to strip the tags out and one is going to truncate the text.', 'start': 6258.658, 'duration': 3.944}, {'end': 6269.671, 'text': "so let's jump back into our helpers file, which is this hbs file,", 'start': 6263.323, 'duration': 6.348}], 'summary': 'Identified issues with text length and tags in public stories, creating two new helpers for resolution.', 'duration': 30.569, 'max_score': 6239.102, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY6239102.jpg'}, {'end': 6343.131, 'src': 'embed', 'start': 6320.326, 'weight': 2, 'content': [{'end': 6328.454, 'text': "So this is just a regular expression that's going to look for anything with the front and back brackets, angle brackets and replace it with nothing.", 'start': 6320.326, 'duration': 8.128}, {'end': 6329.995, 'text': "So that's all that's doing.", 'start': 6328.954, 'duration': 1.041}, {'end': 6335.26, 'text': 'So now we should be able to use strip tags and truncate, although before we can use them, we have to.', 'start': 6330.396, 'duration': 4.864}, {'end': 6336.862, 'text': 'Register them.', 'start': 6336.221, 'duration': 0.641}, {'end': 6339.586, 'text': "So we're going to bring them in from the helpers file.", 'start': 6336.942, 'duration': 2.644}, {'end': 6343.131, 'text': 'So we have strip tags and we have truncate.', 'start': 6339.626, 'duration': 3.505}], 'summary': 'A regular expression is used to remove angle brackets, enabling the use of strip tags and truncate functions from the helpers file.', 'duration': 22.805, 'max_score': 6320.326, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY6320326.jpg'}], 'start': 5539.257, 'title': 'Formatting date and story display', 'summary': 'Covers formatting dates with moment js, creating a view for public stories, implementing user images, creating routes for story display, fetching and rendering stories, and creating helpers for text manipulation in templates.', 'chapters': [{'end': 5981.407, 'start': 5539.257, 'title': 'Formatting date and public stories', 'summary': 'Demonstrates the process of formatting a date using moment js and creating a view to display public stories, including the use of handlebar helpers and materialize classes.', 'duration': 442.15, 'highlights': ['The chapter demonstrates the process of formatting a date using Moment JS. The speaker explains the process of formatting a date using Moment JS, highlighting the ability to customize the format, and provides an example of the formatted date.', 'Creating a view to display public stories. The chapter discusses creating a view to display public stories, including looping through the stories and handling cases where no stories are present.', "Use of handlebar helpers and materialize classes. The speaker explains the use of handlebar helpers for displaying icons and the use of materialize classes like 'chip' for styling the UI."]}, {'end': 6424.038, 'start': 5981.787, 'title': 'Implementing user image and story display', 'summary': 'Covers implementing user images in story display, creating routes to show all stories, fetching and rendering stories, and creating helpers to strip html tags and truncate text in a template.', 'duration': 442.251, 'highlights': ["Creating routes to show all stories and fetching/rendering stories The chapter discusses creating routes to show all stories, fetching the public stories and rendering them in the template. The route is a get request to stories, fetching public stories with a status of 'public', populating user data, sorting by 'created at', and rendering the 'stories index' template.", "Implementing user images in story display The chapter covers adding user images in story display by populating the stories with user data, creating a link to show all stories of a specific user, and displaying the user's display name.", 'Creating helpers to strip HTML tags and truncate text in a template The chapter discusses creating helpers to strip HTML tags and truncate text in a template. It explains the logic of the truncate function to cut the text to a specified length and add ellipses, as well as the strip tags function using regular expressions to remove HTML tags.']}], 'duration': 884.781, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY5539257.jpg', 'highlights': ["Creating routes to show all stories and fetching/rendering stories The chapter discusses creating routes to show all stories, fetching the public stories and rendering them in the template. The route is a get request to stories, fetching public stories with a status of 'public', populating user data, sorting by 'created at', and rendering the 'stories index' template.", "Implementing user images in story display The chapter covers adding user images in story display by populating the stories with user data, creating a link to show all stories of a specific user, and displaying the user's display name.", 'Creating a view to display public stories. The chapter discusses creating a view to display public stories, including looping through the stories and handling cases where no stories are present.', "Use of handlebar helpers and materialize classes. The speaker explains the use of handlebar helpers for displaying icons and the use of materialize classes like 'chip' for styling the UI.", 'Creating helpers to strip HTML tags and truncate text in a template The chapter discusses creating helpers to strip HTML tags and truncate text in a template. It explains the logic of the truncate function to cut the text to a specified length and add ellipses, as well as the strip tags function using regular expressions to remove HTML tags.', 'The chapter demonstrates the process of formatting a date using Moment JS. The speaker explains the process of formatting a date using Moment JS, highlighting the ability to customize the format, and provides an example of the formatted date.']}, {'end': 8922.031, 'segs': [{'end': 6940.411, 'src': 'embed', 'start': 6900.424, 'weight': 0, 'content': [{'end': 6914.776, 'text': "OK so we want to show the edit page and it's going to be a get request to stories slash edit slash and then the I.D.", 'start': 6900.424, 'duration': 14.352}, {'end': 6916.978, 'text': 'of that story.', 'start': 6916.157, 'duration': 0.821}, {'end': 6921.101, 'text': "So here it's going to be edit and then the I.D.", 'start': 6917.338, 'duration': 3.763}, {'end': 6928.127, 'text': 'parameter ensure off and then we want to mark this a sink.', 'start': 6921.181, 'duration': 6.946}, {'end': 6934.426, 'text': "And then here we want to say Cont's story.", 'start': 6931.703, 'duration': 2.723}, {'end': 6940.411, 'text': "We want to wait on story dot and let's use find one.", 'start': 6934.446, 'duration': 5.965}], 'summary': 'Implement a get request for editing a story using the story id.', 'duration': 39.987, 'max_score': 6900.424, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY6900424.jpg'}, {'end': 7024.307, 'src': 'embed', 'start': 7001.479, 'weight': 1, 'content': [{'end': 7015.364, 'text': "We'll say if the story from the database, if the story dot user is not equal to the request dot user dot ID, which is the currently logged in user.", 'start': 7001.479, 'duration': 13.885}, {'end': 7024.307, 'text': "if that's not true, then let's redirect and we'll just redirect us to the public stories, which is just slash stories.", 'start': 7015.364, 'duration': 8.943}], 'summary': 'Redirect to public stories if current user does not match story user.', 'duration': 22.828, 'max_score': 7001.479, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY7001479.jpg'}, {'end': 7652.588, 'src': 'embed', 'start': 7622.336, 'weight': 3, 'content': [{'end': 7624.078, 'text': 'Slash and then the ID.', 'start': 7622.336, 'duration': 1.742}, {'end': 7629.742, 'text': "OK, and then let's change this to just.", 'start': 7624.098, 'duration': 5.644}, {'end': 7636.128, 'text': "This is going to be just slashed slash ID, but it's going to be router dot put.", 'start': 7631.164, 'duration': 4.964}, {'end': 7637.629, 'text': "It's going to be a put request.", 'start': 7636.428, 'duration': 1.201}, {'end': 7640.932, 'text': "All right, let's see, we're going to.", 'start': 7639.19, 'duration': 1.742}, {'end': 7646.545, 'text': "Fetch We're going to check to see if the story is there.", 'start': 7643.103, 'duration': 3.442}, {'end': 7650.787, 'text': "So let's say let story equals a weight.", 'start': 7646.625, 'duration': 4.162}, {'end': 7652.588, 'text': 'OK, we have to add a sink here.', 'start': 7651.227, 'duration': 1.361}], 'summary': 'Changing to slash id, router dot put for put request, fetching and checking story existence.', 'duration': 30.252, 'max_score': 7622.336, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY7622336.jpg'}, {'end': 7775.361, 'src': 'embed', 'start': 7750.083, 'weight': 4, 'content': [{'end': 7756.144, 'text': "the object we're going to put in the request dot body, because that's the data we want to replace it with,", 'start': 7750.083, 'duration': 6.061}, {'end': 7759.425, 'text': "and I'm also going to add some options as a third argument.", 'start': 7756.144, 'duration': 3.281}, {'end': 7769.777, 'text': "one is new and I'm going to set that to true, so it'll just create a new one if it doesn't exist, and then run validators, Run validators.", 'start': 7759.425, 'duration': 10.352}, {'end': 7775.361, 'text': "I'm also going to set to true, which means it'll just check up, make sure that the mongoose fields are valid.", 'start': 7769.797, 'duration': 5.564}], 'summary': 'Replace request data, add options for creating new object and running validators.', 'duration': 25.278, 'max_score': 7750.083, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY7750083.jpg'}, {'end': 8735.573, 'src': 'embed', 'start': 8692.451, 'weight': 2, 'content': [{'end': 8694.913, 'text': "So it's the routes stories.", 'start': 8692.451, 'duration': 2.462}, {'end': 8700.559, 'text': "And so we want the user story, so I'm going to.", 'start': 8697.356, 'duration': 3.203}, {'end': 8709.508, 'text': 'Should I use for this? Show single story.', 'start': 8703.282, 'duration': 6.226}, {'end': 8712.131, 'text': "I'll just copy the first one.", 'start': 8710.85, 'duration': 1.281}, {'end': 8720.619, 'text': 'This is a lot of code for one YouTube video.', 'start': 8718.637, 'duration': 1.982}, {'end': 8725.188, 'text': 'So here this is going to be the user stories.', 'start': 8721.986, 'duration': 3.202}, {'end': 8731.311, 'text': "It's going to be a get request to story slash user slash and then it's going to be the user ID.", 'start': 8725.508, 'duration': 5.803}, {'end': 8735.573, 'text': "OK So here we're going to say get.", 'start': 8731.331, 'duration': 4.242}], 'summary': 'Developing a route for user stories; implementing a get request to retrieve user stories by user id.', 'duration': 43.122, 'max_score': 8692.451, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY8692451.jpg'}], 'start': 6424.038, 'title': 'Updating web application functionalities', 'summary': 'Covers adding edit icon to helper function, handling handlebars html parsing and form editing, using mongoose method for updating data, handling delete requests and showing single story, and creating user stories template in a web application.', 'chapters': [{'end': 6741.964, 'start': 6424.038, 'title': 'Adding edit icon to helper function', 'summary': 'Explains the process of adding an edit icon to the helper function, which involves passing parameters such as story user, logged in user, story id, and implementing a floating button in materialize. additionally, it addresses the challenge of accessing global user in the template and the solution of setting a global variable in app.js using middleware.', 'duration': 317.926, 'highlights': ['Explaining the function to add edit icon to the helper The function takes in parameters like story user, logged in user, and story ID, while implementing a floating button in materialize and checking the equality of user IDs.', 'Discussing the challenge of accessing global user in the template The chapter addresses the issue of not having access to the global user in the template and proposes setting a global variable in app.js using middleware to solve it.']}, {'end': 7720.002, 'start': 6742.504, 'title': 'Handlebars html parsing and form editing', 'summary': 'Outlines the process of parsing html with handlebars by using triple curly braces, adding font size to public css, and creating an edit page and functionality to render and update a story, including passing the story values within the edit page form and handling put requests with the method-override package.', 'duration': 977.498, 'highlights': ['The chapter outlines the process of parsing HTML with handlebars by using triple curly braces. The speaker explains that in order to parse HTML with handlebars, one needs to use triple curly braces.', 'Adding font size to public CSS for the edit icon. The speaker adds a font size of 16 pixels with important to the F.A. small class in the public CSS, resulting in a smaller edit button.', 'Creating an edit page and functionality to render and update a story, including passing the story values within the edit page form. The speaker discusses the creation of an edit page and the functionality to render and update a story, including passing the story values within the edit page form, allowing the user to edit the story.', 'Handling put requests with the method-override package. The speaker explains the process of handling put requests by using the method-override package, which allows replacing the standard method with put requests in the form.']}, {'end': 8091.605, 'start': 7720.002, 'title': 'Mongoose method for updating data', 'summary': 'Discusses using the mongoose method to update data in a web application, including finding by id, updating with request body, setting options for creating new data, running validators, and redirecting to the dashboard, with an emphasis on troubleshooting and refining the process.', 'duration': 371.603, 'highlights': ['Using Mongoose method to find by ID and update data with request body The speaker demonstrates using the Mongoose method to find by ID and update data with the request body, allowing for efficient data manipulation in the web application.', 'Setting options for creating new data and running validators The chapter explains the process of setting options for creating new data and running validators to ensure the validity of the mongoose fields, enhancing the integrity of the web application.', 'Troubleshooting and refining the process of redirecting to the dashboard The speaker troubleshoots and refines the process of redirecting to the dashboard, emphasizing the importance of accurately directing user interactions within the web application.']}, {'end': 8509.231, 'start': 8093.106, 'title': 'Handling delete requests and showing single story', 'summary': 'Covers handling the delete request for stories using the remove method, redirecting to the dashboard upon successful deletion, and adding a route to fetch and display a single story from the database.', 'duration': 416.125, 'highlights': ['Handling the delete request involves using the remove method to delete the story that matches the request params.id, and then redirecting to the dashboard upon successful deletion.', 'Adding a route to fetch and display a single story from the database includes using find by ID and populating with user data, and rendering an error page if the story is not found.', 'The chapter also emphasizes the need to wrap certain parts of the code in try-catch blocks, ensuring async operations and error handling for a smoother user experience.']}, {'end': 8922.031, 'start': 8509.231, 'title': 'Creating user stories template', 'summary': "Discusses creating a user stories template, including formatting the date, displaying the user's information and creating a route to show a specific user's set of stories.", 'duration': 412.8, 'highlights': ["The chapter discusses creating a user stories template, including formatting the date, displaying the user's information and creating a route to show a specific user's set of stories.", 'The user is encouraged to add on to the template and make pull requests to improve it.', "Custom CSS is used to make the user's image smaller by setting a width of 180 pixels.", "The route to show a specific user's set of stories is created using a get request to 'story/user/userID', retrieving only public stories belonging to that user."]}], 'duration': 2497.993, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/SBvmnHTQIPY/pics/SBvmnHTQIPY6424038.jpg', 'highlights': ['Using Mongoose method to find by ID and update data with request body', 'Handling the delete request involves using the remove method to delete the story that matches the request params.id, and then redirecting to the dashboard upon successful deletion.', 'Creating an edit page and functionality to render and update a story, including passing the story values within the edit page form.', "The chapter discusses creating a user stories template, including formatting the date, displaying the user's information and creating a route to show a specific user's set of stories.", 'The chapter also emphasizes the need to wrap certain parts of the code in try-catch blocks, ensuring async operations and error handling for a smoother user experience.']}], 'highlights': ['The application build spans a two and a half hour long video tutorial, covering a CRUD application with Google OAuth using Passport, sessions, and cookies, and storing data in MongoDB.', 'The successful integration of Google authentication, enabling users to log in/register using a Google account and the data being saved in the database.', 'Creating a Google strategy using client ID, client secret, and callback URL for authentication.', 'Creating a new cluster The process involves navigating to MongoDB.com, signing in, and creating a new cluster, which may take three to four minutes to set up.', 'Node.js server is initialized by generating a package.json file using npm init, and installing dependencies such as Express, Mongoose, Connect Mongo, and others. Node.js server initialization, dependency installation', 'Export the connect DB function to be used in the app JS file for connecting to MongoDB. exported connect DB function', 'Using Mongoose method to find by ID and update data with request body', 'Handling the delete request involves using the remove method to delete the story that matches the request params.id, and then redirecting to the dashboard upon successful deletion.', 'The chapter covers the implementation of Google OAuth for login', 'The chapter explains the process of implementing Google authentication in a Node.js application using Passport.js, emphasizing the setup of routes and callback functions, and the extraction and storage of user profile data from Google.']}