title
Spring Boot and Angular Tutorial - Build a Reddit Clone (Coding Project)
description
Learn how to use Spring boot and Angular to build a Reddit clone.
We will be using Java 8, Spring Boot, Spring Security, Spring Data JPA, MySQL on the back-end side and on the front end we will be using Angular 9 and Bootstrap 4.
Also, we will be using Token Based Authentication in the form of JSON Web Tokens (JWT).
💻 Code - Backend: https://github.com/SaiUpadhyayula/spring-reddit-clone
💻 Code - Frontend: https://github.com/SaiUpadhyayula/angular-reddit-clone
🔗 Written tutorial: https://programmingtechie.com/2020/05/14/building-a-reddit-clone-with-spring-boot-and-angular/
✏️ Course from Sai. Check out his YouTube channel: https://www.youtube.com/channel/UCD20RZV_WHQImisCW2QZwDw
⭐️ Course Contents ⭐️
⌨️ (00:00) Intro and Demo
⌨️ (03:50) Project Setup
⌨️ (12:06) User Registration
⌨️ (28:29) User Verification & Async Processing
⌨️ (34:35) User Authentication with JWT
⌨️ (47:48) JWT Validation & Subreddit API
⌨️ (01:00:02) Intro to Mapstruct & Implement Post API
⌨️ (01:16:56) Implement API to Manage Comments
⌨️ (01:30:27) Implement API to Manage Votes
⌨️ (01:41:24) Implement Logout using Refresh Tokens
⌨️ (01:53:59) Getting started with Frontend Application
⌨️ (01:58:28) Document REST API using Swagger & Springfox
⌨️ (02:02:56) Implement User Registration in Angular application
⌨️ (02:14:02) Implement Login in Angular Application
⌨️ (02:21:17) Using Refresh Tokens in Angular Application
⌨️ (02:29:41) Refactoring Home Page Component
⌨️ (02:40:30) Create Subreddits and Posts in Angular Application
⌨️ (02:50:52) Post Comments & Implement User Profile Page
⌨️ (03:04:23) Final part - Implement Voting in Angular App
--
Learn to code for free and get a developer job: https://www.freecodecamp.org
Read hundreds of articles on programming: https://freecodecamp.org/news
detail
{'title': 'Spring Boot and Angular Tutorial - Build a Reddit Clone (Coding Project)', 'heatmap': [{'end': 6729.598, 'start': 6611.656, 'weight': 1}], 'summary': 'This tutorial series covers building a reddit clone using spring boot, angular, and various technologies. it includes implementing features such as user registration, authentication, email verification, database setup, rest api implementation, jwt token management, and angular application development.', 'chapters': [{'end': 659.167, 'segs': [{'end': 27.729, 'src': 'embed', 'start': 0.549, 'weight': 1, 'content': [{'end': 6.09, 'text': "So in this series of tutorials, we'll see how to build a Reddit clone application using Spring Boot and Angular.", 'start': 0.549, 'duration': 5.541}, {'end': 16.453, 'text': 'We will be using Spring Boot, Spring MVC, Spring Security with JWT authentication, Spring Data JPA with MySQL database to build this application.', 'start': 6.711, 'duration': 9.742}, {'end': 20.914, 'text': "So without wasting any time, let's have a look at the application we are going to build.", 'start': 17.393, 'duration': 3.521}, {'end': 22.725, 'text': 'Just a small note.', 'start': 21.744, 'duration': 0.981}, {'end': 27.729, 'text': 'you can find the link to the written tutorial of the series by clicking on the link in the description section,', 'start': 22.725, 'duration': 5.004}], 'summary': 'Build a reddit clone using spring boot and angular, using spring mvc, spring security, jwt authentication, and mysql database.', 'duration': 27.18, 'max_score': 0.549, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c549.jpg'}, {'end': 121.326, 'src': 'embed', 'start': 79.39, 'weight': 0, 'content': [{'end': 86.193, 'text': 'if you want to create a post, you need to be logged in, so first let me register quickly by clicking on sign up button and providing my details,', 'start': 79.39, 'duration': 6.803}, {'end': 90.683, 'text': "And once you click on register button, you're navigated to the login page.", 'start': 87.6, 'duration': 3.083}, {'end': 95.346, 'text': 'You can also see a nice poster notification here on the top right side.', 'start': 91.503, 'duration': 3.843}, {'end': 99.69, 'text': 'So after the user registration, we have to activate the account before we log in.', 'start': 95.607, 'duration': 4.083}, {'end': 105.475, 'text': 'For that, we receive an email which contains the activation link for the account.', 'start': 100.291, 'duration': 5.184}, {'end': 111.72, 'text': "In this application, I'm actually using the fake SMTP server called as MailTrap instead of a real world mail server.", 'start': 105.795, 'duration': 5.925}, {'end': 116.084, 'text': 'So all the mails which we sent from our application are sent to this MailTrap inbox.', 'start': 111.82, 'duration': 4.264}, {'end': 121.326, 'text': 'You can see that we have already received an email with subject as please activate your account.', 'start': 117.224, 'duration': 4.102}], 'summary': "User registration process involves email activation using mailtrap, and receiving an activation email with subject 'please activate your account'.", 'duration': 41.936, 'max_score': 79.39, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c79390.jpg'}, {'end': 264.601, 'src': 'embed', 'start': 235.892, 'weight': 5, 'content': [{'end': 239.635, 'text': 'This is the place where you will generate your project with all the required dependencies.', 'start': 235.892, 'duration': 3.743}, {'end': 244.516, 'text': "For this project, we'll add Spring Web as we are using Spring MEC.", 'start': 240.515, 'duration': 4.001}, {'end': 248.217, 'text': 'We will add a very useful library called as Lombok.', 'start': 245.416, 'duration': 2.801}, {'end': 257.178, 'text': 'This library helps us to generate the usual boilerplate code in Java, like getters, setters, constructors, equals hash code methods, et cetera.', 'start': 248.717, 'duration': 8.461}, {'end': 264.601, 'text': 'And the next thing is we also need Spring Security, Spring Data JPA, MySQL Java driver.', 'start': 258.399, 'duration': 6.202}], 'summary': 'Setting up a project with spring web, lombok, spring security, spring data jpa, and mysql java driver for generating required dependencies and boilerplate code in java.', 'duration': 28.709, 'max_score': 235.892, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c235892.jpg'}, {'end': 543.314, 'src': 'embed', 'start': 515.238, 'weight': 2, 'content': [{'end': 518.399, 'text': 'And next, we have the vote entity, which stores the votes by the user.', 'start': 515.238, 'duration': 3.161}, {'end': 523.64, 'text': 'We distinguish whether a vote is either upvote or downvote using an enum called as vote type.', 'start': 519.159, 'duration': 4.481}, {'end': 526.942, 'text': 'This enum has two possible values, upvote and downvote.', 'start': 524.381, 'duration': 2.561}, {'end': 532.545, 'text': 'And of course, we have references to the post and user entities, and both of them has many to one relationship.', 'start': 527.543, 'duration': 5.002}, {'end': 535.787, 'text': 'That leaves us with the last domain entity comment.', 'start': 533.425, 'duration': 2.362}, {'end': 543.314, 'text': 'It has an ID, text, a reference to the post and user with the many-to-one relationships for both of them and a join.', 'start': 536.528, 'duration': 6.786}], 'summary': 'Entities include vote, comment, post, user with relationships and enums', 'duration': 28.076, 'max_score': 515.238, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c515238.jpg'}, {'end': 625.5, 'src': 'embed', 'start': 600.209, 'weight': 3, 'content': [{'end': 606.456, 'text': 'For that, open the application.properties file inside the source main resources package and add the following properties.', 'start': 600.209, 'duration': 6.247}, {'end': 609.88, 'text': 'The first one is a property for MySQL driver class name.', 'start': 606.856, 'duration': 3.024}, {'end': 614.626, 'text': 'We will use the driver class of the com.mysql.cj.jdbc package.', 'start': 610.16, 'duration': 4.466}, {'end': 616.869, 'text': 'The next property is the data source URL.', 'start': 615.006, 'duration': 1.863}, {'end': 619.892, 'text': "We'll provide the JDBC URL of our database schema.", 'start': 617.289, 'duration': 2.603}, {'end': 622.876, 'text': 'We will see how to create this shortly using MySQL Workbench.', 'start': 620.313, 'duration': 2.563}, {'end': 625.5, 'text': 'Next up, we have our username and password of the database.', 'start': 623.116, 'duration': 2.384}], 'summary': 'Add mysql driver class and data source url to application.properties file.', 'duration': 25.291, 'max_score': 600.209, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c600209.jpg'}], 'start': 0.549, 'title': 'Building a reddit clone with spring boot and angular', 'summary': 'Outlines the process of building a reddit clone using spring boot, spring mvc, spring security, and spring data jpa with mysql database, and demonstrates features such as user registration, account activation via email, posting, voting, and user profiles.', 'chapters': [{'end': 215.34, 'start': 0.549, 'title': 'Building reddit clone with spring boot and angular', 'summary': 'Outlines the process of building a reddit clone using spring boot, spring mvc, spring security, and spring data jpa with mysql database, and demonstrates features such as user registration, account activation via email, posting, voting, and user profiles.', 'duration': 214.791, 'highlights': ['The application is built using Spring Boot, Spring MVC, Spring Security with JWT authentication, and Spring Data JPA with MySQL database.', 'Demonstration of user registration, account activation via email, posting, voting, and user profiles.', 'Use of a fake SMTP server called MailTrap to receive emails from the application.']}, {'end': 659.167, 'start': 216.36, 'title': 'Setting up backend and frontend development', 'summary': 'Covers setting up backend and frontend development for an application, including creating domain entities, enabling lombok, and configuring database properties.', 'duration': 442.807, 'highlights': ['The backend development involves creating domain entities like post, subreddit, user, verification token, vote, and comment, with details on their fields and relationships.', 'The chapter explains the use of Lombok to generate boilerplate code for Java classes, such as getters, setters, constructors, and builder methods, improving code readability and reducing development time.', 'Instructions are provided for configuring database properties in the application.properties file, including the MySQL driver class name, data source URL, username, password, Hibernate dialect, and other properties.']}], 'duration': 658.618, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c549.jpg', 'highlights': ['Demonstration of user registration, account activation via email, posting, voting, and user profiles.', 'The application is built using Spring Boot, Spring MVC, Spring Security with JWT authentication, and Spring Data JPA with MySQL database.', 'The backend development involves creating domain entities like post, subreddit, user, verification token, vote, and comment, with details on their fields and relationships.', 'Instructions for configuring database properties in the application.properties file, including the MySQL driver class name, data source URL, username, password, Hibernate dialect, and other properties.', 'Use of a fake SMTP server called MailTrap to receive emails from the application.', "Explanation of Lombok's use to generate boilerplate code for Java classes, improving code readability and reducing development time."]}, {'end': 1460.661, 'segs': [{'end': 687.302, 'src': 'embed', 'start': 659.427, 'weight': 0, 'content': [{'end': 663.81, 'text': 'Now before we run our application, we have to make sure that the schema already exists in your database.', 'start': 659.427, 'duration': 4.383}, {'end': 667.231, 'text': 'Here we have provided the schema name as Spring Reddit Clone.', 'start': 664.47, 'duration': 2.761}, {'end': 669.593, 'text': "Now let's open MySQL Workbench.", 'start': 667.812, 'duration': 1.781}, {'end': 676.216, 'text': 'And once you are connected to the local database, in the bottom left side corner of the screen, you can find the schema section.', 'start': 670.133, 'duration': 6.083}, {'end': 678.918, 'text': 'Just right click over there and select create schema.', 'start': 676.456, 'duration': 2.462}, {'end': 682.78, 'text': "As I have already created the schema, I won't be creating it again.", 'start': 679.798, 'duration': 2.982}, {'end': 687.302, 'text': 'Just make sure to add the schema name here and click on finish to create the schema.', 'start': 683.46, 'duration': 3.842}], 'summary': "Ensure schema 'spring reddit clone' exists in local database using mysql workbench.", 'duration': 27.875, 'max_score': 659.427, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c659427.jpg'}, {'end': 766.438, 'src': 'embed', 'start': 738.773, 'weight': 3, 'content': [{'end': 743.255, 'text': 'This class, as the name suggests, holds the complete security configuration for our backend.', 'start': 738.773, 'duration': 4.482}, {'end': 749.277, 'text': 'The first thing we are going to do is add the atEnableWebSecurity annotation to this class.', 'start': 744.195, 'duration': 5.082}, {'end': 757.96, 'text': 'This is the main annotation which enables the web security module in our project, which we have added to this Spring Security Starter dependency.', 'start': 749.917, 'duration': 8.043}, {'end': 763.176, 'text': "After that, let's extend our class using Web Security Configure Adapter.", 'start': 759.153, 'duration': 4.023}, {'end': 766.438, 'text': 'This is the base class for our security config class.', 'start': 763.797, 'duration': 2.641}], 'summary': 'Adding atenablewebsecurity annotation enables web security module in our backend.', 'duration': 27.665, 'max_score': 738.773, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c738773.jpg'}, {'end': 880.05, 'src': 'embed', 'start': 856.428, 'weight': 1, 'content': [{'end': 864.435, 'text': "let's also create a method called as sign up, and to this method we will be giving an input of type register request.", 'start': 856.428, 'duration': 8.007}, {'end': 871.682, 'text': "through this class we'll be transferring the user details like username, password and email as part of the request body.", 'start': 864.435, 'duration': 7.247}, {'end': 874.244, 'text': 'we call these kinds of class as a dto.', 'start': 871.682, 'duration': 2.562}, {'end': 876.607, 'text': 'that means a data transfer object.', 'start': 874.244, 'duration': 2.363}, {'end': 880.05, 'text': "i'm going to create this class and put it inside a package called as dto,", 'start': 876.607, 'duration': 3.443}], 'summary': "Create a 'sign up' method to transfer user details like username, password, and email as part of the request body using a dto class.", 'duration': 23.622, 'max_score': 856.428, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c856428.jpg'}, {'end': 1144.613, 'src': 'embed', 'start': 1118.102, 'weight': 2, 'content': [{'end': 1122.204, 'text': "Now let's enhance our registration process by sending out account activation emails.", 'start': 1118.102, 'duration': 4.102}, {'end': 1123.325, 'text': 'For this.', 'start': 1122.925, 'duration': 0.4}, {'end': 1130.888, 'text': 'the idea is to generate a verification token right after we save the user to the database and send the token as part of the verification email.', 'start': 1123.325, 'duration': 7.563}, {'end': 1138.192, 'text': 'Once the user is verified, then we enable the user to log into our application by setting the enable field as true.', 'start': 1131.869, 'duration': 6.323}, {'end': 1144.613, 'text': "Let's create a method called as generate verification token, which takes user object as input.", 'start': 1139.389, 'duration': 5.224}], 'summary': 'Enhance registration process by sending account activation emails with verification token.', 'duration': 26.511, 'max_score': 1118.102, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c1118102.jpg'}], 'start': 659.427, 'title': 'Database schema setup and registration enhancement', 'summary': 'Covers setting up the database schema, creating security configurations, and implementing user registration logic. it also outlines enhancing the registration process with activation emails, including token generation and email sending using java mail sender.', 'chapters': [{'end': 1117.062, 'start': 659.427, 'title': 'Setting up database schema and security configuration', 'summary': 'Covers setting up the database schema, creating security configurations for the backend, and implementing user registration logic, including the use of bcrypt hashing algorithm for password encoding.', 'duration': 457.635, 'highlights': ['The chapter provides a detailed guide on creating a schema in MySQL Workbench and configuring the Spring Reddit Clone application, including the initial setup and starting the Spring context and Tomcat server at port 8080.', 'It explains the process of creating a security configuration class for the backend, using annotations such as @EnableWebSecurity and WebSecurityConfigurerAdapter, and customizing security configurations to disable CSRF protection and define endpoint URL patterns.', 'The transcript delves into the implementation of user registration logic, including the creation of DTOs for transferring user details, the AuthService class for user registration business logic, and the use of bcrypt hashing algorithm to encode passwords before saving them to the database.', 'Additionally, it emphasizes the importance of encoding passwords using bcrypt hashing algorithm to enhance security and provides insights on refactoring code to adhere to best practices, such as using constructor injection over field injection and adding the @Transactional annotation for interacting with the relational database.']}, {'end': 1460.661, 'start': 1118.102, 'title': 'Enhancing registration process with activation emails', 'summary': 'Outlines the process of enhancing the registration process by implementing account activation emails, including generating and saving verification tokens, creating html email templates, and sending out email messages using java mail sender.', 'duration': 342.559, 'highlights': ['The chapter outlines the process of enhancing the registration process by implementing account activation emails', 'including generating and saving verification tokens', 'creating HTML email templates', 'sending out email messages using Java Mail Sender']}], 'duration': 801.234, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c659427.jpg', 'highlights': ['The chapter provides a detailed guide on creating a schema in MySQL Workbench and configuring the Spring Reddit Clone application, including the initial setup and starting the Spring context and Tomcat server at port 8080.', 'The transcript delves into the implementation of user registration logic, including the creation of DTOs for transferring user details, the AuthService class for user registration business logic, and the use of bcrypt hashing algorithm to encode passwords before saving them to the database.', 'The chapter outlines the process of enhancing the registration process by implementing account activation emails', 'It explains the process of creating a security configuration class for the backend, using annotations such as @EnableWebSecurity and WebSecurityConfigurerAdapter, and customizing security configurations to disable CSRF protection and define endpoint URL patterns.']}, {'end': 3601.356, 'segs': [{'end': 2036.875, 'src': 'embed', 'start': 1993.678, 'weight': 0, 'content': [{'end': 1995.999, 'text': 'This should already enable the asynchronous processing.', 'start': 1993.678, 'duration': 2.321}, {'end': 1999.959, 'text': "And now let's go to the piece of code which is responsible to send the email.", 'start': 1996.239, 'duration': 3.72}, {'end': 2004.48, 'text': 'That would be the send email method inside the mail service class.', 'start': 2000.599, 'duration': 3.881}, {'end': 2007.681, 'text': 'And on top of this method, type at async.', 'start': 2005.04, 'duration': 2.641}, {'end': 2009.101, 'text': 'So that is it.', 'start': 2008.461, 'duration': 0.64}, {'end': 2011.202, 'text': 'Now our code should run asynchronously.', 'start': 2009.401, 'duration': 1.801}, {'end': 2016.783, 'text': 'And the response time for registered users API call should be much faster.', 'start': 2011.642, 'duration': 5.141}, {'end': 2019.33, 'text': "So let's restart our server and test it again.", 'start': 2017.483, 'duration': 1.847}, {'end': 2036.875, 'text': 'So as you can see, the API call is taking very less time and looks far better than the previous response time.', 'start': 2031.371, 'duration': 5.504}], 'summary': 'Enabling async processing reduced api response time significantly.', 'duration': 43.197, 'max_score': 1993.678, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c1993678.jpg'}, {'end': 2129.359, 'src': 'embed', 'start': 2098.23, 'weight': 2, 'content': [{'end': 2102.591, 'text': 'And if they are matching, it creates a JSON web token and sends this information back to the client.', 'start': 2098.23, 'duration': 4.361}, {'end': 2109.513, 'text': "client uses this token to authenticate itself for all the consecutive requests it's going to make to the server.", 'start': 2103.647, 'duration': 5.866}, {'end': 2112.115, 'text': 'so once the server receives a request with this token,', 'start': 2109.513, 'duration': 2.602}, {'end': 2119.122, 'text': "it first validates this token whether it's the same token which is generated by the server or not and after the successful validation,", 'start': 2112.115, 'duration': 7.007}, {'end': 2121.364, 'text': 'it responds to the client with the required data.', 'start': 2119.122, 'duration': 2.242}, {'end': 2129.359, 'text': 'Before we dive in and start coding, I would like to take a moment and explain you how the authentication mechanism works in Spring Security.', 'start': 2122.557, 'duration': 6.802}], 'summary': 'Server generates json web token for client authentication in spring security.', 'duration': 31.129, 'max_score': 2098.23, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c2098230.jpg'}, {'end': 2575.776, 'src': 'embed', 'start': 2549.97, 'weight': 3, 'content': [{'end': 2555.452, 'text': 'So before we create the functionality to create JSON Web Tokens, we have to add some Maven dependencies.', 'start': 2549.97, 'duration': 5.482}, {'end': 2567.837, 'text': 'So open up the pom.xml file and make sure you add these three JWT dependencies, the jjwt-api, jjwt-impl, and jjwt-jackson.', 'start': 2556.552, 'duration': 11.285}, {'end': 2572.273, 'text': "So now let's create a class with the name JWT provider.", 'start': 2569.471, 'duration': 2.802}, {'end': 2575.776, 'text': 'I will create this class in a separate package called a security.', 'start': 2573.074, 'duration': 2.702}], 'summary': 'Add jwt dependencies to pom.xml for creating jwt functionality.', 'duration': 25.806, 'max_score': 2549.97, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c2549970.jpg'}, {'end': 2908.453, 'src': 'embed', 'start': 2879.253, 'weight': 4, 'content': [{'end': 2882.115, 'text': "In this video, we're going to dive deep onto the fifth point.", 'start': 2879.253, 'duration': 2.862}, {'end': 2885.549, 'text': 'where we validate the JSON web token on the server.', 'start': 2882.947, 'duration': 2.602}, {'end': 2888.65, 'text': 'So this is how the actual process looks like.', 'start': 2886.429, 'duration': 2.221}, {'end': 2891.332, 'text': 'The client makes a request to the server.', 'start': 2889.251, 'duration': 2.081}, {'end': 2897.156, 'text': 'The request is intercepted by a custom filter called as JWT authentication filter.', 'start': 2891.972, 'duration': 5.184}, {'end': 2900.898, 'text': 'This filter will retrieve the access token and validates it.', 'start': 2897.896, 'duration': 3.002}, {'end': 2905.421, 'text': 'If the validation is successful, the request will be forwarded to the corresponding controller.', 'start': 2901.418, 'duration': 4.003}, {'end': 2908.453, 'text': "Now let's go ahead and implement this functionality.", 'start': 2906.311, 'duration': 2.142}], 'summary': 'Validate json web token using jwt authentication filter.', 'duration': 29.2, 'max_score': 2879.253, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c2879253.jpg'}, {'end': 3209.864, 'src': 'embed', 'start': 3179.508, 'weight': 5, 'content': [{'end': 3184.27, 'text': 'If our token is valid, Spring is going to find the user details inside the security context.', 'start': 3179.508, 'duration': 4.762}, {'end': 3186.05, 'text': 'and it will fulfill our request.', 'start': 3184.83, 'duration': 1.22}, {'end': 3190.252, 'text': 'If not, it will throw an exception, which we will see at the end of the video.', 'start': 3186.671, 'duration': 3.581}, {'end': 3192.492, 'text': 'OK, so we implemented the validation part.', 'start': 3190.452, 'duration': 2.04}, {'end': 3200.475, 'text': "Now to test this, we don't have any secured APIs, so let's go ahead and create one API to create and read subreddits.", 'start': 3192.812, 'duration': 7.663}, {'end': 3204.118, 'text': "Let's create a class called as subreddit controller.", 'start': 3201.255, 'duration': 2.863}, {'end': 3209.864, 'text': 'And the first thing we have to do when we create a controller is to annotate the class as rest controller.', 'start': 3204.779, 'duration': 5.085}], 'summary': 'Valid token in spring finds user details in security context to fulfill request. implemented validation part and created subreddit controller as rest controller.', 'duration': 30.356, 'max_score': 3179.508, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c3179508.jpg'}], 'start': 1461.181, 'title': 'Implementing user authentication and email sending', 'summary': 'Covers configuring smtp server for testing code sending emails, implementing email sending logic in spring application, and implementing user verification for faster api response time and improved user experience. it also provides an overview of the authentication flow, implements authentication logic, and discusses jwt token validation process and subreddit apis.', 'chapters': [{'end': 1700.396, 'start': 1461.181, 'title': 'Configuring smtp server and sending emails', 'summary': 'Covers configuring smtp server using mailtrap for testing code sending emails, and implementing email sending logic in spring application, resulting in successful user registration and email delivery.', 'duration': 239.215, 'highlights': ['Configuring SMTP server using MailTrap for testing code sending emails', 'Implementing email sending logic in Spring application resulting in successful user registration and email delivery', 'Creating custom exception for passing unique exception messages', 'Signing up for MailTrap service to obtain SMTP server details', 'Injecting mail service class and calling send method to trigger email sending']}, {'end': 2073.761, 'start': 1701.016, 'title': 'Implementing user verification', 'summary': 'Explains the process of implementing user verification, including creating endpoints, querying repositories, enabling asynchronous processing, and testing the verification process, resulting in a faster api response time and improved user experience.', 'duration': 372.745, 'highlights': ['Implementing asynchronous processing by enabling @Async in the application class and the send email method, resulting in a much faster API response time.', 'Creating an endpoint for account verification and implementing methods to verify and enable user accounts, including querying repositories and handling invalid tokens.', 'Discussing the need for asynchronous processing due to the delay in sending verification emails and recommending the use of message queues for larger-scale applications.']}, {'end': 2408.974, 'start': 2079.406, 'title': 'Authentication flow overview', 'summary': 'Provides a high-level overview of the authentication flow, including client-server interaction, token generation, and spring security implementation, aiming to create a json web token for user authentication.', 'duration': 329.568, 'highlights': ["The server validates the client's credentials and creates a JSON web token for authentication.", 'Overview of the main components used to create the authentication mechanism, including the auth service, authentication manager, and UserDetailsService.', 'Explanation of the method to load user details from the database using the UserDetailsService interface and the UserDetailsServiceImpl class.', 'Creation of a new endpoint for login functionality in the AuthController class, using a login request object with username and password fields.', 'Configuration of the authentication manager builder to create the authentication manager for user authentication.']}, {'end': 2710.465, 'start': 2408.974, 'title': 'Implementing authentication and creating jwts', 'summary': 'Covers the implementation of authentication logic in authservice by using authentication manager to perform login and creating json web tokens by adding required maven dependencies and using jwt provider class to generate tokens using asymmetric encryption with a keystore.', 'duration': 301.491, 'highlights': ['Implementing authentication logic in AuthService', 'Creating JSON Web Tokens with required Maven dependencies', 'Generating tokens using JWT provider class with asymmetric encryption and keystore']}, {'end': 3066.066, 'start': 2710.465, 'title': 'Jwt token validation process', 'summary': 'Discusses implementing jwt token validation process, including intercepting the request, retrieving and validating the token, and creating a method for validating the json web token.', 'duration': 355.601, 'highlights': ['The client makes a request to the server, intercepted by a JWT authentication filter, retrieving and validating the access token, and forwarding the request to the controller.', 'Implementing JWT authentication filter to intercept the request, fetch the token from the request headers, and validate the JSON Web Token.', 'Creating a method for validating the JSON Web Token by using the public key and catching checked exceptions and re-throwing them as a runtime exception.']}, {'end': 3601.356, 'start': 3066.066, 'title': 'Jwt token validation and subreddit apis', 'summary': 'Details the process of validating jwt tokens for user authentication and implementing subreddit creation and retrieval apis using spring security and spring boot, with a successful implementation demonstrated through the creation and retrieval of subreddit data.', 'duration': 535.29, 'highlights': ['The chapter explains the process of validating JWT tokens and implementing Subreddit creation and retrieval APIs using Spring Security and Spring Boot, with successful demonstration through subreddit creation and retrieval. (relevance: 5)', 'The process of validating JWT tokens is detailed, including the use of the validateToken method and the injection of the JWT provider class inside the JWT authentication filter class. (relevance: 4)', 'The implementation of Subreddit creation and retrieval APIs is described, with the creation of a Subreddit controller class and the use of DTOs to handle subreddit information. (relevance: 3)', 'The responsibility of controllers to receive requests from clients and delegate them to the service layer is emphasized, with the creation of a subreddit service class and the use of mapping methods to handle DTO to entity mappings. (relevance: 2)', 'The configuration of Spring Security to recognize the JWT authentication filter class is highlighted, ensuring the validation logic is appropriately integrated into the system. (relevance: 1)']}], 'duration': 2140.175, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c1461181.jpg', 'highlights': ['Implementing email sending logic in Spring application resulting in successful user registration and email delivery', 'Implementing asynchronous processing by enabling @Async in the application class and the send email method, resulting in a much faster API response time', "The server validates the client's credentials and creates a JSON web token for authentication", 'Creating JSON Web Tokens with required Maven dependencies', 'Implementing JWT authentication filter to intercept the request, fetch the token from the request headers, and validate the JSON Web Token', 'The chapter explains the process of validating JWT tokens and implementing Subreddit creation and retrieval APIs using Spring Security and Spring Boot, with successful demonstration through subreddit creation and retrieval']}, {'end': 4854.835, 'segs': [{'end': 3637.675, 'src': 'embed', 'start': 3608.14, 'weight': 0, 'content': [{'end': 3609.741, 'text': "So let's have a look at what is Mapstruct.", 'start': 3608.14, 'duration': 1.601}, {'end': 3617.685, 'text': 'If you go to the mapstruct.org website, you can see in the home page it is written that is a Java library which generates the mapping code,', 'start': 3609.921, 'duration': 7.764}, {'end': 3619.126, 'text': 'the mapping logic in our application.', 'start': 3617.685, 'duration': 1.441}, {'end': 3624.168, 'text': 'That means if you have two objects and you want to map the data between these two objects,', 'start': 3619.186, 'duration': 4.982}, {'end': 3629.231, 'text': 'we can use Mapstruct to generate the mapping code by just using some annotations.', 'start': 3624.168, 'duration': 5.063}, {'end': 3632.832, 'text': 'If you scroll down, you can see the section Mapstruct in two minutes.', 'start': 3629.931, 'duration': 2.901}, {'end': 3637.675, 'text': 'Here we have an example where we have a car object and a car DTO object.', 'start': 3633.113, 'duration': 4.562}], 'summary': 'Mapstruct is a java library for generating mapping code between objects using annotations.', 'duration': 29.535, 'max_score': 3608.14, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c3608140.jpg'}, {'end': 3700.772, 'src': 'embed', 'start': 3663.104, 'weight': 1, 'content': [{'end': 3671.753, 'text': 'So we can just ask Mapstruct to generate this kind of code automatically by just writing the method definition which takes in the source object as input.', 'start': 3663.104, 'duration': 8.649}, {'end': 3675.476, 'text': 'And we provide the target object type as the written type of the method.', 'start': 3671.953, 'duration': 3.523}, {'end': 3677.098, 'text': "And that's all we have to do.", 'start': 3676.117, 'duration': 0.981}, {'end': 3680.281, 'text': 'Mapstruct will then generate all the required mappings at compile time.', 'start': 3677.138, 'duration': 3.143}, {'end': 3685.925, 'text': 'And so we will actually see how it generates the code and what kind of code it generates very soon.', 'start': 3681.062, 'duration': 4.863}, {'end': 3688.086, 'text': 'But I hope you understand what is Mapstruct.', 'start': 3686.365, 'duration': 1.721}, {'end': 3691.107, 'text': "So let's go ahead and install this library in our project.", 'start': 3688.326, 'duration': 2.781}, {'end': 3694.069, 'text': "OK, so let's go to the documentation section in the home page.", 'start': 3691.428, 'duration': 2.641}, {'end': 3700.772, 'text': 'And under the Apache Maven section, you can see the library details in the pom.xml file.', 'start': 3694.369, 'duration': 6.403}], 'summary': 'Mapstruct automates code generation for mappings at compile time.', 'duration': 37.668, 'max_score': 3663.104, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c3663104.jpg'}, {'end': 3806.637, 'src': 'embed', 'start': 3780.447, 'weight': 4, 'content': [{'end': 3785.408, 'text': 'so mapstrak will identify and generate the mapping logic automatically for these fields.', 'start': 3780.447, 'duration': 4.961}, {'end': 3793.59, 'text': 'and for the remaining field, the number of posts this is just an integer field we have to create mapping from list of post to integer.', 'start': 3785.408, 'duration': 8.182}, {'end': 3796.591, 'text': 'that means we have to just return the size of this list.', 'start': 3793.59, 'duration': 3.001}, {'end': 3806.637, 'text': 'we can do that by creating a new method called as map post so which takes in a list of posts as input and inside this method we will just return number of posts,', 'start': 3796.591, 'duration': 10.046}], 'summary': 'Mapstrak automates mapping logic for fields. create method to map posts to integer.', 'duration': 26.19, 'max_score': 3780.447, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c3780447.jpg'}, {'end': 4133.917, 'src': 'embed', 'start': 4108.863, 'weight': 3, 'content': [{'end': 4116.906, 'text': "So let's go into that interface and you can see the first annotation we have is a mapper annotation from MapStruct on top of our interface.", 'start': 4108.863, 'duration': 8.043}, {'end': 4122.207, 'text': 'And the first mapping method you see is to create a post from the post request object.', 'start': 4117.305, 'duration': 4.902}, {'end': 4127.868, 'text': 'So to create a post, we not only need the post details, but also the subreddit and the user details.', 'start': 4123.243, 'duration': 4.625}, {'end': 4133.917, 'text': "We'll be passing these details through the post service class to this method.", 'start': 4128.55, 'duration': 5.367}], 'summary': 'Using mapstruct to map post request object for creating a post with subreddit and user details.', 'duration': 25.054, 'max_score': 4108.863, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4108863.jpg'}, {'end': 4183.575, 'src': 'embed', 'start': 4153.497, 'weight': 9, 'content': [{'end': 4156.078, 'text': 'Next one is for the fields user and subreddit.', 'start': 4153.497, 'duration': 2.581}, {'end': 4158.719, 'text': 'So here the fields are same.', 'start': 4157.178, 'duration': 1.541}, {'end': 4161.461, 'text': 'between for these two objects.', 'start': 4159.319, 'duration': 2.142}, {'end': 4163.582, 'text': 'that means post request and post.', 'start': 4161.461, 'duration': 2.121}, {'end': 4165.582, 'text': 'so we can go ahead and remove these mappings.', 'start': 4163.582, 'duration': 2}, {'end': 4171.667, 'text': "because of the field name matches in the source and target objects, then we don't need to explicitly mention the mappings.", 'start': 4165.582, 'duration': 6.085}, {'end': 4174.229, 'text': 'that will be taken care by Mapstruct.', 'start': 4171.667, 'duration': 2.562}, {'end': 4176.67, 'text': 'the last mapping is for the field description.', 'start': 4174.229, 'duration': 2.441}, {'end': 4180.633, 'text': 'here we have to mention that the source is inside the post request object.', 'start': 4176.67, 'duration': 3.963}, {'end': 4183.575, 'text': "that's why we put the value as post request dot description.", 'start': 4180.633, 'duration': 2.942}], 'summary': 'Removing mappings for matching fields, specifying source for description.', 'duration': 30.078, 'max_score': 4153.497, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4153497.jpg'}, {'end': 4510.37, 'src': 'embed', 'start': 4483.059, 'weight': 7, 'content': [{'end': 4485.821, 'text': "Before testing this, let's go to the PostController class.", 'start': 4483.059, 'duration': 2.762}, {'end': 4488.843, 'text': 'And you can see that for every method inside this controller.', 'start': 4486.482, 'duration': 2.361}, {'end': 4494.586, 'text': 'I am wrapping the response we are getting from the post service class with the response entity object.', 'start': 4489.844, 'duration': 4.742}, {'end': 4497.546, 'text': 'So this is a class from Spring MVC.', 'start': 4495.446, 'duration': 2.1}, {'end': 4501.908, 'text': 'So through this object, we can return the different status codes for different scenarios.', 'start': 4498.087, 'duration': 3.821}, {'end': 4510.37, 'text': "That means, for instance, if we want to create a post, usually if you're creating a resource in REST world, we should return HTTP status as 201,", 'start': 4502.648, 'duration': 7.722}], 'summary': 'In the postcontroller class, responses from the post service class are wrapped with the response entity object, allowing different status codes to be returned for different scenarios, such as 201 for creating a post in the rest world.', 'duration': 27.311, 'max_score': 4483.059, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4483059.jpg'}, {'end': 4651.158, 'src': 'embed', 'start': 4625.792, 'weight': 5, 'content': [{'end': 4630.473, 'text': "Before starting the code, let's go ahead and see what are the endpoints we are going to create in this video.", 'start': 4625.792, 'duration': 4.681}, {'end': 4633.133, 'text': 'So I opened the link for the written tutorial here.', 'start': 4630.793, 'duration': 2.34}, {'end': 4640.715, 'text': 'And if you go to the section Implement API for Managing Comments, you can see a table where we have our required mappings,', 'start': 4633.734, 'duration': 6.981}, {'end': 4645.696, 'text': 'along with the HTTP method and the name of the method we are going to implement inside our controller.', 'start': 4640.715, 'duration': 4.981}, {'end': 4651.158, 'text': 'So the first one is an endpoint to create comments in our application.', 'start': 4646.676, 'duration': 4.482}], 'summary': 'Identifying endpoints and mappings for creating comments.', 'duration': 25.366, 'max_score': 4625.792, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4625792.jpg'}], 'start': 3608.14, 'title': 'Using mapstruct in java', 'summary': 'Introduces mapstruct, a java library for automated mapping, demonstrating installation and usage in a java project. it discusses automated mapping logic generation, mapping post requests to entities, and implementing api for managing posts and comments using spring mvc classes.', 'chapters': [{'end': 3780.447, 'start': 3608.14, 'title': 'Introduction to mapstruct library', 'summary': 'Introduces mapstruct, a java library that generates mapping code for transferring data between objects, reducing manual effort and potential errors in complex mapping, and demonstrates the installation and usage of mapstruct in a java project.', 'duration': 172.307, 'highlights': ['Mapstruct is a Java library that generates mapping code for transferring data between objects, reducing manual effort and potential errors in complex mapping.', 'Mapstruct can automatically generate the required mapping code at compile time by just writing the method definition, simplifying the mapping process.', 'The chapter demonstrates the installation of Mapstruct in a Java project, including adding dependencies and plugins to the pom.xml file.']}, {'end': 4088.035, 'start': 3780.447, 'title': 'Automated mapping logic generation', 'summary': 'Discusses the automatic generation of mapping logic for fields using mapstrak, creating mapping from list of posts to an integer by returning the size of the list, and using methods and annotations to facilitate the mapping process.', 'duration': 307.588, 'highlights': ['Mapstrak is used to automatically generate mapping logic for fields, streamlining the mapping process.', 'Creation of mapping from list of posts to an integer involves returning the size of the list, simplifying the mapping.', 'Methods and annotations are utilized to facilitate the mapping process, enhancing the efficiency of the mapping operations.']}, {'end': 4268.475, 'start': 4088.735, 'title': 'Mapping post request to post entity', 'summary': 'Explains the process of mapping post request to post entity using mapstruct, including creating mappings for fields such as created date, subreddit, user, and description and utilizing expressions like instant dot now.', 'duration': 179.74, 'highlights': ['The chapter explains the process of mapping post request to post entity using MapStruct, including creating mappings for fields such as created date, subreddit, user, and description and utilizing expressions like instant dot now.', 'The first mapping method creates a post from the post request object, with mappings for fields like created date, subreddit, user, and description, using expressions like instant dot now for created date.', 'Mappings for fields user and subreddit are automatically handled by MapStruct due to same field names in source and target objects, eliminating the need for explicit mention of mappings.', 'The chapter also covers the process of mapping from post object to the post response, with mappings for fields like id, post name, description, url, subreddit, and name, and the use of annotations to map fields from related objects, such as subreddit.name to post response subreddit name.']}, {'end': 4854.835, 'start': 4269.535, 'title': 'Implementing api for managing posts and comments', 'summary': 'Covers the implementation of methods for managing posts and comments, including the use of spring mvc classes, http status codes, and the creation of endpoints for creating and retrieving comments and posts.', 'duration': 585.3, 'highlights': ['The chapter covers the implementation of methods for managing posts and comments', 'The use of Spring MVC classes and HTTP status codes to control response handling', 'Creation of endpoints for creating and retrieving comments and posts']}], 'duration': 1246.695, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c3608140.jpg', 'highlights': ['Mapstruct is a Java library that generates mapping code for transferring data between objects, reducing manual effort and potential errors in complex mapping.', 'Mapstruct can automatically generate the required mapping code at compile time by just writing the method definition, simplifying the mapping process.', 'The chapter demonstrates the installation of Mapstruct in a Java project, including adding dependencies and plugins to the pom.xml file.', 'The chapter explains the process of mapping post request to post entity using MapStruct, including creating mappings for fields such as created date, subreddit, user, and description and utilizing expressions like instant dot now.', 'Creation of mapping from list of posts to an integer involves returning the size of the list, simplifying the mapping.', 'The chapter covers the implementation of methods for managing posts and comments', 'Methods and annotations are utilized to facilitate the mapping process, enhancing the efficiency of the mapping operations.', 'The use of Spring MVC classes and HTTP status codes to control response handling', 'Creation of endpoints for creating and retrieving comments and posts', 'Mappings for fields user and subreddit are automatically handled by MapStruct due to same field names in source and target objects, eliminating the need for explicit mention of mappings.']}, {'end': 5973.889, 'segs': [{'end': 4901.272, 'src': 'embed', 'start': 4855.316, 'weight': 0, 'content': [{'end': 4861.102, 'text': 'So this is the shortcut I use every time to navigate between the files in the history.', 'start': 4855.316, 'duration': 5.786}, {'end': 4868.409, 'text': "Okay, now back to our comment service class and let's inject the post repository and user repository into our comment service.", 'start': 4861.422, 'duration': 6.987}, {'end': 4877.078, 'text': "And inside the save method, I'm going to query the post repository by using the find by ID method and by passing in the post ID.", 'start': 4869.05, 'duration': 8.028}, {'end': 4881.921, 'text': 'So, as this returns an optional, if the post is not available,', 'start': 4878.579, 'duration': 3.342}, {'end': 4889.685, 'text': "we can call the orals throw block and inside that we'll pass in a supplier to throw a post not found exception.", 'start': 4881.921, 'duration': 7.764}, {'end': 4892.787, 'text': 'Next thing is we have to determine the author of the comment.', 'start': 4890.266, 'duration': 2.521}, {'end': 4901.272, 'text': 'So for that, instead of using the username, we can check who is the currently logged in user and use that object to create our comment object.', 'start': 4893.447, 'duration': 7.825}], 'summary': 'Navigating files, injecting repositories, querying by id, handling post not found, determining comment author.', 'duration': 45.956, 'max_score': 4855.316, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4855316.jpg'}, {'end': 4954.171, 'src': 'embed', 'start': 4929.082, 'weight': 3, 'content': [{'end': 4934.504, 'text': "Okay so I've already prepared all the method definitions and mappings inside this comment mapper interface.", 'start': 4929.082, 'duration': 5.422}, {'end': 4942.666, 'text': 'The first mapping we have is for the map method which takes in the comments DTO and the post and the user and returns the comment.', 'start': 4935.084, 'duration': 7.582}, {'end': 4946.907, 'text': 'So the first mapping is for the field ID.', 'start': 4943.466, 'duration': 3.441}, {'end': 4954.171, 'text': 'so we are ignoring this ID field because the id will be auto generated whenever we save the object to the database.', 'start': 4946.907, 'duration': 7.264}], 'summary': 'Method definitions and mappings prepared for comment mapper interface. first mapping for map method with dto, post, and user returns comment. ignoring id field as it will be auto-generated.', 'duration': 25.089, 'max_score': 4929.082, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4929082.jpg'}, {'end': 5179.096, 'src': 'embed', 'start': 5152.901, 'weight': 4, 'content': [{'end': 5159.166, 'text': 'once we get our email message, we can send the email by using the mail service dot send mail method,', 'start': 5152.901, 'duration': 6.265}, {'end': 5165.951, 'text': 'and inside this method we are passing the notification email object where we pass the subject line of our email,', 'start': 5159.166, 'duration': 6.785}, {'end': 5171.793, 'text': 'followed by the email address of the post author and followed by the email message.', 'start': 5165.951, 'duration': 5.842}, {'end': 5179.096, 'text': 'So once we execute this one, we are already sending the email message asynchronously to the user.', 'start': 5172.474, 'duration': 6.622}], 'summary': 'Using mail service, we can send email asynchronously to the user.', 'duration': 26.195, 'max_score': 5152.901, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c5152901.jpg'}, {'end': 5435.75, 'src': 'embed', 'start': 5367.119, 'weight': 5, 'content': [{'end': 5372.202, 'text': 'We are also returning back the response entity to the client, similarly to our previous method,', 'start': 5367.119, 'duration': 5.083}, {'end': 5377.824, 'text': 'by adding the return value from the service to the body and the HTTP status as OK.', 'start': 5372.202, 'duration': 5.622}, {'end': 5385.328, 'text': 'All right, we have completed the implementation of the API to create and read comments.', 'start': 5381.365, 'duration': 3.963}, {'end': 5391.052, 'text': "Let's test our implementation now by first starting up the server and opening the Postman client.", 'start': 5385.828, 'duration': 5.224}, {'end': 5435.75, 'text': "So let's open our controller class, which is named as vote controller.", 'start': 5431.709, 'duration': 4.041}], 'summary': 'Implemented api for creating and reading comments, testing with postman and vote controller.', 'duration': 68.631, 'max_score': 5367.119, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c5367119.jpg'}, {'end': 5742.468, 'src': 'embed', 'start': 5710.529, 'weight': 7, 'content': [{'end': 5711.63, 'text': 'I will remove it now.', 'start': 5710.529, 'duration': 1.101}, {'end': 5718.358, 'text': 'So these new fields are number of votes for a post, the number of comments and the last field is duration.', 'start': 5712.331, 'duration': 6.027}, {'end': 5723.061, 'text': 'So this field shows us the relative time duration of the post creation time.', 'start': 5719.099, 'duration': 3.962}, {'end': 5727.262, 'text': 'So we are calculating this using a library called as time ago.', 'start': 5723.341, 'duration': 3.921}, {'end': 5729.923, 'text': 'So let me open the GitHub page of this library.', 'start': 5727.742, 'duration': 2.181}, {'end': 5731.884, 'text': "It's just a Kotlin library.", 'start': 5730.123, 'duration': 1.761}, {'end': 5735.125, 'text': 'So we can also use it in our Java project.', 'start': 5732.484, 'duration': 2.641}, {'end': 5742.468, 'text': 'Here in the example, you can see that the time is displaying as four days ago, a minute ago, and also just now.', 'start': 5735.285, 'duration': 7.183}], 'summary': 'New fields added: votes, comments, duration. using time ago library for relative time.', 'duration': 31.939, 'max_score': 5710.529, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c5710529.jpg'}], 'start': 4855.316, 'title': 'Managing file history and rest api implementation', 'summary': 'Discusses navigating between files in the history, injecting post and user repository into the comment service class, implementing a comment service with a comment mapper interface, and the rest api for creating and reading comments and submitting votes for posts.', 'chapters': [{'end': 4901.272, 'start': 4855.316, 'title': 'Navigating files in history', 'summary': 'Discusses navigating between files in the history using a shortcut, injecting post and user repository into the comment service class, querying post repository to find a post by id, and determining the author of the comment based on the currently logged in user.', 'duration': 45.956, 'highlights': ['Injecting post and user repository into our comment service class allows for efficient data retrieval and manipulation.', 'Querying the post repository by using the find by ID method improves efficiency in locating specific posts.', 'Determining the author of the comment based on the currently logged in user enhances user interaction and personalization.']}, {'end': 5179.096, 'start': 4902.072, 'title': 'Implementing comment service', 'summary': 'Covers the implementation of a comment service, including creating a comment mapper interface with method definitions and mappings, injecting the mapper into the service class, saving comments to the database, and sending notification emails to post authors.', 'duration': 277.024, 'highlights': ['Created a comment mapper interface with method definitions and mappings, including mappings for the ID, text, and created date fields, with the use of Java expressions for evaluating the created date field, ensuring the auto generation of ID, and mapping the text and created date fields from comments DTO to comment objects.', 'Injected the comment mapper into the service class, utilized it to map comments DTO to comment objects, and made a method call to AuthService to get the currently logged in user for the save method.', 'Implemented the functionality to send a notification email to the author of the post by reusing the previously built mail sending functionality, asynchronously sending the email message to the user after building the email body and using the mail service to send the email.']}, {'end': 5973.889, 'start': 5180.137, 'title': 'Implementation of rest api for comments and votes', 'summary': 'Details the implementation of a rest api for creating and reading comments and submitting votes for posts, including details on http status codes, mapping methods, and dependencies like the time-ago library and kotlin standard libraries.', 'duration': 793.752, 'highlights': ['The chapter details the implementation of a REST API for creating and reading comments, with an explanation of HTTP status codes and mapping methods, as well as dependencies like the time-ago library and Kotlin standard libraries.', 'The implementation includes details on creating methods for getting all comments for a post and for a user, and testing the implementation using Postman.', 'The chapter also covers the implementation of submitting votes for posts, including validations to ensure users can only upvote or downvote once consecutively, and the use of a time-ago library for calculating relative time durations.', 'The implementation involves mapping methods and dependencies like the time-ago library and Kotlin standard libraries, as well as details on calculating relative time durations for posts.']}], 'duration': 1118.573, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c4855316.jpg', 'highlights': ['Injecting post and user repository into our comment service class allows for efficient data retrieval and manipulation.', 'Querying the post repository by using the find by ID method improves efficiency in locating specific posts.', 'Determining the author of the comment based on the currently logged in user enhances user interaction and personalization.', 'Created a comment mapper interface with method definitions and mappings, including mappings for the ID, text, and created date fields, with the use of Java expressions for evaluating the created date field, ensuring the auto generation of ID, and mapping the text and created date fields from comments DTO to comment objects.', 'Implemented the functionality to send a notification email to the author of the post by reusing the previously built mail sending functionality, asynchronously sending the email message to the user after building the email body and using the mail service to send the email.', 'The chapter details the implementation of a REST API for creating and reading comments, with an explanation of HTTP status codes and mapping methods, as well as dependencies like the time-ago library and Kotlin standard libraries.', 'The implementation includes details on creating methods for getting all comments for a post and for a user, and testing the implementation using Postman.', 'The chapter also covers the implementation of submitting votes for posts, including validations to ensure users can only upvote or downvote once consecutively, and the use of a time-ago library for calculating relative time durations.']}, {'end': 6713.072, 'segs': [{'end': 5998.26, 'src': 'embed', 'start': 5973.889, 'weight': 3, 'content': [{'end': 5982.193, 'text': "so the good thing here is we updated our mappings and we didn't even touch the post service class because of these changes,", 'start': 5973.889, 'duration': 8.304}, {'end': 5994.719, 'text': 'because we just updated our post mapper class methods inside this class and by creating this mapper we are able to decouple the mapping logic with with the actual business logic which is handled inside the service.', 'start': 5982.193, 'duration': 12.526}, {'end': 5998.26, 'text': "so that's always a good thing to decouple our components right.", 'start': 5994.719, 'duration': 3.541}], 'summary': 'Updated mappings without touching post service class, decoupling mapping logic from business logic.', 'duration': 24.371, 'max_score': 5973.889, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c5973889.jpg'}, {'end': 6067.891, 'src': 'embed', 'start': 6016.634, 'weight': 5, 'content': [{'end': 6023.599, 'text': 'I created this body, so I have provided the vote type as downvote and provided a post ID.', 'start': 6016.634, 'duration': 6.965}, {'end': 6028.042, 'text': "now let's test and send this request and see what it happens.", 'start': 6024.68, 'duration': 3.362}, {'end': 6031.465, 'text': 'and as you can see, the server responded with status.', 'start': 6028.042, 'duration': 3.423}, {'end': 6033.786, 'text': 'that means with status 200.', 'start': 6031.465, 'duration': 2.321}, {'end': 6035.487, 'text': 'that means okay.', 'start': 6033.786, 'duration': 1.701}, {'end': 6039.79, 'text': "now let's see if the vote count is also included in the post response.", 'start': 6035.487, 'duration': 4.303}, {'end': 6044.533, 'text': "so now i'm going to call the endpoint to get all posts.", 'start': 6039.79, 'duration': 4.743}, {'end': 6051.718, 'text': 'so here you can see that for the post id which i used before, the vote count is minus one as we have downloaded this post.', 'start': 6044.533, 'duration': 7.185}, {'end': 6059.604, 'text': "so that means our implementation is working as expected and let's also test another case.", 'start': 6052.538, 'duration': 7.066}, {'end': 6063.968, 'text': 'so if we try to download the post again, that means one more time.', 'start': 6059.604, 'duration': 4.364}, {'end': 6067.891, 'text': 'you can see we have received the message you have already downloaded this post.', 'start': 6063.968, 'duration': 3.923}], 'summary': 'Implemented downvoting feature; successful test with -1 vote count and post download restriction.', 'duration': 51.257, 'max_score': 6016.634, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6016634.jpg'}, {'end': 6159.68, 'src': 'embed', 'start': 6133.741, 'weight': 0, 'content': [{'end': 6138.043, 'text': 'and that is the reason we have to find a solution to invalidate the token, also on our backend.', 'start': 6133.741, 'duration': 4.302}, {'end': 6146.169, 'text': 'which brings us to our second point, which is to introduce an expiration time for our tokens and make them as short lived as possible.', 'start': 6138.763, 'duration': 7.406}, {'end': 6152.554, 'text': 'so ideally we have to give an expiration time of 10 to 15 minutes for our JSONWIB tokens,', 'start': 6146.169, 'duration': 6.385}, {'end': 6157.859, 'text': 'and here I will be using the terms the JSONWIB token and access token interchangeably from now on.', 'start': 6152.554, 'duration': 5.305}, {'end': 6159.68, 'text': 'so, but the downside here?', 'start': 6157.859, 'duration': 1.821}], 'summary': 'Introduce 10-15 minute expiration time for jsonwib tokens.', 'duration': 25.939, 'max_score': 6133.741, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6133741.jpg'}, {'end': 6218.162, 'src': 'embed', 'start': 6173.328, 'weight': 2, 'content': [{'end': 6178.73, 'text': 'The third solution is to introduce a concept called as refresh tokens, which builds on our point number two.', 'start': 6173.328, 'duration': 5.402}, {'end': 6184.792, 'text': 'But the idea is to provide the user an additional token called as refresh token at the time of authentication.', 'start': 6179.21, 'duration': 5.582}, {'end': 6192.636, 'text': 'So we use this refresh token to generate a new access token whenever the access token is expired or about to be expired.', 'start': 6185.213, 'duration': 7.423}, {'end': 6195.577, 'text': 'So in this way, we can keep on rotating the access tokens.', 'start': 6193.056, 'duration': 2.521}, {'end': 6199.678, 'text': 'And when the user logs out, we can just delete this refresh token.', 'start': 6195.977, 'duration': 3.701}, {'end': 6207.7, 'text': 'The last solution is when the user wants to log out, we just store the token inside a database.', 'start': 6201.599, 'duration': 6.101}, {'end': 6215.122, 'text': 'And once we have done that, we check each token, each request and check whether this request,', 'start': 6208.22, 'duration': 6.902}, {'end': 6218.162, 'text': 'and check whether this token is inside the database or not.', 'start': 6215.122, 'duration': 3.04}], 'summary': 'Introduce refresh tokens to rotate access tokens and store tokens in a database for logout.', 'duration': 44.834, 'max_score': 6173.328, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6173328.jpg'}, {'end': 6461.513, 'src': 'embed', 'start': 6436.381, 'weight': 1, 'content': [{'end': 6441.924, 'text': "so, before doing any more implementation, let's leave this aside and create a class with name refresh token service.", 'start': 6436.381, 'duration': 5.543}, {'end': 6446.626, 'text': 'This class will be responsible to create, delete and validate the refresh tokens.', 'start': 6442.844, 'duration': 3.782}, {'end': 6451.869, 'text': "So the first thing I'm going to do is to add in a method called as generate refresh token.", 'start': 6447.406, 'duration': 4.463}, {'end': 6454.99, 'text': "And here I'm going to create an object for refresh token.", 'start': 6452.609, 'duration': 2.381}, {'end': 6461.513, 'text': 'And this refresh token is, so we, so we are going to store this refresh token inside the database.', 'start': 6455.61, 'duration': 5.903}], 'summary': 'Create a refreshtokenservice class to generate, delete, and validate refresh tokens and store them in the database.', 'duration': 25.132, 'max_score': 6436.381, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6436381.jpg'}], 'start': 5973.889, 'title': 'Decoupling mapping logic and implementing json web token invalidation', 'summary': 'Discusses decoupling mapping logic, updating mappings without service class modification, and implementing json web token invalidation with expiration time, refresh tokens, and database token storage for enhanced security and user experience.', 'chapters': [{'end': 6067.891, 'start': 5973.889, 'title': 'Decoupling mapping logic', 'summary': 'Discusses decoupling the mapping logic from the business logic, updating mappings without touching the service class, and successfully submitting a downvote and verifying the vote count functionality with server response status 200.', 'duration': 94.002, 'highlights': ['Decoupling the mapping logic from the business logic allows for updating mappings without touching the service class, enhancing flexibility and maintainability.', 'Submitting a downvote results in a server response with status 200, indicating successful submission.', 'Verifying the vote count functionality shows that the implementation is working as expected, as downloading a post results in a vote count of minus one.']}, {'end': 6713.072, 'start': 6069.304, 'title': 'Implementing json web token invalidation', 'summary': 'Discusses implementing json web token invalidation mechanism, including introducing expiration time, using refresh tokens, and database token storage, aimed at enhancing token security and user experience.', 'duration': 643.768, 'highlights': ['Introducing expiration time for JSON Web Tokens, ideally 10 to 15 minutes, to enhance security and user experience.', 'Utilizing refresh tokens to generate new access tokens when the previous ones expire, ensuring continuous token rotation for improved security.', 'Creating a refresh token service to handle the generation, validation, and deletion of refresh tokens, enhancing token security and management.', 'Implementing a logout mechanism by deleting the refresh token, ensuring secure user logout and token invalidation.']}], 'duration': 739.183, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c5973889.jpg', 'highlights': ['Introducing expiration time for JSON Web Tokens, ideally 10 to 15 minutes, to enhance security and user experience.', 'Creating a refresh token service to handle the generation, validation, and deletion of refresh tokens, enhancing token security and management.', 'Implementing a logout mechanism by deleting the refresh token, ensuring secure user logout and token invalidation.', 'Decoupling the mapping logic from the business logic allows for updating mappings without touching the service class, enhancing flexibility and maintainability.', 'Utilizing refresh tokens to generate new access tokens when the previous ones expire, ensuring continuous token rotation for improved security.', 'Submitting a downvote results in a server response with status 200, indicating successful submission.', 'Verifying the vote count functionality shows that the implementation is working as expected, as downloading a post results in a vote count of minus one.']}, {'end': 8759.588, 'segs': [{'end': 6736.245, 'src': 'embed', 'start': 6713.132, 'weight': 0, 'content': [{'end': 6721.474, 'text': 'So instead of that, we will be sending the generated refresh token by calling refresh token service dot generate refresh token.', 'start': 6713.132, 'duration': 8.342}, {'end': 6727.175, 'text': 'So this will return us the string and we will pass this to the authentication response.', 'start': 6722.074, 'duration': 5.101}, {'end': 6729.598, 'text': "Okay, so that's it.", 'start': 6728.757, 'duration': 0.841}, {'end': 6733.642, 'text': 'We have covered all the points to implement Refresh Token mechanism in our application.', 'start': 6729.658, 'duration': 3.984}, {'end': 6736.245, 'text': "Let's start the application and test it.", 'start': 6734.263, 'duration': 1.982}], 'summary': 'Implemented refresh token mechanism for application', 'duration': 23.113, 'max_score': 6713.132, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6713132.jpg'}, {'end': 6978.691, 'src': 'embed', 'start': 6954.03, 'weight': 9, 'content': [{'end': 6960.616, 'text': 'Once the installation is completed, you can see that the bootstrap is added to the list of dependencies inside the package.json file.', 'start': 6954.03, 'duration': 6.586}, {'end': 6971.586, 'text': 'Now we have to update the angular.json file with the location of the bootstrap CSS files,', 'start': 6965.822, 'duration': 5.764}, {'end': 6978.691, 'text': 'because the Angular CLI by default will exclude the bootstrap CSS files when creating the bundle when starting the application.', 'start': 6971.586, 'duration': 7.105}], 'summary': 'After installation, bootstrap is added to package.json dependencies. angular.json file is updated to include bootstrap css files.', 'duration': 24.661, 'max_score': 6954.03, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6954030.jpg'}, {'end': 7441.582, 'src': 'embed', 'start': 7411.407, 'weight': 3, 'content': [{'end': 7420.49, 'text': "Now I'm going to open the written tutorial and copying the signup component HTML file code from there and paste it inside our project.", 'start': 7411.407, 'duration': 9.083}, {'end': 7425.972, 'text': "After that, let's also copy the CSS file to the signup component dot CSS.", 'start': 7421.751, 'duration': 4.221}, {'end': 7441.582, 'text': 'Now before checking out how this looks inside the browser, you have to add a route from the signup button on the header section to the signup page.', 'start': 7434.699, 'duration': 6.883}], 'summary': 'Copy html and css code to the project, add route to signup page.', 'duration': 30.175, 'max_score': 7411.407, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c7411407.jpg'}, {'end': 7488.479, 'src': 'embed', 'start': 7463.294, 'weight': 2, 'content': [{'end': 7469.635, 'text': "Now let's go to the browser and check if we are able to navigate to the signup page after clicking on the signup button on the header section.", 'start': 7463.294, 'duration': 6.341}, {'end': 7471.356, 'text': 'So perfect, it works.', 'start': 7470.235, 'duration': 1.121}, {'end': 7476.016, 'text': "Now let's handle the form input inside our signup page using reactive forms.", 'start': 7471.856, 'duration': 4.16}, {'end': 7481.578, 'text': "As a first step, let's import the reactive forms module inside our app module.ts file.", 'start': 7476.877, 'duration': 4.701}, {'end': 7488.479, 'text': "I'm going to add reactive forms module just below the app protein module and also make sure that to add the import statement.", 'start': 7482.138, 'duration': 6.341}], 'summary': 'Tested signup page navigation, implemented reactive forms module.', 'duration': 25.185, 'max_score': 7463.294, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c7463294.jpg'}, {'end': 7767.263, 'src': 'embed', 'start': 7742.909, 'weight': 4, 'content': [{'end': 7750.37, 'text': "I'm going to open, I'm going to go inside the signup folder and create a file called as signupRequest.payload.ts.", 'start': 7742.909, 'duration': 7.461}, {'end': 7758.592, 'text': "And inside this field, I'm going to create a signupRequest payload model interface with fields username, email and password.", 'start': 7751.27, 'duration': 7.322}, {'end': 7767.263, 'text': "OK, now let's declare this model inside our component.", 'start': 7764.901, 'duration': 2.362}], 'summary': 'Creating signuprequest payload model with username, email, and password fields.', 'duration': 24.354, 'max_score': 7742.909, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c7742909.jpg'}, {'end': 8032.727, 'src': 'embed', 'start': 8001.506, 'weight': 1, 'content': [{'end': 8005.25, 'text': "And I'm going to overwrite the add course mappings method.", 'start': 8001.506, 'duration': 3.744}, {'end': 8013.695, 'text': 'And this method contains all the course related configurations which we required for the backend.', 'start': 8006.77, 'duration': 6.925}, {'end': 8019.999, 'text': 'And here we are actually accepting the request from all origins to our backend.', 'start': 8014.315, 'duration': 5.684}, {'end': 8026.904, 'text': "If you're developing a production grade application, you may want to not do this and read more about what are the right way to do.", 'start': 8020.359, 'duration': 6.545}, {'end': 8032.727, 'text': 'But for now, this configuration should resolve the problem we have with our registration.', 'start': 8027.864, 'duration': 4.863}], 'summary': 'Overwriting add course mappings method for backend configurations and allowing requests from all origins to resolve registration problem.', 'duration': 31.221, 'max_score': 8001.506, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8001506.jpg'}, {'end': 8152.332, 'src': 'embed', 'start': 8123.26, 'weight': 5, 'content': [{'end': 8130.082, 'text': "After that is done, let's open the login component.ts file and let's configure the form group with variable name as login form.", 'start': 8123.26, 'duration': 6.822}, {'end': 8134.444, 'text': "And I'm going to initialize the form inside the ngOnInit block.", 'start': 8131.263, 'duration': 3.181}, {'end': 8140.758, 'text': 'Here we are defining the form controls for two fields we have inside our form, which is username and password.', 'start': 8135.592, 'duration': 5.166}, {'end': 8146.365, 'text': 'And we also have defined the validations that these fields require when submitting the form.', 'start': 8141.98, 'duration': 4.385}, {'end': 8152.332, 'text': "Now let's open our login component HTML file and sync the validations we did in the component.ts file.", 'start': 8146.925, 'duration': 5.407}], 'summary': 'Configured form group with username and password fields and their validations.', 'duration': 29.072, 'max_score': 8123.26, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8123260.jpg'}, {'end': 8259.45, 'src': 'embed', 'start': 8236.164, 'weight': 6, 'content': [{'end': 8243.566, 'text': 'After that restart the application and refresh the swaggerui.html page and we should be able to see the swagger REST API documentation again.', 'start': 8236.164, 'duration': 7.402}, {'end': 8256.79, 'text': 'Expand the auth controller and click on the login API section and you can see this API accepts username and password as the request payload and it returns the auth token reference token,', 'start': 8244.446, 'duration': 12.344}, {'end': 8259.45, 'text': 'username and expiration time as responses.', 'start': 8256.79, 'duration': 2.66}], 'summary': 'After restarting application, swagger rest api documentation shows login api accepts username, password and returns auth token, username, and expiration time.', 'duration': 23.286, 'max_score': 8236.164, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8236164.jpg'}, {'end': 8389.388, 'src': 'embed', 'start': 8354.364, 'weight': 7, 'content': [{'end': 8360.125, 'text': "Just below the HTTP client module, I'm going to declare NGX web storage module.for root.", 'start': 8354.364, 'duration': 5.761}, {'end': 8366.326, 'text': 'And also make sure to add the import statement from the NGX web storage package.', 'start': 8361.665, 'duration': 4.661}, {'end': 8370.762, 'text': 'All right, now we are ready to access the local storage from our application.', 'start': 8367.901, 'duration': 2.861}, {'end': 8378.304, 'text': "So let's go back to our AuthService class and inject the class local storage service from ngx web storage.", 'start': 8371.142, 'duration': 7.162}, {'end': 8389.388, 'text': "And once it is done, let's store the token and user information inside the local storage by typing this dot local storage dot store,", 'start': 8379.465, 'duration': 9.923}], 'summary': 'Declaring ngx web storage module for root and accessing local storage from application.', 'duration': 35.024, 'max_score': 8354.364, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8354364.jpg'}, {'end': 8713.813, 'src': 'embed', 'start': 8688.764, 'weight': 8, 'content': [{'end': 8696.59, 'text': 'inside the interceptor method, we first read the token from our local storage using the all service dot get JWT token method,', 'start': 8688.764, 'duration': 7.826}, {'end': 8699.791, 'text': 'which is just retrieving the authentication token from the local storage.', 'start': 8696.59, 'duration': 3.201}, {'end': 8703.693, 'text': 'If the token is valid, we will be setting the value inside the authorization headers.', 'start': 8699.951, 'duration': 3.742}, {'end': 8707.375, 'text': 'If our JSON Web token is active, this is how the process works.', 'start': 8703.953, 'duration': 3.422}, {'end': 8713.813, 'text': 'Now if the token we are setting to the headers is an invalid token, we receive an error response from our backend.', 'start': 8708.191, 'duration': 5.622}], 'summary': 'Interceptor reads token from local storage, sets value in authorization headers if valid. invalid token results in backend error.', 'duration': 25.049, 'max_score': 8688.764, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8688764.jpg'}], 'start': 6713.132, 'title': 'Implementing authentication and user management in angular', 'summary': 'Covers implementing refresh token mechanism, signup functionality, form submission, http call integration, cors configuration, login page implementation, http call handling, and token interceptor in angular 9 app, with focus on angular components, form handling, http requests, and backend integration.', 'chapters': [{'end': 7385.268, 'start': 6713.132, 'title': 'Implementing refresh token mechanism', 'summary': 'Covers the implementation of refresh token mechanism in an application using angular 9, including the installation of bootstrap, creation of the header component, and documentation of rest apis using swagger and springfox.', 'duration': 672.136, 'highlights': ['The chapter covers the implementation of Refresh Token mechanism in an application', 'Using Angular 9 and Visual Studio Code for frontend development', 'Installation of Bootstrap and updating angular.json file for CSS integration', 'Creation of the header component and its HTML and CSS implementation', 'Documentation of REST APIs using Swagger and SpringFox']}, {'end': 7695.693, 'start': 7385.268, 'title': 'Implementing signup functionality in angular app', 'summary': 'Covers implementing the signup functionality in an angular app, including creating the signup component, adding form input handling using reactive forms, and displaying validation errors for each field.', 'duration': 310.425, 'highlights': ['Created the signup component and added route for navigation to the signup page', 'Implemented form input handling using reactive forms and added validators for the fields', 'Displayed validation errors for each field and applied styling for invalid inputs']}, {'end': 7935.334, 'start': 7696.634, 'title': 'Integrating form submission and http call in angular', 'summary': 'Covers integrating form submission and http call in angular, including defining payload model interface, creating signup method, making http call to backend api, and subscribing to the response.', 'duration': 238.7, 'highlights': ['Defined signupRequest payload model interface with fields username, email, and password inside the Angular application.', 'Created a separate class called AuthService to make the HTTP call to the backend API, with the signup method declared to handle the HTTP call.', 'Injected the HTTP client class into the AuthService through the constructor and declared the written type as observable of any for the signup method.', 'Subscribed to the observable returned by the signup method in the signup component.ts file and logged the response.']}, {'end': 8185.712, 'start': 7936.255, 'title': 'Configuring cors and implementing login page', 'summary': 'Covers configuring cors to resolve backend request issues, implementing login functionality in angular, including creating login component, configuring routes, and adding form validations, resulting in successful backend response and user input validation.', 'duration': 249.457, 'highlights': ['Configuring CORS by creating a class called WebConfig, adding configuration and enabling WebMVC annotations, implementing a WebMVC configurator interface, and overwriting the addCorsMappings method to accept requests from all origins.', 'Implementing login functionality by creating a login component, copying and pasting HTML and CSS code from a blog post, extracting common CSS code to a styles.css file, configuring routes for the login page, and setting up form controls with validations for username and password fields.']}, {'end': 8759.588, 'start': 8186.793, 'title': 'Handling http calls and token interceptor in angular', 'summary': 'Discusses handling http calls to the login rest api, enabling swagger api documentation, creating models in angular, using ngx-web-storage for local storage, adding ngx-toaster for notifications, and implementing token interceptor for managing json web tokens in the angular application.', 'duration': 572.795, 'highlights': ['Enabling Swagger API documentation', 'Creating models in Angular for login request and response', 'Using ngx-web-storage for local storage', 'Adding ngx-toaster for notifications', 'Implementing token interceptor for managing JSON web tokens']}], 'duration': 2046.456, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c6713132.jpg', 'highlights': ['Implemented Refresh Token mechanism in the application', 'Configured CORS to accept requests from all origins', 'Implemented form input handling using reactive forms and validators', 'Created signup component and added route for navigation', 'Defined signupRequest payload model interface with fields', 'Implemented login functionality and form controls with validations', 'Enabled Swagger API documentation and created models for login', 'Used ngx-web-storage for local storage and added ngx-toaster for notifications', 'Implemented token interceptor for managing JSON web tokens', 'Installed Bootstrap and updated angular.json file for CSS integration']}, {'end': 9541.767, 'segs': [{'end': 8822.414, 'src': 'embed', 'start': 8760.008, 'weight': 0, 'content': [{'end': 8768.235, 'text': 'Coming to our RefreshToken method, if we check the REST API documentation, this method takes in two fields as input, the RefreshToken and username.', 'start': 8760.008, 'duration': 8.227}, {'end': 8775.2, 'text': 'So we are constructing this object inside the refresh token method and making a HTTP post call to our backend.', 'start': 8769.175, 'duration': 6.025}, {'end': 8776.801, 'text': 'For this post call.', 'start': 8775.88, 'duration': 0.921}, {'end': 8785.848, 'text': 'we are receiving the login response object from our backend as response and we are storing the new authentication token and username values inside the local storage.', 'start': 8776.801, 'duration': 9.047}, {'end': 8795.435, 'text': 'As we discussed before, we are setting the new access token value to the behavior subject and setting the ease token refreshing field value to false,', 'start': 8787.008, 'duration': 8.427}, {'end': 8797.836, 'text': 'or else all the outgoing calls will be failing with a 403 error.', 'start': 8795.435, 'duration': 2.401}, {'end': 8804.555, 'text': 'Okay now before we test this implementation we need to create a homepage component in our application.', 'start': 8799.87, 'duration': 4.685}, {'end': 8807.999, 'text': "For that I'm going to type ng g c home.", 'start': 8805.316, 'duration': 2.683}, {'end': 8812.944, 'text': 'This component retrieves and displays all the posts we have in the database.', 'start': 8809.14, 'duration': 3.804}, {'end': 8815.066, 'text': 'So for that now.', 'start': 8813.825, 'duration': 1.241}, {'end': 8822.414, 'text': 'open the written tutorial and copy the HTML under the create homepage component section and paste it into the home component HTML file.', 'start': 8815.066, 'duration': 7.348}], 'summary': 'The refreshtoken method makes a post call to store new authentication token and username. a homepage component is created to display posts from the database.', 'duration': 62.406, 'max_score': 8760.008, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8760008.jpg'}, {'end': 8866.888, 'src': 'embed', 'start': 8840.933, 'weight': 2, 'content': [{'end': 8845.356, 'text': "And inside the constructor, I'm going to inject the HTTP client class to our post service.", 'start': 8840.933, 'duration': 4.423}, {'end': 8848.618, 'text': "And let's create a method called as get all posts.", 'start': 8846.376, 'duration': 2.242}, {'end': 8852.755, 'text': "So now let's go ahead and check our REST API documentation.", 'start': 8849.932, 'duration': 2.823}, {'end': 8862.544, 'text': 'So you can see this is just a normal get call and we receive an array of object which contains all these fields which are related to the post.', 'start': 8853.395, 'duration': 9.149}, {'end': 8866.888, 'text': "So now let's go back to the VSCode and create a file called as postmodel.ts.", 'start': 8863.004, 'duration': 3.884}], 'summary': 'Inject http client class, create get all posts method, check rest api documentation', 'duration': 25.955, 'max_score': 8840.933, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8840933.jpg'}, {'end': 9193.201, 'src': 'embed', 'start': 9149.968, 'weight': 1, 'content': [{'end': 9156.929, 'text': 'now, if you go ahead and open the application inside the browser, you can see the up and down arrows along with the icon for comments.', 'start': 9149.968, 'duration': 6.961}, {'end': 9162.471, 'text': 'but one thing which looks strange is that the home component and the header component are overlapping.', 'start': 9156.929, 'duration': 5.542}, {'end': 9164.371, 'text': 'we can fix that easily.', 'start': 9162.471, 'duration': 1.9}, {'end': 9168.212, 'text': 'we can fix that easily by adding the css to our styles.css file.', 'start': 9164.371, 'duration': 3.841}, {'end': 9172.793, 'text': 'We basically added a margin top value of 63 pixels for body.', 'start': 9169.275, 'duration': 3.518}, {'end': 9179.816, 'text': 'If you go and check the application, you can see now the home component is not overlapping with the header component anymore.', 'start': 9173.874, 'duration': 5.942}, {'end': 9183.557, 'text': "Okay, now let's go ahead and try to break down this homepage into different components.", 'start': 9180.116, 'duration': 3.441}, {'end': 9190.34, 'text': "For that, I'm going to use the screenshot of the final version of the homepage to get an idea how we're going to refactor this page.", 'start': 9184.418, 'duration': 5.922}, {'end': 9193.201, 'text': 'So, in the homepage we have many posts.', 'start': 9191.5, 'duration': 1.701}], 'summary': 'Fixed overlap between home and header components by adding 63px margin in styles.css. refactoring homepage into different components using screenshot of final version.', 'duration': 43.233, 'max_score': 9149.968, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c9149968.jpg'}, {'end': 9469.897, 'src': 'embed', 'start': 9441.477, 'weight': 7, 'content': [{'end': 9447.082, 'text': "I'm going to create the service using the command ng-gs which stands for ng generate service.", 'start': 9441.477, 'duration': 5.605}, {'end': 9449.97, 'text': 'subreddit slash subreddit.', 'start': 9448.129, 'duration': 1.841}, {'end': 9455.232, 'text': 'We should create a subreddit service.ts file under the newly created subreddit folder.', 'start': 9450.67, 'duration': 4.562}, {'end': 9460.434, 'text': "Now let's also create a model class which holds the response from the subreddit HTTP call.", 'start': 9455.992, 'duration': 4.442}, {'end': 9469.897, 'text': "I'm going to create a file called as subreddit response.ts and I'm going to create a class which contains the field ID, description,", 'start': 9461.254, 'duration': 8.643}], 'summary': 'Creating a service using ng-gs command to generate a subreddit service.ts file and a model class for subreddit response.ts.', 'duration': 28.42, 'max_score': 9441.477, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c9441477.jpg'}], 'start': 8760.008, 'title': 'Refreshtoken method and creating homepage component', 'summary': 'Discusses using the refreshtoken method for http post calls and creating a homepage component with post service implementation, rest api integration, font awesome icons, and refactoring into different components.', 'chapters': [{'end': 8797.836, 'start': 8760.008, 'title': 'Refreshtoken method and http post call', 'summary': 'Discusses the process of using the refreshtoken method to make an http post call to the backend, which involves constructing an object with the refreshtoken and username, receiving a login response object, and storing the new authentication token and username values in local storage, thus ensuring the ease token refreshing field value is set to false to avoid outgoing call failures with a 403 error.', 'duration': 37.828, 'highlights': ['The RefreshToken method takes in two fields as input, the RefreshToken and username, and makes an HTTP post call to the backend.', 'The login response object from the backend is received and the new authentication token and username values are stored in local storage.', 'The ease token refreshing field value is set to false to prevent outgoing call failures with a 403 error.']}, {'end': 9541.767, 'start': 8799.87, 'title': 'Creating homepage component and refactoring with angular', 'summary': 'Discusses creating a homepage component, implementing a post service, incorporating rest api documentation, integrating font awesome icons, and refactoring the homepage into different components, with a focus on creating a post tile component and vote button component.', 'duration': 741.897, 'highlights': ['Creating a homepage component and implementing a post service', 'Incorporating REST API documentation and creating a post model class', 'Integrating font awesome icons and addressing CSS overlap', 'Refactoring the homepage into different components', 'Creating a subreddit service and model class']}], 'duration': 781.759, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c8760008.jpg', 'highlights': ['Creating a homepage component and implementing a post service', 'Refactoring the homepage into different components', 'Incorporating REST API documentation and creating a post model class', 'Integrating font awesome icons and addressing CSS overlap', 'The RefreshToken method takes in two fields as input, the RefreshToken and username, and makes an HTTP post call to the backend', 'The login response object from the backend is received and the new authentication token and username values are stored in local storage', 'The ease token refreshing field value is set to false to prevent outgoing call failures with a 403 error', 'Creating a subreddit service and model class']}, {'end': 10635.979, 'segs': [{'end': 9564.024, 'src': 'embed', 'start': 9541.767, 'weight': 0, 'content': [{'end': 9550.133, 'text': 'four records in the array, we will display a view all button which takes us to a new page and display all the subreddit information.', 'start': 9541.767, 'duration': 8.366}, {'end': 9552.695, 'text': "For now, let's add this view all button to our section.", 'start': 9550.514, 'duration': 2.181}, {'end': 9559.901, 'text': 'We can add that by declaring a boolean flag first inside the subreddit sidebar component called as display view all.', 'start': 9552.915, 'duration': 6.986}, {'end': 9564.024, 'text': 'And inside the subscribe method of the get all subreddits call.', 'start': 9560.561, 'duration': 3.463}], 'summary': 'Array has four records, adding view all button to display subreddit information.', 'duration': 22.257, 'max_score': 9541.767, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c9541767.jpg'}, {'end': 10210.228, 'src': 'embed', 'start': 10184.41, 'weight': 1, 'content': [{'end': 10191.115, 'text': "I'm going to open the home page and click on the create post button on the sidebar section and I'm going to provide the necessary details here.", 'start': 10184.41, 'duration': 6.705}, {'end': 10195.358, 'text': 'So you can see the cool tiny MC editor we installed looks something like this.', 'start': 10191.215, 'duration': 4.143}, {'end': 10201.282, 'text': "So I'm going to use this controls and provide some text and click on the post button.", 'start': 10196.298, 'duration': 4.984}, {'end': 10204.464, 'text': 'And you can see we are navigated to the home page.', 'start': 10202.462, 'duration': 2.002}, {'end': 10210.228, 'text': 'If you scroll all the way down, you see the HTML code instead of seeing the text in the expected format.', 'start': 10204.684, 'duration': 5.544}], 'summary': 'Demonstrating creating a post using the mc editor, resulting in html code.', 'duration': 25.818, 'max_score': 10184.41, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c10184410.jpg'}, {'end': 10269.236, 'src': 'embed', 'start': 10228.016, 'weight': 2, 'content': [{'end': 10232.5, 'text': 'But for now, we have to change the way we are rendering this information inside the post trial component.', 'start': 10228.016, 'duration': 4.484}, {'end': 10239.767, 'text': "So let's open up the post trial component.html file and under the div section where we display the description,", 'start': 10233.041, 'duration': 6.726}, {'end': 10246.434, 'text': "I'm going to change the interpolation to a inner HTML directive and pass the value post.description to it.", 'start': 10239.767, 'duration': 6.667}, {'end': 10252.019, 'text': 'This will render our text as HTML and now we are able to see the text as we expect.', 'start': 10247.415, 'duration': 4.604}, {'end': 10262.837, 'text': 'So, in the last episode we developed the logic to create the post in our application,', 'start': 10258.567, 'duration': 4.27}, {'end': 10266.044, 'text': "but we still don't have a way to drill down and read the post information.", 'start': 10262.837, 'duration': 3.207}, {'end': 10269.236, 'text': "Let's create a component called as view post.", 'start': 10267.034, 'duration': 2.202}], 'summary': 'Change rendering method in post trial component to display html; develop logic for creating and viewing posts.', 'duration': 41.22, 'max_score': 10228.016, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c10228016.jpg'}, {'end': 10595.638, 'src': 'embed', 'start': 10570.553, 'weight': 4, 'content': [{'end': 10575.716, 'text': "If you're following along with this tutorial from the beginning, chances are that it's not so hard to replicate this bug.", 'start': 10570.553, 'duration': 5.163}, {'end': 10578.558, 'text': 'In fact we have not one but two bugs.', 'start': 10576.716, 'duration': 1.842}, {'end': 10579.62, 'text': "Let's have a look at them.", 'start': 10578.819, 'duration': 0.801}, {'end': 10585.967, 'text': 'The first one is inside the intercept method, where we are retrieving the token from the local storage,', 'start': 10580.32, 'duration': 5.647}, {'end': 10591.573, 'text': 'and inside the add token method we are cloning this request and adding the authorization header.', 'start': 10585.967, 'duration': 5.606}, {'end': 10595.638, 'text': 'We are cloning this request because the initial request object is immutable.', 'start': 10592.314, 'duration': 3.324}], 'summary': 'Tutorial reveals 2 bugs in intercept method: retrieving token and cloning request.', 'duration': 25.085, 'max_score': 10570.553, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c10570553.jpg'}], 'start': 9541.767, 'title': 'Implementing view all button, subreddit and post creation, and fixing tinymce html rendering', 'summary': "Discusses implementing a 'view all' button, moving properties, generating components, adding routes, integrating tinymce editor, making http post calls, and fixing html rendering and creating post view component in an angular application.", 'chapters': [{'end': 9584.905, 'start': 9541.767, 'title': 'Implementing view all button', 'summary': "Discusses implementing a 'view all' button to display subreddit information, using a boolean flag and the splice method to limit the displayed entries to four, and making necessary additions to the vote button component.ts file.", 'duration': 43.138, 'highlights': ["Adding a 'View All' button to display subreddit information and limiting displayed entries to four using the splice method", 'Implementing a boolean flag called display view all inside the subreddit sidebar component', 'Making necessary additions to the vote button component.ts file']}, {'end': 10183.95, 'start': 9585.706, 'title': 'Implementing subreddit and post creation', 'summary': 'Covers moving properties between files, generating components, adding routes, implementing form groups and controls, making http post calls, and integrating tinymce editor for subreddit and post creation in an angular application.', 'duration': 598.244, 'highlights': ['Integrating TinyMCE editor for post creation', 'Implementing createSubreddit and createPost methods', 'Adding routes and navigating between components']}, {'end': 10635.979, 'start': 10184.41, 'title': 'Fixing tinymce html rendering and creating post view component', 'summary': 'Covers fixing the rendering of html code from tinymce editor, creating a post view component with functionalities such as navigating to post, displaying post details, submitting comments, and handling bugs in token interceptor, and comment service.', 'duration': 451.569, 'highlights': ['We fixed the rendering issue of HTML code from TinyMCE editor by changing the interpolation to inner HTML directive, allowing the text to be rendered as HTML instead of displaying the HTML code, resulting in an improved user experience.', 'Created a post view component with functionalities including navigating to post, displaying post details, submitting comments, and fetching post and comment information from the backend to enhance the user interaction and engagement.', 'Identified and addressed bugs in the token interceptor, including issues with handling token expiration and refreshing, to ensure seamless and secure authentication and authorization processes, preventing 403 errors and potential security vulnerabilities.']}], 'duration': 1094.212, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c9541767.jpg', 'highlights': ["Implemented 'View All' button to display subreddit info and limit entries to 4", 'Integrated TinyMCE editor for post creation and added routes for navigation', 'Fixed HTML rendering issue from TinyMCE editor by changing interpolation to inner HTML directive', 'Created post view component with functionalities for user interaction and engagement', 'Identified and addressed bugs in token interceptor for seamless authentication and authorization']}, {'end': 11597.858, 'segs': [{'end': 10808.852, 'src': 'embed', 'start': 10763.446, 'weight': 2, 'content': [{'end': 10770.709, 'text': 'after running these commands we have to enable ng-bootstrap in our application by adding the ngb module to the app-module.ts file.', 'start': 10763.446, 'duration': 7.263}, {'end': 10774.072, 'text': 'Now we are ready to make the changes.', 'start': 10772.531, 'duration': 1.541}, {'end': 10781.997, 'text': "So I'm going to open the written tutorial and under the section displaying username in the header section, go to the header component,", 'start': 10774.472, 'duration': 7.525}, {'end': 10787.421, 'text': 'HTML and CSS files, copy the code and paste it into the respective files.', 'start': 10781.997, 'duration': 5.424}, {'end': 10793.966, 'text': 'So we basically updated the header component by adding a dropdown from the ng-bootstrap library.', 'start': 10789.184, 'duration': 4.782}, {'end': 10798.288, 'text': 'We are displaying this dropdown based on the value of the ease-logged-in flag.', 'start': 10794.606, 'duration': 3.682}, {'end': 10803.73, 'text': 'If the flag is true, we are displaying the dropdown and the options in the dropdown are profile and logout.', 'start': 10798.868, 'duration': 4.862}, {'end': 10808.852, 'text': 'So we have some functions defined through the click directive.', 'start': 10804.59, 'duration': 4.262}], 'summary': 'Enabled ng-bootstrap, updated header component with dropdown based on ease-logged-in flag.', 'duration': 45.406, 'max_score': 10763.446, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c10763446.jpg'}, {'end': 10907.26, 'src': 'embed', 'start': 10879.248, 'weight': 1, 'content': [{'end': 10884.251, 'text': 'so we have some welcome text here, along with the number of posts and comments submitted by the user.', 'start': 10879.248, 'duration': 5.003}, {'end': 10886.413, 'text': 'We are using this.', 'start': 10885.111, 'duration': 1.302}, {'end': 10891.22, 'text': 'we are using this app post child component here because we want to display a list of posts.', 'start': 10886.413, 'duration': 4.807}, {'end': 10894.926, 'text': 'And lastly, we are displaying all the comments which are posted by the user.', 'start': 10892.042, 'duration': 2.884}, {'end': 10901.155, 'text': 'To use this pose style component inside the user component, we have to make a small refactoring.', 'start': 10896.772, 'duration': 4.383}, {'end': 10907.26, 'text': 'In the previous episodes, we had the logic to read pose from backend inside the pose style component.', 'start': 10901.956, 'duration': 5.304}], 'summary': 'Using app post child component to display posts and comments.', 'duration': 28.012, 'max_score': 10879.248, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c10879248.jpg'}, {'end': 11081.773, 'src': 'embed', 'start': 11056.308, 'weight': 0, 'content': [{'end': 11062.491, 'text': 'so without this mappings, if you want to try, if you are creating a post, it will not save the user information.', 'start': 11056.308, 'duration': 6.183}, {'end': 11072.727, 'text': 'Okay, we have already created the vote button component in the previous video when refactoring our homepage.', 'start': 11067.483, 'duration': 5.244}, {'end': 11081.773, 'text': 'We have the upvote and downvote icons and inside the HTML, the click directive for these icons is calling the upvote post and downvote post methods.', 'start': 11073.667, 'duration': 8.106}], 'summary': 'Creating mappings will save user information for posts, with upvote and downvote icons and methods.', 'duration': 25.465, 'max_score': 11056.308, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c11056308.jpg'}, {'end': 11266.868, 'src': 'embed', 'start': 11241.701, 'weight': 4, 'content': [{'end': 11248.745, 'text': 'we just have to delete the stored jwt and refresh tokens, along with the user information from the local storage.', 'start': 11241.701, 'duration': 7.044}, {'end': 11257.039, 'text': "After that, we will make an API call to the backend to delete the refresh token so that it won't be possible to rotate the JSON Web Tokens.", 'start': 11249.631, 'duration': 7.408}, {'end': 11259.822, 'text': 'We can quickly have a look at this Wagger documentation.', 'start': 11257.7, 'duration': 2.122}, {'end': 11264.086, 'text': 'So here all we need is a refresh request payload object.', 'start': 11260.362, 'duration': 3.724}, {'end': 11266.868, 'text': 'which we can construct it on the fly.', 'start': 11264.747, 'duration': 2.121}], 'summary': 'Delete jwt and refresh tokens, user info from local storage. make api call to backend to delete refresh token.', 'duration': 25.167, 'max_score': 11241.701, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c11241701.jpg'}], 'start': 10636.519, 'title': 'Angular application development', 'summary': 'Covers fixing bugs, installing ng-bootstrap library, updating header component, creating user profile component, refactoring pose style component, retrieving user posts and comments, adding user profile routing, backend changes for post and vote functionality, and implementing user authentication, logout, guards for secured routes, and configuring guards in the app routing module.', 'chapters': [{'end': 10985.373, 'start': 10636.519, 'title': 'Angular application development', 'summary': 'Covers fixing bugs, installing ng-bootstrap library, updating header component, creating user profile component, refactoring pose style component, and retrieving user posts and comments.', 'duration': 348.854, 'highlights': ['We fixed a bug by adding an else condition, using filter on behavior subject, accepting the first entry using the take method, and using the switch map method for making requests.', 'Installed ng-bootstrap library using npm commands and enabled it in the application by adding the ngb module to the app-module.ts file.', 'Updated header component to display a dropdown from ng-bootstrap library based on the ease-loggedIn flag, added functions for navigating to user profile and handling logout.', "Created user profile component and displayed user's posts and comments, refactored pose style component to receive posts as input, and retrieved user posts and comments from the backend."]}, {'end': 11220.01, 'start': 10985.613, 'title': 'Angular app development update', 'summary': 'Covers adding user profile routing, backend changes for post and vote functionality, and injecting services in the vote button component.', 'duration': 234.397, 'highlights': ['Added user profile routing and updated post controller for user-related methods, resulting in successful display of user profile page with post and comment information.', 'Implemented backend changes for post and vote functionality, including adding path variable annotation and additional mapping for the user field, ensuring proper saving of user information and vote indication.', 'Injected vote service, auth service, post service, and toaster service classes in the vote button component, enabling upvoting and downvoting functionality with observable subscription to update vote details.', 'Generated vote service class with method to make post call to vote API, utilizing vote payload class for request payload and enum for vote type, and subscribing to success response to update vote details.']}, {'end': 11597.858, 'start': 11220.01, 'title': 'Implementing user authentication and authorization in angular', 'summary': 'Covers implementing user authentication, logout, guards for secured routes, and configuring guards in the app routing module, along with making changes to permit certain api calls in the backend security configuration.', 'duration': 377.848, 'highlights': ['The chapter covers implementing user authentication, logout, guards for secured routes, and configuring guards in the app routing module, along with making changes to permit certain API calls in the backend security configuration.', 'The process of logout involves deleting stored JWT and refresh tokens, along with user information from local storage, and making an API call to the backend to delete the refresh token to prevent rotation of JSON Web Tokens.', 'The implementation of guards for secured routes involves creating a can activate guard using the ng generate guard command and configuring the guards in the app routing module by adding the can activate property for specific components.', 'The exclusion of certain endpoints in the Spring security configuration to permit calls to get all subreddit and get all post API for visitors, even if not logged in, is also discussed.', 'The token interceptor class is modified to add a valid token to the authorization header only if present in local storage, bringing consistency to the authorization process and preventing unnecessary errors in the backend.']}], 'duration': 961.339, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/DKlTBBuc32c/pics/DKlTBBuc32c10636519.jpg', 'highlights': ['Implemented backend changes for post and vote functionality, ensuring proper saving of user information and vote indication.', "Created user profile component and displayed user's posts and comments, refactored pose style component to receive posts as input.", 'Installed ng-bootstrap library using npm commands and enabled it in the application by adding the ngb module to the app-module.ts file.', 'Updated header component to display a dropdown from ng-bootstrap library based on the ease-loggedIn flag, added functions for navigating to user profile and handling logout.', 'The process of logout involves deleting stored JWT and refresh tokens, along with user information from local storage, and making an API call to the backend to delete the refresh token to prevent rotation of JSON Web Tokens.']}], 'highlights': ['Demonstration of user registration, account activation via email, posting, voting, and user profiles.', 'The application is built using Spring Boot, Spring MVC, Spring Security with JWT authentication, and Spring Data JPA with MySQL database.', 'Instructions for configuring database properties in the application.properties file, including the MySQL driver class name, data source URL, username, password, Hibernate dialect, and other properties.', 'Implementing email sending logic in Spring application resulting in successful user registration and email delivery', 'Creating JSON Web Tokens with required Maven dependencies', 'Mapstruct is a Java library that generates mapping code for transferring data between objects, reducing manual effort and potential errors in complex mapping.', 'Injecting post and user repository into our comment service class allows for efficient data retrieval and manipulation.', 'Introducing expiration time for JSON Web Tokens, ideally 10 to 15 minutes, to enhance security and user experience.', 'Implemented Refresh Token mechanism in the application', 'Configured CORS to accept requests from all origins', 'Implemented form input handling using reactive forms and validators', 'Creating a homepage component and implementing a post service', 'Implemented backend changes for post and vote functionality, ensuring proper saving of user information and vote indication.', "Created user profile component and displayed user's posts and comments, refactored pose style component to receive posts as input.", 'Installed ng-bootstrap library using npm commands and enabled it in the application by adding the ngb module to the app-module.ts file.']}