| @@ -11,6 +11,7 @@ authRoutes.post('/register/', async (request, response) => { | |||||
| const email: string = request.body.email; | const email: string = request.body.email; | ||||
| const password: string = request.body.password; | const password: string = request.body.password; | ||||
| const isVerified: boolean = false; | const isVerified: boolean = false; | ||||
| const userCollection = getDatabaseClient().db(DB_NAME).collection('users'); | const userCollection = getDatabaseClient().db(DB_NAME).collection('users'); | ||||
| // Check if form is filled | // Check if form is filled | ||||
| @@ -4,10 +4,10 @@ export interface Category { | |||||
| _id: string, | _id: string, | ||||
| name: string, | name: string, | ||||
| icon: string, | icon: string, | ||||
| shelves: Array<Shelf>, | |||||
| shelves?: Array<Shelf>, | |||||
| isArchived: boolean, | isArchived: boolean, | ||||
| } | } | ||||
| export interface MongoCategory extends Omit<Category, 'shelves'> { | export interface MongoCategory extends Omit<Category, 'shelves'> { | ||||
| shelves: Array<string>, // Ids | |||||
| shelves?: Array<string>, // Shelf IDs | |||||
| } | } | ||||
| @@ -1,16 +1,14 @@ | |||||
| import { LanguageType } from "./variables"; | import { LanguageType } from "./variables"; | ||||
| import { Word } from "./word"; | import { Word } from "./word"; | ||||
| export interface Library { | export interface Library { | ||||
| _id: string, | _id: string, | ||||
| languageType: LanguageType, | languageType: LanguageType, | ||||
| isArchived: boolean, | isArchived: boolean, | ||||
| allWords: Array<{ | |||||
| word: Word, | |||||
| isArchived: boolean, | |||||
| wordStats: { | |||||
| favouriteCount: number, // Total users who liked this word | |||||
| addCount: number, // Total users have added this word to their shelf | |||||
| } | |||||
| }>, | |||||
| allWords: Array<Word>, | |||||
| } | |||||
| export interface MongoLibrary extends Omit<Library, "allWords"> { | |||||
| allWords: Array<string> // Word IDs | |||||
| } | } | ||||
| @@ -1,24 +1,17 @@ | |||||
| import { Category } from "./category"; | import { Category } from "./category"; | ||||
| import { Shelf } from "./shelf"; | import { Shelf } from "./shelf"; | ||||
| export interface IUser { | |||||
| export interface User { | |||||
| _id: string, | _id: string, | ||||
| name: string, | name: string, | ||||
| email: string, | email: string, | ||||
| password: string, | password: string, | ||||
| isVerified: boolean, | isVerified: boolean, | ||||
| otp: number, | otp: number, | ||||
| categories: Array<Category>, | |||||
| uncategorised: Shelf, | |||||
| categories?: Array<Category>, | |||||
| uncategorised?: Shelf, | |||||
| } | } | ||||
| export interface MongoIUser { | |||||
| _id: string, | |||||
| name: string, | |||||
| email: string, | |||||
| password: string, | |||||
| isVerified: boolean, | |||||
| otp: number, | |||||
| categories: Array<string>, //Array of IDs | |||||
| uncategorised: string, // Shelf ID | |||||
| export interface MongoUser extends Omit<User, "categories"> { | |||||
| categories?: Array<string> // Category IDs | |||||
| } | } | ||||
| @@ -1,16 +1,27 @@ | |||||
| import { grammarType } from "./variables"; | import { grammarType } from "./variables"; | ||||
| interface gramaticalDetail { | |||||
| type: grammarType, | |||||
| description: string, | |||||
| examples: Array<string>, | |||||
| } | |||||
| export interface Word { | export interface Word { | ||||
| _id: string, | _id: string, | ||||
| name: string, | name: string, | ||||
| pronounciation: { | pronounciation: { | ||||
| text: string, | text: string, | ||||
| audio: string, | |||||
| audio?: string, | |||||
| }, | |||||
| similarWords?: Array<Word>, | |||||
| grammaticalDetails: Array<gramaticalDetail>, | |||||
| wordStats: { | |||||
| favouriteCount: number, // Total users who liked this word | |||||
| addCount: number, // Total users have added this word to their shelf | |||||
| }, | }, | ||||
| similarWords: Array<Word>, | |||||
| grammaticalDetails: Array<{ | |||||
| type: grammarType, | |||||
| description: string, | |||||
| examples: Array<string>, | |||||
| }> | |||||
| isArchived: boolean, | |||||
| } | |||||
| export interface MongoWord extends Omit<Word, "similarWords"> { | |||||
| similarWords: Array<string> | |||||
| } | } | ||||
| @@ -1,13 +1,13 @@ | |||||
| import express from 'express'; | import express from 'express'; | ||||
| import passport from 'passport'; | import passport from 'passport'; | ||||
| import { IUser } from '../models/user'; | |||||
| import { User } from '../models/user'; | |||||
| export const revisionRoutes = express.Router(); | export const revisionRoutes = express.Router(); | ||||
| export const jwtAuthentication = passport.authenticate('jwt', { session: false }); | export const jwtAuthentication = passport.authenticate('jwt', { session: false }); | ||||
| revisionRoutes.get('/revision-questions/', jwtAuthentication, async (request, response) => { | revisionRoutes.get('/revision-questions/', jwtAuthentication, async (request, response) => { | ||||
| const user: IUser = (request.user as any); | |||||
| const user: User = (request.user as any); | |||||
| // TODO: Revision logic | // TODO: Revision logic | ||||
| @@ -1,17 +1,17 @@ | |||||
| import express from 'express'; | import express from 'express'; | ||||
| import passport from 'passport'; | |||||
| import { IUser } from '../models/user'; | |||||
| import { v4 as uuidv4 } from 'uuid'; | |||||
| import { Category } from '../models/category'; | |||||
| import passport, { use } from 'passport'; | |||||
| import { MongoUser } from '../models/user'; | |||||
| import { Category, MongoCategory } from '../models/category'; | |||||
| import { DB_NAME } from '../db-utils'; | import { DB_NAME } from '../db-utils'; | ||||
| import { getDatabaseClient } from '../db-utils'; | import { getDatabaseClient } from '../db-utils'; | ||||
| import { ObjectId } from 'bson'; | |||||
| export const userProfileRoutes = express.Router(); | export const userProfileRoutes = express.Router(); | ||||
| export const jwtAuthentication = passport.authenticate('jwt', { session: false }); | export const jwtAuthentication = passport.authenticate('jwt', { session: false }); | ||||
| userProfileRoutes.get('/profile/', jwtAuthentication, async (request, response) => { | userProfileRoutes.get('/profile/', jwtAuthentication, async (request, response) => { | ||||
| const user: IUser = (request.user as any); | |||||
| const user: MongoUser = (request.user as any); | |||||
| response.json({ | response.json({ | ||||
| _id: user._id, | _id: user._id, | ||||
| name: user.name, | name: user.name, | ||||
| @@ -23,21 +23,91 @@ userProfileRoutes.get('/profile/', jwtAuthentication, async (request, response) | |||||
| return; | return; | ||||
| }); | }); | ||||
| userProfileRoutes.post('/category/', jwtAuthentication, async (request, response) => { | userProfileRoutes.post('/category/', jwtAuthentication, async (request, response) => { | ||||
| const user: IUser = (request.user as any); | |||||
| const user: MongoUser = (request.user as any); | |||||
| const userCollection = getDatabaseClient().db(DB_NAME).collection('categories'); | |||||
| const categoryCollection = getDatabaseClient().db(DB_NAME).collection('categories'); | |||||
| const userCollection = getDatabaseClient().db(DB_NAME).collection('users'); | |||||
| const newCategory: Category = { | |||||
| _id: uuidv4(), | |||||
| name: request.body.name, | |||||
| icon: request.body.icon, | |||||
| shelves: [], | |||||
| isArchived: false, | |||||
| if (!request.body.name || !request.body.icon) { | |||||
| response.status(400); | |||||
| response.send("Category Name or icon(base64) missing"); | |||||
| return; | |||||
| } | } | ||||
| response.status(200); | |||||
| try { | |||||
| const newCategory = await categoryCollection.insertOne({ | |||||
| name: request.body.name, | |||||
| icon: request.body.icon, | |||||
| isArchived: false, | |||||
| }); | |||||
| if (!user.categories) { | |||||
| user.categories = []; | |||||
| } | |||||
| user.categories.push(newCategory.insertedId.toHexString()); | |||||
| await userCollection.updateOne({ | |||||
| _id: user._id | |||||
| }, { | |||||
| $set: { | |||||
| categories: user.categories | |||||
| } | |||||
| }); | |||||
| response.sendStatus(200); | |||||
| } catch(e) { | |||||
| response.sendStatus(500); | |||||
| return; | |||||
| } | |||||
| return; | |||||
| }); | |||||
| userProfileRoutes.put('/category/', jwtAuthentication, async (request, response) => { | |||||
| const categoryCollection = getDatabaseClient().db(DB_NAME).collection('categories'); | |||||
| let currentCategory; | |||||
| try { | |||||
| currentCategory = await categoryCollection.findOne({ | |||||
| _id: new ObjectId(request.body._id) | |||||
| }); | |||||
| } catch { | |||||
| if (!currentCategory) { | |||||
| response.status(400); | |||||
| response.send("Category ID did not match"); | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (request.body.isArchived) { | |||||
| if (typeof request.body.isArchived !== "boolean") { | |||||
| response.status(400); | |||||
| response.send("Archived should be a boolean flag"); | |||||
| return; | |||||
| } | |||||
| } | |||||
| try { | |||||
| await categoryCollection.updateOne({ | |||||
| _id: new ObjectId(request.body._id), | |||||
| }, { | |||||
| $set: { | |||||
| name: request.body.name ? request.body.name : currentCategory.name, | |||||
| icon: request.body.icon ? request.body.icon : currentCategory.icon, | |||||
| isArchived: request.body.isArchived !== undefined ? request.body.isArchived : currentCategory.isArchived | |||||
| } | |||||
| }); | |||||
| response.sendStatus(200); | |||||
| } catch (e) { | |||||
| response.status(400); | |||||
| response.json(e); | |||||
| } | |||||
| return; | return; | ||||
| }); | }); | ||||