@@ -8,6 +8,8 @@ import { userProfileRoutes } from './user-profile/profile-routes'; | |||
import { categoryRoutes } from './user-profile/category-routes'; | |||
import { shelfRoutes } from './user-profile/shelf-routes'; | |||
import { libraryRoutes } from './library/library-routes'; | |||
import { recollectionRoutes } from './revision/revision-routes'; | |||
import { recollectionHistoryRoutes } from './user-profile/recollection-history-routes'; | |||
const SENDGRID_API_KEY = process.env.SENDGRID_API_KEY || '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'; | |||
@@ -23,6 +25,8 @@ app.use('/user/', userProfileRoutes); | |||
app.use('/category/', categoryRoutes); | |||
app.use('/shelf/', shelfRoutes); | |||
app.use('/library/', libraryRoutes); | |||
app.use('/recollection/', recollectionRoutes); | |||
app.use('/recollection-history/', recollectionHistoryRoutes); | |||
app.get('/', (request, response) => { | |||
response.send('Server running @ port' + app.get('port')); | |||
@@ -0,0 +1,6 @@ | |||
export interface RecollectionHistory { | |||
userId: string, | |||
wordId: string, | |||
timeStamp: Date, | |||
wasRecallSuccessful: boolean | |||
} |
@@ -1,18 +1,11 @@ | |||
import { viewPermissionType } from "./variables"; | |||
import { Word } from "./word"; | |||
interface RevisionHistoryRecord { | |||
day: Date, | |||
wasRecallSuccessful: boolean | |||
} | |||
interface AddedWord { | |||
interface ShelfWord { | |||
word: Word, | |||
notes: Array<string>, | |||
isFavourite: boolean, | |||
nextRevisionDateTime: Date, | |||
spaceBetweenRecall: number, // in Days | |||
revisionHistory : Array<RevisionHistoryRecord>, | |||
isArchived: boolean, | |||
} | |||
@@ -21,13 +14,13 @@ export interface Shelf { | |||
description?: string, | |||
viewType: viewPermissionType, | |||
isArchived: boolean, | |||
addedWords?: Array<AddedWord> | |||
words?: Array<ShelfWord> | |||
} | |||
export interface MongoAddedWord extends Omit<AddedWord, "word"> { | |||
export interface MongoShelfWord extends Omit<ShelfWord, "word"> { | |||
word: string, | |||
} | |||
export interface MongoShelf extends Omit<Shelf, "addedWords"> { | |||
addedWords?: Array<MongoAddedWord> | |||
export interface MongoShelf extends Omit<Shelf, "words"> { | |||
words?: Array<MongoShelfWord> | |||
} |
@@ -1,5 +1,6 @@ | |||
import { Category } from "./category"; | |||
import { Shelf } from "./shelf"; | |||
import { Word } from "./word"; | |||
export interface User { | |||
_id: string, | |||
@@ -10,9 +11,11 @@ export interface User { | |||
otp: number, | |||
categories?: Array<Category>, | |||
uncategorised?: Shelf, | |||
favouriteWords?: Array<Word>, | |||
} | |||
export interface MongoUser extends Omit<Omit<User, "categories">, "uncategorised"> { | |||
export interface MongoUser extends Omit<User, "categories" | "uncategorised" | "favouriteWords"> { | |||
categories?: Array<string> // Category IDs, | |||
uncategorised: string | |||
uncategorised?: string, // Shelf ID | |||
favouriteWords?: Array<string> // Favourite Words ID | |||
} |
@@ -0,0 +1,16 @@ | |||
import express from 'express'; | |||
import passport from 'passport'; | |||
import { MongoShelf } from '../models/shelf'; | |||
import { DB_NAME, getDatabaseClient } from '../db-utils'; | |||
import { MongoCategory } from '../models/category'; | |||
export const recollectionRoutes = express.Router(); | |||
export const jwtAuthentication = passport.authenticate('jwt', { session: false }); | |||
recollectionRoutes.get('/questions/', jwtAuthentication, async (request, response) => { | |||
const shelfCollection = getDatabaseClient().db(DB_NAME).collection<MongoShelf>('shelves'); | |||
const categoryCollection = getDatabaseClient().db(DB_NAME).collection<MongoCategory>('categories'); | |||
}); |
@@ -1,10 +1,8 @@ | |||
import { ObjectId } from 'bson'; | |||
import express from 'express'; | |||
import passport from 'passport'; | |||
import { MongoShelf } from '../models/shelf'; | |||
import { DB_NAME, getDatabaseClient } from '../db-utils'; | |||
import { MongoCategory } from '../models/category'; | |||
import { MongoUser } from '../models/user'; | |||
import { ObjectId } from 'bson'; | |||
import { Word } from '../models/word'; | |||
export const userProfileRoutes = express.Router(); | |||
@@ -19,91 +17,86 @@ userProfileRoutes.get('/profile/', jwtAuthentication, async (request, response) | |||
email: user.email, | |||
isVerified: user.isVerified, | |||
categories: user.categories, | |||
uncategorised: user.uncategorised | |||
uncategorised: user.uncategorised, | |||
favouriteWords: user.favouriteWords, | |||
}); | |||
return; | |||
}); | |||
// Add favourite word | |||
userProfileRoutes.get('/profile/deep-copy/', jwtAuthentication, async (request, response) => { | |||
userProfileRoutes.post('/favourite-words/', jwtAuthentication, async (request, response) => { | |||
const user: MongoUser = (request.user as any); | |||
const categoryCollection = getDatabaseClient().db(DB_NAME).collection<MongoCategory>('categories'); | |||
const shelfCollection = getDatabaseClient().db(DB_NAME).collection<MongoShelf>('shelves'); | |||
const userCollection = getDatabaseClient().db(DB_NAME).collection<MongoUser>('users'); | |||
const wordCollection = getDatabaseClient().db(DB_NAME).collection<Word>('words'); | |||
let deepCategories = []; | |||
if (!user.favouriteWords) { | |||
user.favouriteWords = []; | |||
} | |||
for (let i = 0; i < user.categories.length; i += 1) { | |||
let deepShelves = []; | |||
if (!request.body.wordId) { | |||
response.status(400); | |||
response.send("Missing wordID"); | |||
return; | |||
} else if (user.favouriteWords.includes(request.body.wordId)) { | |||
response.status(400); | |||
response.send("WordID already present"); | |||
return; | |||
} | |||
const matchedCategory: any = await categoryCollection.findOne({ | |||
_id: new ObjectId(user.categories[i]) | |||
}); | |||
const matchedWord = await wordCollection.findOne({ | |||
_id: new ObjectId(request.body.wordId) | |||
}); | |||
if (matchedCategory && matchedCategory.shelves) { | |||
for (let j = 0; j < matchedCategory.shelves.length; j += 1) { | |||
let deepAddedWords = []; | |||
const matchedShelf: any = await shelfCollection.findOne({ | |||
_id: new ObjectId(matchedCategory.shelves[j]) | |||
}); | |||
if (matchedShelf && matchedShelf.addedWords) { | |||
for (let k = 0; k < matchedShelf.addedWords.length; k += 1) { | |||
const matchedWord = await wordCollection.findOne({ | |||
_id: new ObjectId(matchedShelf.addedWords[k].word) | |||
}); | |||
if (matchedWord) { | |||
deepAddedWords.push(matchedWord); | |||
} | |||
} | |||
} | |||
matchedShelf.addedWords = deepAddedWords; | |||
deepShelves.push(matchedShelf); | |||
} | |||
} | |||
if (!matchedWord) { | |||
response.status(400); | |||
response.send("Word not present in the library"); | |||
return; | |||
} | |||
matchedCategory.shelves = deepShelves; | |||
deepCategories.push(matchedCategory); | |||
user.favouriteWords.push(request.body.wordId); | |||
const updatedUser = await userCollection.updateOne({ | |||
_id: new ObjectId(user._id) | |||
}, { | |||
$set: { | |||
favouriteWords: user.favouriteWords | |||
} | |||
}); | |||
if (updatedUser.acknowledged) { | |||
response.sendStatus(200); | |||
} else { | |||
response.sendStatus(500); | |||
} | |||
let deepUncategorisedAddedWords = []; | |||
const matchedUncategoisedShelf: any = await shelfCollection.findOne({ | |||
_id: new ObjectId(user.uncategorised) | |||
}); | |||
if (matchedUncategoisedShelf && matchedUncategoisedShelf.addedWords) { | |||
for (let k = 0; k < matchedUncategoisedShelf.addedWords.length; k += 1) { | |||
const matchedWord = await wordCollection.findOne({ | |||
_id: new ObjectId(matchedUncategoisedShelf.addedWords[k].word) | |||
}); | |||
if (matchedWord) { | |||
deepUncategorisedAddedWords.push(matchedWord); | |||
} | |||
} | |||
return; | |||
}); | |||
matchedUncategoisedShelf.addedWords = deepUncategorisedAddedWords; | |||
// Update favourite word | |||
userProfileRoutes.put('/favourite-words/', jwtAuthentication, async (request, response) => { | |||
const user: MongoUser = (request.user as any); | |||
const userCollection = getDatabaseClient().db(DB_NAME).collection<MongoUser>('users'); | |||
if (!request.body.favouriteWords) { | |||
response.status(400); | |||
response.send("Missing favouriteWords param"); | |||
return; | |||
} | |||
response.json({ | |||
_id: user._id, | |||
name: user.name, | |||
email: user.email, | |||
isVerified: user.isVerified, | |||
categories: deepCategories, | |||
uncategorised: matchedUncategoisedShelf | |||
const updatedUser = await userCollection.updateOne({ | |||
_id: new ObjectId(user._id) | |||
}, { | |||
$set: { | |||
favouriteWords: request.body.favouriteWords | |||
} | |||
}); | |||
if (updatedUser.acknowledged) { | |||
response.sendStatus(200); | |||
} else { | |||
response.sendStatus(500); | |||
} | |||
return; | |||
}); |
@@ -0,0 +1,59 @@ | |||
import { RecollectionHistory } from '../models/recollection-history'; | |||
import express from 'express'; | |||
import passport from 'passport'; | |||
import { DB_NAME, getDatabaseClient } from '../db-utils'; | |||
import { MongoUser } from '../models/user'; | |||
import { ObjectId } from 'bson'; | |||
export const recollectionHistoryRoutes = express.Router(); | |||
export const jwtAuthentication = passport.authenticate('jwt', { session: false }); | |||
// Get recollection history for the user | |||
recollectionHistoryRoutes.get('', jwtAuthentication, async (request, response) => { | |||
const user: MongoUser = (request.user as any); | |||
const recollectionHistoryCollection = getDatabaseClient().db(DB_NAME).collection<RecollectionHistory>('recollection-history'); | |||
const recollectionHistoryRecords = await recollectionHistoryCollection.find({ | |||
userId: new ObjectId(user._id) | |||
}).toArray(); | |||
if (recollectionHistoryRecords.length > 0) { | |||
response.status(200); | |||
response.json(recollectionHistoryRecords); | |||
} else { | |||
response.status(200); | |||
response.json([]); | |||
} | |||
return; | |||
}); | |||
// Add user recollection history | |||
recollectionHistoryRoutes.post('', jwtAuthentication, async (request, response) => { | |||
const user: MongoUser = (request.user as any); | |||
const recollectionHistoryCollection = getDatabaseClient().db(DB_NAME).collection<RecollectionHistory>('recollection-history'); | |||
if (!request.body.userId || !request.body.wordId || !request.body.timeStamp || !request.body.wasRecallSuccessful) { | |||
response.status(400); | |||
response.send("Missing attributes"); | |||
return; | |||
} | |||
const newRecollectionHistoryRecord = await recollectionHistoryCollection.insertOne({ | |||
userId: user._id, | |||
wordId: request.body.wordId, | |||
timeStamp: request.body.timeStamp, | |||
wasRecallSuccessful: request.body.wasRecallSuccessful | |||
}); | |||
if (newRecollectionHistoryRecord.acknowledged) { | |||
response.sendStatus(200); | |||
return; | |||
} else { | |||
response.sendStatus(500); | |||
return; | |||
} | |||
}); |
@@ -1,10 +1,10 @@ | |||
import { ObjectID, ObjectId } from 'bson'; | |||
import { ObjectId } from 'bson'; | |||
import express from 'express'; | |||
import passport from 'passport'; | |||
import { MongoCategory } from '../models/category'; | |||
import { DB_NAME } from '../db-utils'; | |||
import { getDatabaseClient } from '../db-utils'; | |||
import { MongoAddedWord, MongoShelf } from '../models/shelf'; | |||
import { MongoShelfWord, MongoShelf } from '../models/shelf'; | |||
import { Word } from '../models/word'; | |||
export const shelfRoutes = express.Router(); | |||
@@ -99,7 +99,7 @@ shelfRoutes.post('/add/', jwtAuthentication, async (request, response) => { | |||
shelfRoutes.put('/update/', jwtAuthentication, async (request, response) => { | |||
const shelfCollection = getDatabaseClient().db(DB_NAME).collection<MongoShelf>('shelves'); | |||
const wordCollection = getDatabaseClient().db(DB_NAME).collection<Word>('words'); | |||
const updatedAddedWords: Array<MongoAddedWord> = request.body.addedWords ? request.body.addedWords : []; | |||
const updatedAddedWords: Array<MongoShelfWord> = request.body.addedWords ? request.body.addedWords : []; | |||
const currentShelf = await shelfCollection.findOne({ | |||
_id: new ObjectId(request.body._id) | |||
@@ -121,8 +121,7 @@ shelfRoutes.put('/update/', jwtAuthentication, async (request, response) => { | |||
for (let i = 0; i < updatedAddedWords.length; i += 1) { | |||
if (!updatedAddedWords[i].word || updatedAddedWords[i].isArchived === undefined || | |||
updatedAddedWords[i].isFavourite === undefined || !updatedAddedWords[i].nextRevisionDateTime || | |||
updatedAddedWords[i].notes === undefined || updatedAddedWords[i].revisionHistory === undefined || | |||
!updatedAddedWords[i].nextRevisionDateTime || updatedAddedWords[i].notes === undefined || | |||
!updatedAddedWords[i].spaceBetweenRecall) { | |||
response.status(400); | |||
response.send("Missing key in " + JSON.stringify(updatedAddedWords[i])); | |||