diff --git a/.DS_Store b/.DS_Store index 14bbbe7d0..907524415 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/week-3/02-course-app-easy-2/index.js b/week-3/02-course-app-easy-2/index.js index 32fff61e9..797c2ee1b 100644 --- a/week-3/02-course-app-easy-2/index.js +++ b/week-3/02-course-app-easy-2/index.js @@ -1,4 +1,5 @@ const express = require('express'); +const jwt = require('jsonwebtoken'); const app = express(); app.use(express.json()); @@ -7,46 +8,169 @@ let ADMINS = []; let USERS = []; let COURSES = []; +const secretKey = "My-Secret-Key"; + +const generateJwt = (user) => { + const payload = {username: user.username}; + return jwt.sign(payload, secretKey, {expiresIn: '1h'}); +}; + +const authenticateJwt = (req, res, next) => { + const authHeader = req.headers.authorization; + + if(authHeader){ + const token = authHeader.split(' ')[1]; + + jwt.verify(token, secretKey, (err, user) => { + if(err){ + return res.status(403); + } + + req.user = user; + next(); + }); + } + + else{ + res.status(401); + } +}; + // Admin routes app.post('/admin/signup', (req, res) => { // logic to sign up admin + const admin = req.body; + const existingAdmin = ADMINS.find(a => a.username === admin.username); + + if(existingAdmin){ + res.status(403).json({message: 'Admin already exists'}); + } + + else{ + ADMINS.push(admin); + const token = generateJwt(admin.username); + res.json({message: 'Admin created successfully', token}); + } }); app.post('/admin/login', (req, res) => { // logic to log in admin + const {username, password} = req.headers; + const admin = ADMINS.find(a => a.username === username && a.password === password); + + if(admin){ + const token = generateJwt(admin.username); + res.json({message: 'Logged in succcessfully', token}); + } + + else{ + res.status(403).json({message: 'Admin authentication failed'}); + } }); -app.post('/admin/courses', (req, res) => { +app.post('/admin/courses', authenticateJwt, (req, res) => { // logic to create a course + const course = req.body; + course.id = COURSES.length + 1; + COURSES.push(course); + res.json({message: 'course created successfully', courseId: course.id}); }); -app.put('/admin/courses/:courseId', (req, res) => { +app.put('/admin/courses/:courseId', authenticateJwt, (req, res) => { // logic to edit a course + const courseId = parseInt(req.params.courseId); + const courseIndex = COURSES.findIndex(c => c.id === courseId); + + if(courseIndex > -1){ + const updatedCourse = { ...COURSES[courseIndex], ...req.body}; + COURSES[courseIndex] = updatedCourse; + res.json({message: 'Course updated successfully'}); + } + + else{ + res.status(404).json({message: 'Course not found'}); + } }); app.get('/admin/courses', (req, res) => { // logic to get all courses + res.json({courses: COURSES}); }); // User routes app.post('/users/signup', (req, res) => { // logic to sign up user + const user = req.body; + const existingUser = USERS.find(u => u.username === user.username); + + if(existingUser){ + res.status(403).json({message: 'User already exists'}); + } + + else{ + USERS.push(user); + const token = generateJwt(user.username); + res.json({message: 'User created successfully'}); + } }); app.post('/users/login', (req, res) => { // logic to log in user + const {username, password} = req.headers; + const user = USERS.find(u => u.username === username && u.password === password); + + if(user){ + const token = generateJwt(user.username); + res.json({message: 'Logged in successfully'}); + } + + else{ + res.status(403).json({message: 'User authentication failed'}); + } }); -app.get('/users/courses', (req, res) => { +app.get('/users/courses', authenticateJwt, (req, res) => { // logic to list all courses + res.json({courses: COURSES}); }); -app.post('/users/courses/:courseId', (req, res) => { +app.post('/users/courses/:courseId', authenticateJwt, (req, res) => { // logic to purchase a course + const courseId = parseInt(req.params.courseId); + const course = COURSES.find(c => c.id === courseId); + + if(course){ + const user = USERS.find(u => u.username === req.user.username); + + if(user){ + if(!user.purchasedCourses){ + user.purchasedCourses = []; + } + + user.purchasedCourses.push(course); + res.json({message: 'Course purchased successfully'}); + } + + else{ + res.status(403).json({message: 'User not found'}); + } + } + + else{ + res.status(404).json({message: 'Course not found'}); + } }); -app.get('/users/purchasedCourses', (req, res) => { +app.get('/users/purchasedCourses', authenticateJwt, (req, res) => { // logic to view purchased courses + const user = USERS.find(u => u.username === req.user.username); + if(user && user.purchasedCourses){ + res.json({purchasedCourses: user.purchasedCourses}); + } + + else{ + res.status(404).json({message: 'No courses purchased'}); + } }); app.listen(3000, () => { diff --git a/week-3/02-course-app-easy/index.js b/week-3/02-course-app-easy/index.js index 32fff61e9..783b718ca 100644 --- a/week-3/02-course-app-easy/index.js +++ b/week-3/02-course-app-easy/index.js @@ -6,47 +6,151 @@ app.use(express.json()); let ADMINS = []; let USERS = []; let COURSES = []; +let userPurchases = []; // Admin routes app.post('/admin/signup', (req, res) => { // logic to sign up admin + var details = req.body; + var flag = false; + + for(let i=0;i { // logic to log in admin + var usernameCheck = req.headers.username; + var passwordCheck = req.headers.password; + var flag = false; + + for(let i=0;i { // logic to create a course + var courseDetails = req.body; + courseDetails.id = Date.now; + + COURSES.push(courseDetails); + res.status(200).json('Course created successfully'); }); app.put('/admin/courses/:courseId', (req, res) => { // logic to edit a course + var cid = req.params.courseId; + var updatedDetails = req.body; + + for(let i=0;i { // logic to get all courses + res.status(200).json(COURSES); }); // User routes app.post('/users/signup', (req, res) => { // logic to sign up user + var userDetails = req.body; + var flag = false; + + for(let i=0;i { // logic to log in user + var usernameCheck = req.headers.username; + var passwordCheck = req.headers.password; + + var flag = false; + + for(let i=0;i { // logic to list all courses + res.status(200).json(COURSES); }); app.post('/users/courses/:courseId', (req, res) => { // logic to purchase a course + var idOfCourse = req.params.courseId; + + for(let i=0;i { // logic to view purchased courses + res.status(200).json(userPurchases); }); app.listen(3000, () => { diff --git a/week-3/03-course-app-medium/admins.json b/week-3/03-course-app-medium/admins.json new file mode 100644 index 000000000..e69de29bb diff --git a/week-3/03-course-app-medium/courses.json b/week-3/03-course-app-medium/courses.json new file mode 100644 index 000000000..e69de29bb diff --git a/week-3/03-course-app-medium/index.js b/week-3/03-course-app-medium/index.js index 32fff61e9..1e9173580 100644 --- a/week-3/03-course-app-medium/index.js +++ b/week-3/03-course-app-medium/index.js @@ -1,4 +1,6 @@ const express = require('express'); +const jwt = require('jsonwebtoken'); +const fs = require('fs'); const app = express(); app.use(express.json()); @@ -7,46 +9,145 @@ let ADMINS = []; let USERS = []; let COURSES = []; +try{ + ADMINS = JSON.parse(fs.readFileSync('admins.json', 'utf-8')); + USERS = JSON.parse(fs.readFileSync('users.json', 'utf-8')); + COURSES = JSON.parse(fs.readFileSync('courses.json', 'utf-8')); +} +catch{ + ADMINS = []; + USERS = []; + COURSES = []; +} +//console.log(ADMINS); + +const SECRET = 'my-secret-key'; + +const authenticateJwt = (req, res, next) => { + const authHeader = req.headers.authorization; + if(authHeader){ + const token = authHeader.split(' ')[1]; + jwt.verify(token, SECRET, (err, user) => { + if(err){ + return res.status(403); + } + + req.user = user; + next(); + }); + } + + else{ + res.status(401); + } +}; + // Admin routes app.post('/admin/signup', (req, res) => { - // logic to sign up admin + const { username, password } = req.body; + const admin = ADMINS.find(a => a.username === username); + console.log("admin signup"); + if (admin) { + res.status(403).json({ message: 'Admin already exists' }); + } else { + const newAdmin = { username, password }; + ADMINS.push(newAdmin); + fs.writeFileSync('admins.json', JSON.stringify(ADMINS)); + const token = jwt.sign({ username, role: 'admin' }, SECRET, { expiresIn: '1h' }); + res.json({ message: 'Admin created successfully', token }); + } }); app.post('/admin/login', (req, res) => { - // logic to log in admin + const { username, password } = req.headers; + const admin = ADMINS.find(a => a.username === username && a.password === password); + if (admin) { + const token = jwt.sign({ username, role: 'admin' }, SECRET, { expiresIn: '1h' }); + res.json({ message: 'Logged in successfully', token }); + } else { + res.status(403).json({ message: 'Invalid username or password' }); + } }); -app.post('/admin/courses', (req, res) => { - // logic to create a course +app.post('/admin/courses', authenticateJwt, (req, res) => { + const course = req.body; + course.id = COURSES.length + 1; + COURSES.push(course); + fs.writeFileSync('courses.json', JSON.stringify(COURSES)); + res.json({ message: 'Course created successfully', courseId: course.id }); }); -app.put('/admin/courses/:courseId', (req, res) => { - // logic to edit a course +app.put('/admin/courses/:courseId', authenticateJwt, (req, res) => { + const course = COURSES.find(c => c.id === parseInt(req.params.courseId)); + if (course) { + Object.assign(course, req.body); + fs.writeFileSync('courses.json', JSON.stringify(COURSES)); + res.json({ message: 'Course updated successfully' }); + } else { + res.status(404).json({ message: 'Course not found' }); + } }); -app.get('/admin/courses', (req, res) => { - // logic to get all courses +app.get('/admin/courses', authenticateJwt, (req, res) => { + res.json({ courses: COURSES }); }); // User routes app.post('/users/signup', (req, res) => { - // logic to sign up user + const { username, password } = req.body; + const user = USERS.find(u => u.username === username); + if (user) { + res.status(403).json({ message: 'User already exists' }); + } else { + const newUser = { username, password }; + USERS.push(newUser); + fs.writeFileSync('users.json', JSON.stringify(USERS)); + const token = jwt.sign({ username, role: 'user' }, SECRET, { expiresIn: '1h' }); + res.json({ message: 'User created successfully', token }); + } }); app.post('/users/login', (req, res) => { - // logic to log in user + const { username, password } = req.headers; + const user = USERS.find(u => u.username === username && u.password === password); + if (user) { + const token = jwt.sign({ username, role: 'user' }, SECRET, { expiresIn: '1h' }); + res.json({ message: 'Logged in successfully', token }); + } else { + res.status(403).json({ message: 'Invalid username or password' }); + } }); -app.get('/users/courses', (req, res) => { - // logic to list all courses +app.get('/users/courses', authenticateJwt, (req, res) => { + res.json({ courses: COURSES }); }); -app.post('/users/courses/:courseId', (req, res) => { - // logic to purchase a course +app.post('/users/courses/:courseId', authenticateJwt, (req, res) => { + const course = COURSES.find(c => c.id === parseInt(req.params.courseId)); + if (course) { + const user = USERS.find(u => u.username === req.user.username); + if (user) { + if (!user.purchasedCourses) { + user.purchasedCourses = []; + } + user.purchasedCourses.push(course); + fs.writeFileSync('users.json', JSON.stringify(USERS)); + res.json({ message: 'Course purchased successfully' }); + } else { + res.status(403).json({ message: 'User not found' }); + } + } else { + res.status(404).json({ message: 'Course not found' }); + } }); -app.get('/users/purchasedCourses', (req, res) => { - // logic to view purchased courses +app.get('/users/purchasedCourses', authenticateJwt, (req, res) => { + const user = USERS.find(u => u.username === req.user.username); + if (user) { + res.json({ purchasedCourses: user.purchasedCourses || [] }); + } else { + res.status(403).json({ message: 'User not found' }); + } }); app.listen(3000, () => { diff --git a/week-3/03-course-app-medium/users.json b/week-3/03-course-app-medium/users.json new file mode 100644 index 000000000..e69de29bb diff --git a/week-3/04-course-app-hard/index.js b/week-3/04-course-app-hard/index.js index 32fff61e9..2bdead037 100644 --- a/week-3/04-course-app-hard/index.js +++ b/week-3/04-course-app-hard/index.js @@ -1,52 +1,184 @@ const express = require('express'); +const jwt = require('jsonwebtoken'); +const mongoose = require('mongoose'); const app = express(); app.use(express.json()); -let ADMINS = []; -let USERS = []; -let COURSES = []; +const SECRET = 'my-secret-key'; + +//define mongoose schemas +const userSchema = new mongoose.Schema({ + username: String, + password: String, + purchasedCourses: [{type: mongoose.Schema.Types.ObjectId, ref: 'Course'}] +}); + +const adminSchema = new mongoose.Schema({ + username: String, + password: String +}); + +const courseSchema = new mongoose.Schema({ + title: String, + description: String, + price: Number, + imageLink: String, + published: Boolean +}); + +//define mongoose models +const User = mongoose.model('User', userSchema); +const Admin = mongoose.model('Admin', adminSchema); +const Course = mongoose.model('Course', courseSchema); + +const authenticateJwt = (req, res, next) => { + const authHeader = req.headers.authorization; + + if(authHeader){ + const token = authHeader.split(' ')[1]; + jwt.verify(token, SECRET, (err, user) => { + if(err){ + return res.status(403); + } + + res.user = user; + next(); + }); + } + + else{ + res.status(401); + } +}; + +//connect to MongoDB +mongoose.connect('mongodb+srv://koustubhlap:kond018@koustubh18.qmw1c9a.mongodb.net/', {dbName: "courses"}); // Admin routes app.post('/admin/signup', (req, res) => { // logic to sign up admin + const {username, password} = req.body; + function callback(admin){ + if(admin){ + res.status(403).json({message: 'Admin already exists'}); + } + else{ + const obj = {username: username, password: password}; + const newAdmin = new Admin(obj); + newAdmin.save(); + const token = jwt.sign({username, role: 'admin'}, SECRET, {expiresIn: '1h'}); + res.json({message: 'Admin created successfully'}); + } + } + + Admin.findOne({username}).then(callback); }); -app.post('/admin/login', (req, res) => { +app.post('/admin/login', async (req, res) => { // logic to log in admin + const {username, password} = req.headers; + const admin = await Admin.findOne({username, password}); + + if(admin){ + const token = jwt.sign({username, role: 'admin'}, SECRET, {expiresIn: '1h'}); + res.json({message: 'Logged in successfully', token}); + } + + else{ + res.status(403).json({message: 'Invalid username or password'}); + } }); -app.post('/admin/courses', (req, res) => { +app.post('/admin/courses', authenticateJwt, async (req, res) => { // logic to create a course + const course = new Course(req.body); + await course.save(); + res.json({message: 'Course created successfully', courseId: course.id}); }); -app.put('/admin/courses/:courseId', (req, res) => { +app.put('/admin/courses/:courseId', authenticateJwt, async (req, res) => { // logic to edit a course + const course = await Course.findByIdAndUpdate(req.params.courseId, req.body, {new: true}); + + if(course){ + req.json({message: 'Course updated successfully'}); + } + + else{ + res.status(404).json({message: 'Course not found'}); + } }); -app.get('/admin/courses', (req, res) => { +app.get('/admin/courses', authenticateJwt, async (req, res) => { // logic to get all courses + const courses = await Course.find({}); + res.json({courses}); }); // User routes -app.post('/users/signup', (req, res) => { +app.post('/users/signup', async (req, res) => { // logic to sign up user + const {username, password} = req.body; + const user = await User.findOne({username}); + + if(user){ + res.status(403).json({message: 'User already exists'}); + } + + else{ + const newUser = new User({username, password}); + await newUser.save(); + const token = jwt.sign({username, role: 'user'}, SECRET, {expiresIn: '1h'}); + res.json({message: 'User created successfully'}); + } }); -app.post('/users/login', (req, res) => { +app.post('/users/login', async (req, res) => { // logic to log in user + const {username, password} = req.headers; + const user = await User.findOne({username, password}); + + if(user){ + const token = jwt.sign({username, role: 'user'}, SECRET, {expiresIn: '1h'}); + res.json({message: 'Logged in successfully'}); + } + + else{ + res.status(403).json({message: 'Invalid username or password'}); + } }); -app.get('/users/courses', (req, res) => { +app.get('/users/courses', authenticateJwt, async (req, res) => { // logic to list all courses + const courses = await Course.find({published: true}); + res.json({courses}); }); -app.post('/users/courses/:courseId', (req, res) => { - // logic to purchase a course +app.post('/users/courses/:courseId', authenticateJwt, async (req, res) => { + const course = await Course.findById(req.params.courseId); + console.log(course); + if (course) { + const user = await User.findOne({ username: req.user.username }); + if (user) { + user.purchasedCourses.push(course); + await user.save(); + res.json({ message: 'Course purchased successfully' }); + } else { + res.status(403).json({ message: 'User not found' }); + } + } else { + res.status(404).json({ message: 'Course not found' }); + } }); -app.get('/users/purchasedCourses', (req, res) => { - // logic to view purchased courses +app.get('/users/purchasedCourses', authenticateJwt, async (req, res) => { + const user = await User.findOne({ username: req.user.username }).populate('purchasedCourses'); + if (user) { + res.json({ purchasedCourses: user.purchasedCourses || [] }); + } else { + res.status(403).json({ message: 'User not found' }); + } }); app.listen(3000, () => { diff --git a/week-4/01-easy-todo-app/src/App.jsx b/week-4/01-easy-todo-app/src/App.jsx index c949df883..3dae191f3 100644 --- a/week-4/01-easy-todo-app/src/App.jsx +++ b/week-4/01-easy-todo-app/src/App.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import React, { useState, useEffect } from 'react' import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import './App.css' @@ -6,12 +6,40 @@ import './App.css' function App() { const [todos, setTodos] = useState([]) // fetch all todos from server + React.useEffect(() => { + fetch('http://localhost:3000', { + method: 'GET' + }).then((response) => { + response.json().then((todo) => { + setTodos(todo); + }) + }) + + setInterval(() => { + fetch('http://localhost:3000', { + method: 'GET' + }).then((response) => { + response.json().then((todo) => { + setTodos(todo); + }) + }) + }, 1000) + + }, []); return ( <>

