Overarching Project
It’s again time to continue with the overarching project. In this part, you’ll focus on adding user-specific functionality to the “Reddit”-themed overarching project.
We recommend working on the overarching project only after completing all other assignments in this part. For deeper learning, it can also help to take a short break of a few days before starting the project.
The overarching project in this part is divided into six steps. The steps are divided so that you always first implement server-side functionality and then client-side functionality. This way, you can focus on one side of the application at a time.
First, in the tenth step, you will add server-side APIs for registration and logging in.
WSD Overarching Project, Step 10
0 / 20 points
In this step, you will implement a set of authentication-related API using a layered architecture and a database to store all relevant user information on the server-side. At the end of this step, your server-side application has the following functionality:
- Database that stores user information.
- API for user registration.
- API for user login.
Users database schema
First, add a new migration file to the database-migrations folder of the project. The migration will be used to create the table users.
You can use any name for the migration file (as long as it follows the naming convention of the other migration files). The contents of the migration file should be as follows:
CREATE TABLE users ( id SERIAL PRIMARY KEY, email TEXT NOT NULL, password_hash TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
CREATE UNIQUE INDEX ON users (lower(trim(email)));After adding the migration file, run the migration to create the table in the database.
Tasks
The task is to implement the following:
POST /api/auth/register
Accepts a JSON body with email and password. Check if the user already exists in the database; if not, create a new user in the database.
The password must be hashed and only the hash stored (not plain text).
Add a new user to the database based on the request body. The request body will have two fields as follows:
{ "email": "dummy_Email@gmail.com", "password": "dummy_Password"}Response to the request with the JSON messages like below after registration, regardless of whether the registration was successful or not.
{ "message": "Confirmation email sent to address ${email}." }POST /api/auth/login
Accepts a JSON body with email and password.
-
Check if the email exists in the database.
-
If it exists, verify the entered password against the stored hashed password.
-
If the email and password match, respond with JSON:
{"message": "Login successful!","user": payload,"token": string (a JWT token)}Where the payload includes the user id and email, and the token is a JWT signed token of the payload.
-
If the email did not exist in the database or the password is incorrect, respond with JSON:
{ "error": "Incorrect email or password." }
Updating routes
Update app.js file to have the two APIs for registering and logging.
Note! When signing the JWT token, use “jwt_secret” as the secret key.
Submission
Once ready, zip the contents of the server folder of your overarching project and submit the zip file below. The controllers folder should be at the root of the zip file. The expected file structure of the project is as follows.
Follow the names exactly as given, as the automated tests will check for them. Your project may have additional files (e.g., Dockerfile, deno.json).
.├── controllers│ ├── authController.js (new)│ └── ...├── repositories│ ├── authRepository.js (new)│ └── ...├── app-run.js└── app.js (updated)Then, in the eleventh step, you will add client-side functionality for interacting with the server-side authentication APIs. This includes registration and login forms, client-side APIs for authentication, and shared state for managing the logged-in user.
WSD Overarching Project, Step 11
0 / 30 points
In this step, you will implement a set of authentication-related APIs, create a shared state for managing authentication, and develop components for logging and registering on the client side. By the end of this step, your application should include the following new functionality:
- A client-side API for authentication.
- A shared state for managing authentication.
- A form for logging in and registering.
Tasks
The task is divided into parts to help structure your work. Each part corresponds to a specific module or component with its own responsibilities.
authApi.js
Create a file authApi.js in the src/lib/apis folder. This file should export functions for interacting with the authentication-related APIs you implemented in earlier overarching project steps.
The API endpoints are as follows:
POST /api/auth/register→ register a new user.POST /api/auth/login→ log in an existing user.
For more details about these API endpoints, refer to WSD Overarching Project, Step 10.
authState.svelte.js
Create a file authState.svelte.js in the src/lib/states folder.
The state should manage authentication state (user and token), store and restore values from localStorage, and provide functions for login, register, and logout. It should export a function that allows components to access and modify the authentication state.
Dynamic registration and login page (routes/auth/[action]/+page.svelte and +page.js)
Implement the dynamic route for login and registration in src/routes/auth/[action]/+page.svelte and src/routes/auth/[action]/+page.js.
Create the dynamic routes for login and registration, including validation of the action parameter, a shared form component, and handling of form submission, success, error messages, and redirection.
+layout.svelte
Create a file +layout.svelte in the src/routes folder. This file will show the authentication status of the user.
When authenticated, the layout should display the text "Hello, {user's email}!" and a log out button. When not authenticated, the layout should display “Login” and “Register” links.
Home page (routes/+page.svelte)
Create a file +page.svelte in the src/routes folder. This file will show a welcome message: “Welcome to the home page!”`.
Example Authentication Flow
- User submits the login or registration form (handled in
+page.svelte). - The form data is sent to
/api/auth/loginor/api/auth/registerusingapiRequest. - On successful login, the server responds with:
{ "message": "Login successful!", "user": "<payload include userId and email>", "token": "<JWT token of payload>" }- The client stores the JWT in both localStorage and the shared state(
authState). - After login, the user is redirected to the main page; after registration, to the login page.
- The user’s email (get from authState) is displayed on all pages after login.
Submission
Once ready, zip the contents of your client/src folder and submit the zip file below. The routes folder should be at the root of the zip file. Follow the file and folder names exactly, as automated tests depend on them.
Your project may include additional files (e.g., Dockerfile, deno.json).
Expected file structure:
.├── lib│ └── apis│ │ ├── authApi.js (new)│ │ └── ...│ ├── components│ │ └── ...│ └── states│ ├── authState.svelte.js (new)│ └── ...└── routes ├── auth │ └── [action] │ ├── +page.js (new) │ └── +page.svelte (new) ├── communities │ └── ... ├── +layout.svelte (new) └── +page.svelte (new)Then, in the twelfth step, you will add server-side functionality for identifying users who created specific communities and restricting certain actions to logged-in users only.
WSD Overarching Project, Step 12
0 / 25 points
In this step, you will implement functions to integrate user information and guard access for specific community-related APIs on the server side. At the end of this step, your server-side application should have the following functionalities:
- An updated database for communities to associate with users.
- An authenticated middleware to verify and add user information into the context.
- Guarding the specific communities API to be usable only with user information.
Database schema
First, add a new migration file to the database-migrations folder of the project. The migration will be used to associate the table “communities” with the table “users”.
You can use any name for the migration file (as long as it follows the naming convention of the other migration files). The contents of the migration file should be as follows:
ALTER TABLE communities ADD COLUMN created_by INTEGER NOT NULL REFERENCES users(id);After adding the migration file, run the migration to create the table in the database.
Tasks
The task is divided into parts to help structure your work. Each part corresponds to a specific module or component with its own responsibilities.
Authentication middleware
Create a file called middlewares.js in the root of the server-side application. The middleware should do the following:
- Extract the token from the Authorization header.
- Verify the token.
- Extract user information from the token.
- Add user information from the token to the context.
Modifying the communities repository
Modify the /repositories/communityRepository.js file so that the functions for creating and deleting communities are passed the identifier of the user who is logged in. The creating function now also stores the identification of the user who performs the operations. The delete functions only operate when the user who is logged in is the same as the person who created that community.
Modifying the communities controller
Then modify the /controllers/communityController.js file so that the controller functions retrieve the user from the context using c.get("user") and pass the user’s identifier to the creating and deleting repository functions.
Updating routes
Update app.js to protect the two communities api routes, which are creating and deleting communities, using the authenticate-middleware.
Note: You don’t want to use authenticate-middleware for GET request API since we still want users who are not logged in to see our communities.
Submission
Once ready, zip the contents of the server folder of your overarching project and submit the zip file below. The controllers folder should be at the root of the zip file. The expected file structure of the project is as follows.
Follow the names exactly as given, as the automated tests will check for them. Your project may have additional files (e.g., Dockerfile, deno.json).
.├── controllers│ ├── communityController.js (updated)│ └── ...├── repositories│ ├── communityRepository.js (updated)│ └── ...├── app-run.js├── app.js (updated)└── middlewares.js (new)Then, in the thirteenth step, you add the client-side functionality for restricting the interaction with communities.
WSD Overarching Project, Step 13
0 / 30 points
In this step, focusing on client-side functionality, you will integrate authentication into your client-side application so that the users can only perform certain actions on the communities when they are logged in, update communities-related API to use authenticated requests, and add a visible constraint between non-users and users when interacting with communities. After this step, your client-side application should have the following functionalities:
- Communities-related API module using authenticated request
- Visibility constraints for non-user vs user in the communities list and the communities form
Tasks
The task is divided into parts to help structure your work. Each part corresponds to a specific module or component with its own responsibilities.
Creating authenticated fetch
Create a src/lib/utils/fetchUtils.js file that exports the authFetch function. The authFetch function should do the following:
- This will serve as a wrapper for fetch functions used in the API module.
- This function will retrieve the token from
authStateand add it to theAuthorizationheader, and make the fetch request - If the response status is 401 (Unauthorized), it logs out the user and redirects to the login page.
Modifying the communities API module
Modify the communities API module src/lib/apis/communitiesApi.js file so that it uses an authenticated request when performing the create and delete actions. Use the authFetch helper function from the fetchUtils.js module.
Noted: Do not use
authFetchfor other APIs that makeGETrequests, since we still want non-users (those who do not log in) to see the communities list and its content.
Modifying the communities list
Modify the src/lib/components/communities/CommunityList.svelte file so that the remove button is only visible if the one who created the communities is the same as the one who is logged in. Do this by comparing the field created_by of the community object with the userId from authState.
Modifying the communities form
Modify the src/lib/components/communities/CommunityForm.svelte file so that it is only visible when the user is logged in.
Modifying the main page text
Modify src/routes/+layout.svelte file so that when the user is not logged in, the text "Hello anonymous!" should be displayed instead of "Hello, {user's email}!"
Modifying the main page text
Finally, modify the src/routes/+page.svelte so that when a user is logged in, the user should be shown a link to /communities with the text “Go to communities”.
Submission
Once ready, zip the contents of your client/src folder and submit the zip file below. The routes folder should be at the root of the zip file. Follow the file and folder names exactly, as automated tests depend on them.
Your project may include additional files (e.g., Dockerfile, deno.json).
Expected file structure:
.├── lib│ ├── apis│ │ ├── communitiesApi.js (updated)│ │ └── ...│ ├── components│ │ ├── communities│ │ │ ├── CommunityForm.svelte (updated)│ │ │ ├── CommunityList.svelte (updated)│ │ │ └── ...│ │ └── ...│ ├── states│ └── utils│ └── fetchUtils.js (new)└── routes ├── auth │ └── ... ├── communities │ └── ... ├── +layout.svelte └── +page.svelte (updated)Then, in the fourteenth step, you will add server-side functionality for identifying users who created specific posts and comments, and restricting certain actions to logged-in users only.
WSD Overarching Project, Step 14
0 / 25 points
In this step, you will implement functions to integrate user information and guard access for specific post and comment APIs on the server side. At the end of this step, your server-side application should have the following functionalities:
- An updated database for posts and comments to associate with users
- Guarding the specific post and comment API to be only usable with user information
- Using an authenticated middleware for the post and comment API.
Database schema
First, add a new migration file to the database-migrations folder of the project. The migration will be used to associate the table “posts” with the table “users”.
You can use any name for the migration file (as long as it follows the naming convention of the other migration files). The contents of the migration file should be as follows:
ALTER TABLE posts ADD COLUMN created_by INTEGER NOT NULL REFERENCES users(id);After adding the migration file, run the migration to create the table in the database.
Tasks
The task is divided into parts to help structure your work. Each part corresponds to a specific module or component with its own responsibilities.
Modifying the post and comments repository
Modify the /repositories/postRepository.js and /repositories/commentRepository.js files so that the functions for creating and deleting are passed the identifier of the user who is logged in. The creating function now also stores the identification of the user who performs the operations. The delete functions only operate when the user who is performing the delete action is the same as the person who created that object.
Modifying the post and comments controller
Then modify the /controllers/postController.js and /controllers/commentController.js files so that the controller functions retrieve the user from the context using c.get("user") and pass the user’s identifier to the creating and deleting repository functions.
Updating routes
Update app.js to protect the post and comment API routes that are responsible for creating and deleting using the authenticate-middleware.
Note: You don’t want to use authenticate-middleware for GET request API since we still want users who are not logged in to see our posts and comments.
Submission
Once ready, zip the contents of the server folder of your overarching project and submit the zip file below. The controllers folder should be at the root of the zip file. The expected file structure of the project is as follows.
Follow the names exactly as given, as the automated tests will check for them. Your project may have additional files (e.g., Dockerfile, deno.json).
.├── controllers│ ├── commentController.js (updated)│ ├── postController.js (updated)│ └── ...├── repositories│ ├── commentRepository.js (updated)│ ├── postRepository.js (updated)│ └── ...├── app-run.js├── app.js (updated)└── middlewares.jsFinally, in the fifteenth step, you will add the client-side functionality for restricting the interaction with posts and comments.
WSD Overarching Project, Step 15
0 / 25 points
In this step, focusing on client-side functionality, you will integrate authentication into your client-side application so that the users can only perform certain actions on the posts and comments when they are logged in, update to post and comment API to use authenticated requests, and add a visible constraint between non-users and users when interacting with posts and comments. After this step, your client-side application should have the following functionalities:
- Post and comment APIs module using an authenticated request.
- Visibility constraints for non-user vs user in posts lists, and post forms.
- Visibility constraints for non-user vs user in comments lists, and comments forms.
Tasks
The task is divided into parts to help structure your work. Each part corresponds to a specific module or component with its own responsibilities.
Modifying the post and comments API module
Modify the posts and comments API module postsApi.js and commentsApi.js file so that it uses authenticated requests when performing create and delete actions. Use the authFetch helper function from the fetchUtils.js module.
Noted: Do not use
authFetchfor other API that do aGETrequest since we still want our non-user (users that do not log in) to still see the posts and comments.
Modifying the post and comments list
Modify the PostList.svelte and CommentList.svelte files so that the remove button is only visible if the one who created it is the same as the one who is logged in. You do this by comparing the field created_by of the data object with the userId from authState.
Modifying the post and comments form
Modify the PostForm.svelte and CommentForm.svelte file so that the forms are only visible when the user is logged in.
Submission
Once ready, zip the contents of your client/src folder and submit the zip file below. The routes folder should be at the root of the zip file. Follow the file and folder names exactly, as automated tests depend on them.
Your project may include additional files (e.g., Dockerfile, deno.json).
Expected file structure:
.├── lib│ └── apis│ │ ├── commentsApi.js (updated)│ │ ├── postsApi.js (updated)│ │ └── ...│ ├── components│ │ ├── comments│ │ │ ├── CommentForm.svelte (updated)│ │ │ └── CommentList.svelte (updated)│ │ ├── posts│ │ │ ├── PostForm.svelte (updated)│ │ │ ├── PostList.svelte (updated)│ │ │ └── ...│ │ └── ...│ ├── states│ └── ...└── routes ├── auth │ └── ... ├── communities │ └── ... ├── +layout.svelte └── +page.svelte