Untitled
unknown
plain_text
2 years ago
26 kB
4
Indexable
import { getData, setData, DataStore, Quiz, User, ErrorObject, Question, Trash, Answer } from './dataStore'; import { validQuizCheck, validQuizNameCheck, getRandomColourName } from './other'; /** * Given basic details about a new quiz, create one for the logged in user * * @param {int} authUserId - id of authorised user * @param {string} name - name of quiz * @param {string} description - description of quiz * * * @returns {quizId: int} - id of quiz */ interface QuizCreateReturn { quizId: number; } function adminQuizCreate(authUserId: number, name: string, description: string): QuizCreateReturn | ErrorObject { // Get data from dataStore const data: DataStore = getData(); const user: User = data.users.find((user: User) => user.id === authUserId); // Checks if AuthUserId is not a valid user. if (!user) { return { error: 'AuthUserId is not a valid user.' }; } // checks if the name is valid and the user does not already have a quiz with // this name if (validQuizNameCheck(name, authUserId)) { return validQuizNameCheck(name, authUserId); } // Checks if description is too long if (description.length > 100) { return { error: 'Description is more than 100 characters in length' }; } let quizId: number; if (data.quizzes.length === 0 && data.trash.length === 0) { quizId = 1; } else { const quizIds = data.quizzes.map(ids => ids.id); const maxInQuizzes = Math.max.apply(null, quizIds); const trashQuizIds = data.trash.map(ids => ids.quiz.id); const maxInTrash = Math.max.apply(null, trashQuizIds); if (maxInQuizzes > maxInTrash) { quizId = maxInQuizzes + 1; } else quizId = maxInTrash + 1; } // add this quiz to the quizzes array in the dataStore data.quizzes.push({ id: quizId, ownerId: authUserId, name: name, description: description, timeCreated: Math.floor(Date.now() / 1000), timeLastEdited: Math.floor(Date.now() / 1000), numQuestions: 0, duration: 0, questions: [], }); // add the quizId to the ownedId array of the user user.ownedQuizIds.push(quizId); setData(data); return { quizId: quizId, }; } /** * Given a particular quiz, move the quiz to the trash. * * @param {int} authUserId * @param {int} quizId * * @returns {} - empty object * */ function adminQuizRemove(authUserId: number, quizId: number): Record<string, never> | ErrorObject { const data: DataStore = getData(); // checks if authUserId and quizId are valid and the quiz belongs to the user if (validQuizCheck(authUserId, quizId)) { return validQuizCheck(authUserId, quizId); } const quiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); // find the user const user: User = data.users.find((user: User) => user.id === authUserId); // remove the quiz from the quizzes aray in the dataStore data.quizzes.splice( data.quizzes.findIndex((quiz: Quiz) => quiz.id === quizId), 1 ); // remove the quizId from the user's owned quiz Ids user.ownedQuizIds.splice( user.ownedQuizIds.findIndex((ownedId: number) => ownedId === quizId), 1 ); quiz.timeLastEdited = Math.floor(Date.now() / 1000); data.trash.push({ ownerId: authUserId, quiz: quiz }); setData(data); return {}; } /** * Get all of the relevant information about the current quiz. * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * * @returns { * quizId: int, * name: string, * timeCreated: int * timeLastEdited: int * description: string * } - information about quiz */ interface QuizInfoReturn { quizId?: number; name?: string; timeCreated?: number; timeLastEdited?: number; description?: string; numQuestions?: number, duration?: number, questions?: Question[], error?: string; } function adminQuizInfo(authUserId: number, quizId: number): QuizInfoReturn { const data: DataStore = getData(); // checks if authUserId and quizId are valid and the quiz belongs to the user if (validQuizCheck(authUserId, quizId)) { return validQuizCheck(authUserId, quizId); } // find the quiz const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); // return information about the quiz return { quizId: foundQuiz.id, name: foundQuiz.name, timeCreated: foundQuiz.timeCreated, timeLastEdited: foundQuiz.timeLastEdited, description: foundQuiz.description, numQuestions: foundQuiz.numQuestions, duration: foundQuiz.duration, questions: foundQuiz.questions }; } /** * Update the name of the relevant quiz. * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {string} name - name of quiz * * @returns { } - empty object * */ function adminQuizNameUpdate(authUserId: number, quizId: number, name: string): Record<string, never> | ErrorObject { const data: DataStore = getData(); // checks if authUserId and quizId are valid and the quiz belongs to the user if (validQuizCheck(authUserId, quizId)) { return validQuizCheck(authUserId, quizId); } // checks if the name is valid and the user does not already have a quiz with // this name if (validQuizNameCheck(name, authUserId)) { return validQuizNameCheck(name, authUserId); } // find the quiz const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); // update name and timeLastEdited of specified quiz foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); foundQuiz.name = name; setData(data); return {}; } /** * Provide a list of allquizzes that are owned by the currently logged in user. * * @param {number} authUserID - authorised user's id stored as an integer * @returns {quizzes : Array<{ * quizId: number, * name: string * }> * } - an object of an array quizID and name of the quiz */ interface QuizList { quizId: number; name: string; } interface QuizListReturn { quizzes?: QuizList[]; error?: string; } function adminQuizList(authUserId: number): QuizListReturn { const data: DataStore = getData(); // finds specific user in database const foundUser = data.users.find((user: User) => user.id === authUserId); // checks if user exists if (foundUser === undefined) { return { error: 'User id does not correspond to a valid user' }; } // goes through quizzes checking if user owns them and gets its details const foundQuizzes = []; for (const quiz of data.quizzes) { if (foundUser.ownedQuizIds.includes(quiz.id)) { const quizId: number = quiz.id; const name: string = quiz.name; foundQuizzes.push({ quizId: quizId, name: name }); } } return { quizzes: foundQuizzes }; } /** * This function updates the description of the relevant quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {string} description - description of quiz * * @returns { } - empty object * */ function adminQuizDescriptionUpdate(authUserId: number, quizId: number, description: string): Record<string, never> | ErrorObject { const data: DataStore = getData(); const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); if (!foundUser) { return { error: 'authUserId is not a valid user.' }; } if (!foundQuiz) { return { error: 'quizId does not refer to a valid quiz.' }; } if (!foundUser.ownedQuizIds.find((quiz) => quiz === quizId)) { return { error: 'This user does not own this quiz.' }; } if (description.length > 100) { return { error: 'Description is more than 100 characters' }; } foundQuiz.description = description; foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); setData(data); return {}; } /** * This function transfers ownership of a quiz to a different user based on their email * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {string} userEmail - email of user to transfer ownership to * * @returns { } - empty object * */ function adminQuizTransfer(authUserId: number, quizId: number, userEmail: string) { const data: DataStore = getData(); // checks if authUserId and quizId are valid and the quiz belongs to the user if (validQuizCheck(authUserId, quizId)) { return validQuizCheck(authUserId, quizId); } const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundUserToRecieve: User = data.users.find((user: User) => user.email === userEmail); const foundReplaceQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); if (!foundUserToRecieve) { return { error: 'userEmail is not a valid email.' }; } if (foundUser.email === userEmail) { return { error: 'userEmail is the current logged in user.' }; } for (const quiz of foundUserToRecieve.ownedQuizIds) { const foundQuiz: Quiz = data.quizzes.find((specificQuiz: Quiz) => quiz === specificQuiz.id); if (foundQuiz.name === foundReplaceQuiz.name) { return { error: 'Quiz ID refers to a quiz that has a name that is already used by the target user.' }; } } // change ownerId of quiz to new owner foundReplaceQuiz.ownerId = foundUserToRecieve.id; // add the quizId to the ownedId array of the user foundUserToRecieve.ownedQuizIds.push(quizId); // remove the quizId from the user's owned quiz Ids foundUser.ownedQuizIds.splice( foundUser.ownedQuizIds.findIndex((ownedId: number) => ownedId === quizId), 1 ); setData(data); return { }; } /** * This function creates a new question and adds it to a quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {string} question - question being asked * @param {int} duration - duration of question * @param {int} points - how many points the question is worth * @param {...{object}} points - possible answers to the question * * @returns {questionId: int} - id of created question * */ export interface QuestionCreate { questionId: number; } function adminQuestionCreate(authUserId: number, quizId: number, question: string, duration: number, points: number, answers: Answer[]): QuestionCreate | ErrorObject { const data: DataStore = getData(); const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); if (!foundUser) { return { error: 'authUserId is not a valid user.' }; } if (!foundQuiz) { return { error: 'quizId does not refer to a valid quiz.' }; } if (!foundUser.ownedQuizIds.includes(quizId)) { return { error: 'This user does not own this quiz.' }; } if (question.length < 5 || question.length > 50) { return { error: 'The question length invalid' }; } if (duration <= 0) { return { error: 'The question duration must be a positive number' }; } if (foundQuiz.duration + duration > 180) { return { error: 'The duration of the quiz is longer than 3 minutes' }; } if (points < 1 || points > 10) { return { error: 'Invalid point distribution' }; } const answersOnly = answers.map(answer => answer.answer); const duplicateAnswers = answersOnly.filter((element, index, arr) => arr.indexOf(element) !== index); if (duplicateAnswers.length > 0) { return { error: 'There cannot be duplicate answers.' }; } if (answers.length < 2 || answers.length > 6) { return { error: 'Invalid amount of answers inputted' }; } if (!answers.find(answers => answers.correct === true)) { return { error: 'There must be at least one correct answer' }; } if (answers.find(answer => answer.answer.length < 1 || answer.answer.length > 30)) { return { error: 'Invalid answer length' }; } foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); foundQuiz.numQuestions++; let questionId: number; if (data.questions.length === 0) { questionId = 1; } else questionId = data.questions[data.questions.length - 1].questionId + 1; let answerId: number; if (data.answers.length === 0) { answerId = 1; } else answerId = data.answers[data.answers.length - 1].answerId + 1; data.questions.push( { ownerId: foundQuiz.ownerId, quizId: foundQuiz.id, questionId: questionId } ); const allAnswersInfo = answers.map((answer, index) => ({ answerId: answerId + index, answer: answer.answer, colour: getRandomColourName(), correct: answer.correct })); for (const answer of allAnswersInfo) { data.answers.push(answer); } foundQuiz.duration += duration; const questionCreated: Question = { questionId: questionId, question: question, duration: duration, points: points, answers: allAnswersInfo }; foundQuiz.questions.push(questionCreated); setData(data); return { questionId: questionId }; } /** * This function restores a quiz from the trash back to an active quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * * @returns { } - empty object * */ function adminQuizRestore(authUserId: number, quizId: number) { const data: DataStore = getData(); // assumed valid user due to token (check spec) const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); const foundQuizTrash: Trash = data.trash.find((trash: Trash) => trash.quiz.id === quizId); // Quiz ID does not refer to a valid quiz if (!foundQuiz && !foundQuizTrash) { return { error: 'quizId does not refer to a valid quiz.' }; } // Quiz ID does not refer to a quiz that this user owns if (!foundQuizTrash && foundUser.id !== foundQuiz.ownerId) { return { error: 'quizId does not refer to a quiz that this user owns.' }; } if (!foundQuiz && foundUser.id !== foundQuizTrash.ownerId) { return { error: 'quizId does not refer to a quiz that this user owns.' }; } // Quiz ID refers to a quiz that is not currently in the trash if (foundQuiz) { return { error: 'quizId refers to a quiz that is not currently in the trash.' }; } // add quiz back to quizzes dataStore data.quizzes.push(foundQuizTrash.quiz); // add the quizId from the user's owned quiz Ids foundUser.ownedQuizIds.push(foundQuizTrash.quiz.id); // remove quiz from trash data.trash.splice(data.trash.findIndex((trashId: Trash) => trashId.quiz.id === quizId), 1); setData(data); return { }; } /** * This function permanently deletes specific quizzes in the trash * * @param {int} authUserId - id of authorised user * @param {string[]} quizIds - id of quizzes * * @returns { } - empty object * */ export function trashEmpty(userId: number, quizIds: string[]) { const data: DataStore = getData(); for (const quiz of quizIds) { const id = parseInt(quiz); const foundUser: User | undefined = data.users.find((user: User) => user.id === userId); const foundQuiz: Quiz | undefined = data.quizzes.find((quiz: Quiz) => quiz.id === id); const foundQuizTrash: Trash | undefined = data.trash.find((trash: Trash) => trash.quiz.id === id); // Quiz ID does not refer to a valid quiz if (!foundQuiz && !foundQuizTrash) { return { error: 'Invalid QuizId in Input!' }; } // Quiz ID does not refer to a quiz that this user owns if (!foundQuizTrash && foundUser && foundQuiz && foundUser.id !== foundQuiz.ownerId) { return { error: 'Not all quizzes belong to this user!' }; } if (!foundQuiz && foundUser && foundQuizTrash && foundUser.id !== foundQuizTrash.ownerId) { return { error: 'Not all quizzes belong to this user!' }; } // Quiz ID refers to a quiz that is not currently in the trash if (foundQuiz) { return { error: 'Not all quizzes are in the trash!' }; } } for (const exists of quizIds) { const id = parseInt(exists); data.trash.splice(data.trash.findIndex((trashId: Trash) => trashId.quiz.id === id), 1); } setData(data); return { }; } /** * This function returns a list of all quizzes in the trash * * @param {int} authUserId - id of authorised user * * @returns {object} - array of quizzes */ export interface TrashList { quizId: number, name: string, } export interface viewTrashReturn { quizzes: TrashList[] } function adminViewTrash(authUserId: number): viewTrashReturn { const data = getData(); // finds all quizzes that belong to user in trash const trash = data.trash.filter(trash => trash.ownerId === authUserId); const trashList = []; for (const element of trash) { trashList.push({ quizId: element.quiz.id, name: element.quiz.name, }); } setData(data); return { quizzes: trashList }; } /** * This function moves a question in a quiz to a specified position in that quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {int} questionId - id of question * @param {int} newPosition - position question will be moved to * * @returns { } - empty object * */ function adminQuizMoveQuestion(authUserId: number, quizId: number, questionId: number, newPosition: number): Record<string, never> | ErrorObject { const data: DataStore = getData(); // assumed valid user due to token (check spec) const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); // Quiz ID does not refer to a valid quiz if (!foundQuiz) { return { error: 'quizId does not refer to a valid quiz.' }; } // Quiz ID does not refer to a quiz that this user owns if (foundUser.id !== foundQuiz.ownerId) { return { error: 'quizId does not refer to a quiz that this user owns.' }; } const foundQuestion: Question = foundQuiz.questions.find((question: Question) => question.questionId === questionId); if (!foundQuestion) { return { error: 'questionId does not refer to a valid question within this quiz.' }; } if (newPosition < 0 || newPosition > foundQuiz.questions.length - 1) { return { error: 'New position is invalid.', }; } const oldPosition = foundQuiz.questions.indexOf(foundQuestion); if (oldPosition === newPosition) { return { error: 'Question is already in that position', }; } foundQuiz.questions.splice(oldPosition, 1); foundQuiz.questions.splice(newPosition, 0, foundQuestion); foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); setData(data); return { }; } /** * This function deletes a question from the quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {int} questionId - id of the quiz question * * @returns { } - empty object * */ function adminQuestionDelete(authUserId: number, quizId: number, questionId: number): Record<string, never> | ErrorObject { const data: DataStore = getData(); const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); if (!foundUser) { return { error: 'authUserId is not a valid user.' }; } if (!foundQuiz) { return { error: 'quizId does not refer to a valid quiz' }; } if (!foundUser.ownedQuizIds.includes(quizId)) { return { error: 'This user does not own this quiz' }; } const foundQuestion = foundQuiz.questions.find(question => question.questionId === questionId); if (!foundQuestion) { return { error: 'Question Id does not refer to a valid question within this quiz' }; } for (const answer of foundQuestion.answers) { const answerToRemove = data.answers.find(foundAnswer => foundAnswer.answerId === answer.answerId); data.answers.splice(data.answers.indexOf(answerToRemove), 1); } const QuestionInData = data.questions.find(question => question.questionId === questionId); foundQuiz.questions.splice(foundQuiz.questions.indexOf(foundQuestion), 1); data.questions.splice(data.questions.indexOf(QuestionInData), 1); foundQuiz.duration -= foundQuestion.duration; foundQuiz.numQuestions--; foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); setData(data); return {}; } /** * This function creates a new question and adds it to a quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {int} questionId - id of question * @param {string} question - question being asked * @param {int} duration - duration of question * @param {int} points - how many points the question is worth * @param {...{object}} points - possible answers to the question * * @returns {} * */ function adminQuestionUpdate(authUserId: number, quizId: number, questionId: number, question: string, duration: number, points: number, answers: Answer[]): Record<string, never> | ErrorObject { const data: DataStore = getData(); const foundUser: User = data.users.find((user: User) => user.id === authUserId); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); if (!foundQuiz) { return { error: 'quizId does not refer to a valid quiz.' }; } if (!foundUser.ownedQuizIds.includes(quizId)) { return { error: 'This user does not own this quiz.' }; } if (question.length < 5 || question.length > 50) { return { error: 'The question length invalid' }; } if (duration <= 0) { return { error: 'The question duration must be a positive number' }; } if (points < 1 || points > 10) { return { error: 'Invalid point distribution' }; } const answersOnly = answers.map(answer => answer.answer); const duplicateAnswers = answersOnly.filter((element, index, arr) => arr.indexOf(element) !== index); if (duplicateAnswers.length > 0) { return { error: 'There cannot be duplicate answers.' }; } if (answers.length < 2 || answers.length > 6) { return { error: 'Invalid amount of answers inputted' }; } if (!answers.find(answers => answers.correct === true)) { return { error: 'There must be at least one correct answer' }; } if (answers.find(answer => answer.answer.length < 1 || answer.answer.length > 30)) { return { error: 'Invalid answer length' }; } const foundQuestion = foundQuiz.questions.find(question => question.questionId === questionId); if (!foundQuestion) { return { error: 'Question Id does not refer to a valid question within this quiz' }; } if (foundQuiz.duration - foundQuestion.duration + duration > 180) { return { error: 'The duration of the quiz is longer than 3 minutes' }; } foundQuiz.duration = foundQuiz.duration - foundQuestion.duration + duration; foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); for (const answer of foundQuestion.answers) { const answerToRemove = data.answers.find(foundAnswer => foundAnswer.answerId === answer.answerId); data.answers.splice(data.answers.indexOf(answerToRemove), 1); } let answerId: number; if (data.answers.length === 0) { answerId = 1; } else answerId = data.answers[data.answers.length - 1].answerId + 1; const allAnswersInfo = answers.map((answer, index) => ({ answerId: answerId + index, answer: answer.answer, colour: getRandomColourName(), correct: answer.correct })); for (const answer of allAnswersInfo) { data.answers.push(answer); } foundQuestion.duration = duration; foundQuestion.points = points; foundQuestion.question = question; foundQuestion.answers = allAnswersInfo; return {}; } /** * This function duplicates a question in a quiz * * @param {int} authUserId - id of authorised user * @param {int} quizId - id of quiz * @param {int} questionId - id of the quiz question * * @returns {object} - new id of duplicated question * */ interface DuplicateReturn { newQuestionId: number } function adminQuestionDuplicate(authUserId: number, quizId: number, questionId: number): DuplicateReturn | ErrorObject { const data: DataStore = getData(); const foundQuiz: Quiz = data.quizzes.find((quiz: Quiz) => quiz.id === quizId); // checks if authUserId and quizId are valid and the quiz belongs to the user if (validQuizCheck(authUserId, quizId)) { return validQuizCheck(authUserId, quizId); } const foundQuestion = foundQuiz.questions.find(question => question.questionId === questionId); if (!foundQuestion) { return { error: 'Question Id does not refer to a valid question within this quiz' }; } if (foundQuiz.duration + foundQuestion.duration > 180) { return { error: 'Quiz duration cannot exceed 3 minutes' }; } foundQuiz.numQuestions++; foundQuiz.duration += foundQuestion.duration; foundQuiz.timeLastEdited = Math.floor(Date.now() / 1000); const dupeQuestion = Object.assign({}, foundQuestion); const newQuestionId = data.questions[data.questions.length - 1].questionId + 1; dupeQuestion.questionId = newQuestionId; for (const dupeAnswer of dupeQuestion.answers) { dupeAnswer.answerId = data.answers[data.answers.length - 1].answerId + 1; data.answers.push(dupeAnswer); } // add the duplicated question to the index directly after the question that was duplicated foundQuiz.questions.splice(foundQuiz.questions.indexOf(foundQuestion) + 1, 0, dupeQuestion); data.questions.push( { ownerId: foundQuiz.ownerId, quizId: foundQuiz.id, questionId: newQuestionId, }); setData(data); return { newQuestionId: newQuestionId }; } export { adminQuizCreate, adminQuizRemove, adminQuizInfo, adminQuizDescriptionUpdate, adminQuizNameUpdate, adminQuizList, adminQuizTransfer, adminQuestionCreate, adminQuizRestore, adminQuizMoveQuestion, adminViewTrash, adminQuestionDelete, adminQuestionUpdate, adminQuestionDuplicate };
Editor is loading...