Easy Todo App

+ {todos.map((value) => { + return <> + {value.title} + {value.description} + +

+ + })}
) diff --git a/week-4/01-easy-todo-app/todoServer.solution.js b/week-4/01-easy-todo-app/todoServer.solution.js new file mode 100644 index 000000000..d348f4a8d --- /dev/null +++ b/week-4/01-easy-todo-app/todoServer.solution.js @@ -0,0 +1,107 @@ +/** + You need to create an express HTTP server in Node.js which will handle the logic of a todo list app. + - Don't use any database, just store all the data in an array to store the todo list data (in-memory) + - Hard todo: Try to save responses in files, so that even if u exit the app and run it again, the data remains (similar to databases) + + Each todo has a title and a description. The title is a string and the description is a string. + Each todo should also get an unique autogenerated id every time it is created + The expected API endpoints are defined below, + 1.GET /todos - Retrieve all todo items + Description: Returns a list of all todo items. + Response: 200 OK with an array of todo items in JSON format. + Example: GET http://localhost:3000/todos + + 2.GET /todos/:id - Retrieve a specific todo item by ID + Description: Returns a specific todo item identified by its ID. + Response: 200 OK with the todo item in JSON format if found, or 404 Not Found if not found. + Example: GET http://localhost:3000/todos/123 + + 3. POST /todos - Create a new todo item + Description: Creates a new todo item. + Request Body: JSON object representing the todo item. + Response: 201 Created with the ID of the created todo item in JSON format. eg: {id: 1} + Example: POST http://localhost:3000/todos + Request Body: { "title": "Buy groceries", "completed": false, description: "I should buy groceries" } + + 4. PUT /todos/:id - Update an existing todo item by ID + Description: Updates an existing todo item identified by its ID. + Request Body: JSON object representing the updated todo item. + Response: 200 OK if the todo item was found and updated, or 404 Not Found if not found. + Example: PUT http://localhost:3000/todos/123 + Request Body: { "title": "Buy groceries", "completed": true } + + 5. DELETE /todos/:id - Delete a todo item by ID + Description: Deletes a todo item identified by its ID. + Response: 200 OK if the todo item was found and deleted, or 404 Not Found if not found. + Example: DELETE http://localhost:3000/todos/123 + + - For any other route not defined in the server return 404 + + Testing the server - run `npm run test-todoServer` command in terminal + */ +const express = require('express'); +const bodyParser = require('body-parser'); +const cors = require('cors'); + +const app = express(); + +app.use(cors()); + +app.use(bodyParser.json()); + +let todos = []; + +app.get('/todos', (req, res) => { + res.json(todos); +}); + +app.get('/todos/:id', (req, res) => { + const todo = todos.find(t => t.id === parseInt(req.params.id)); + if (!todo) { + res.status(404).send(); + } else { + res.json(todo); + } +}); + +app.post('/todos', (req, res) => { + const newTodo = { + id: Math.floor(Math.random() * 1000000), // unique random id + title: req.body.title, + description: req.body.description + }; + todos.push(newTodo); + res.status(201).json(newTodo); +}); + +app.put('/todos/:id', (req, res) => { + const todoIndex = todos.findIndex(t => t.id === parseInt(req.params.id)); + if (todoIndex === -1) { + res.status(404).send(); + } else { + todos[todoIndex].title = req.body.title; + todos[todoIndex].description = req.body.description; + res.json(todos[todoIndex]); + } +}); + +app.delete('/todos/:id', (req, res) => { + const todoIndex = todos.findIndex(t => t.id === parseInt(req.params.id)); + if (todoIndex === -1) { + res.status(404).send(); + } else { + todos.splice(todoIndex, 1); + res.status(200).send(); + } +}); + +// for all other routes, return 404 +app.use((req, res, next) => { + res.status(404).send(); +}); + +app.listen(() => { + console.log('Todo Server listening on port 3000'); +}, 3000); + +module.exports = app; diff --git a/week-7/assignment-1/db/index.js b/week-7/assignment-1/db/index.ts similarity index 80% rename from week-7/assignment-1/db/index.js rename to week-7/assignment-1/db/index.ts index 5dda977c5..419a59ea4 100644 --- a/week-7/assignment-1/db/index.js +++ b/week-7/assignment-1/db/index.ts @@ -1,4 +1,4 @@ -const mongoose = require("mongoose"); +import mongoose from "mongoose"; const userSchema = new mongoose.Schema({ username: String, @@ -15,7 +15,4 @@ const todoSchema = new mongoose.Schema({ const User = mongoose.model('User', userSchema); const Todo = mongoose.model('Todo', todoSchema); -module.exports = { - User, - Todo -} \ No newline at end of file +export default {User, Todo}; \ No newline at end of file diff --git a/week-7/assignment-1/index.js b/week-7/assignment-1/index.ts similarity index 80% rename from week-7/assignment-1/index.js rename to week-7/assignment-1/index.ts index f20939843..7f5a65fee 100644 --- a/week-7/assignment-1/index.js +++ b/week-7/assignment-1/index.ts @@ -16,4 +16,4 @@ app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) -mongoose.connect('mongodb://localhost:27017/courses', { dbName: "courses" }); +mongoose.connect('mongodb+srv://koustubhlap:kond018@koustubh18.qmw1c9a.mongodb.net/', { dbName: "Todos" }); diff --git a/week-7/assignment-1/middleware/index.js b/week-7/assignment-1/middleware/index.ts similarity index 89% rename from week-7/assignment-1/middleware/index.js rename to week-7/assignment-1/middleware/index.ts index 221f83f4b..4d2f39456 100644 --- a/week-7/assignment-1/middleware/index.js +++ b/week-7/assignment-1/middleware/index.ts @@ -1,6 +1,6 @@ const jwt = require('jsonwebtoken'); const { Response } = require('express'); -const SECRET = 'SECr3t'; // This should be in an environment variable in a real application +const SECRET = 'secret'; // This should be in an environment variable in a real application const authenticateJwt = (req, res, next) => { const authHeader = req.headers.authorization; diff --git a/week-7/assignment-1/package-lock.json b/week-7/assignment-1/package-lock.json index 25aec70ab..a72fee059 100644 --- a/week-7/assignment-1/package-lock.json +++ b/week-7/assignment-1/package-lock.json @@ -13,12 +13,118 @@ "express": "^4.18.2", "jsonwebtoken": "^9.0.1", "mongoose": "^7.4.1" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/mongoose": "^5.11.97", + "@types/node": "^20.11.16" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/mongoose": { + "version": "5.11.97", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", + "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", + "deprecated": "Mongoose publishes its own types, so you do not need to install this package.", + "dev": true, + "dependencies": { + "mongoose": "*" } }, "node_modules/@types/node": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.4.tgz", - "integrity": "sha512-CukZhumInROvLq3+b5gLev+vgpsIqC2D0deQr/yS1WnxvmYLlJXZpaQrQiseMY+6xusl79E04UjWoqyr+t1/Ew==" + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } }, "node_modules/@types/webidl-conversions": { "version": "7.0.0", @@ -909,6 +1015,11 @@ "node": ">= 0.6" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -960,10 +1071,110 @@ } }, "dependencies": { + "@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "@types/mongoose": { + "version": "5.11.97", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", + "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", + "dev": true, + "requires": { + "mongoose": "*" + } + }, "@types/node": { - "version": "20.4.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.4.tgz", - "integrity": "sha512-CukZhumInROvLq3+b5gLev+vgpsIqC2D0deQr/yS1WnxvmYLlJXZpaQrQiseMY+6xusl79E04UjWoqyr+t1/Ew==" + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } }, "@types/webidl-conversions": { "version": "7.0.0", @@ -1619,6 +1830,11 @@ "mime-types": "~2.1.24" } }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/week-7/assignment-1/package.json b/week-7/assignment-1/package.json index 422e2f636..93e5423f4 100644 --- a/week-7/assignment-1/package.json +++ b/week-7/assignment-1/package.json @@ -14,5 +14,10 @@ "express": "^4.18.2", "jsonwebtoken": "^9.0.1", "mongoose": "^7.4.1" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/mongoose": "^5.11.97", + "@types/node": "^20.11.16" } } diff --git a/week-7/assignment-1/routes/auth.js b/week-7/assignment-1/routes/auth.ts similarity index 100% rename from week-7/assignment-1/routes/auth.js rename to week-7/assignment-1/routes/auth.ts diff --git a/week-7/assignment-1/routes/todo.js b/week-7/assignment-1/routes/todo.ts similarity index 100% rename from week-7/assignment-1/routes/todo.js rename to week-7/assignment-1/routes/todo.ts diff --git a/week-7/assignment-1/tsconfig.json b/week-7/assignment-1/tsconfig.json new file mode 100644 index 000000000..9ef3a5def --- /dev/null +++ b/week-7/assignment-1/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}