diff --git a/client/src/AdminDashboard/QuestionTable.tsx b/client/src/AdminDashboard/QuestionTable.tsx
index 51b6f120..9e27aadf 100644
--- a/client/src/AdminDashboard/QuestionTable.tsx
+++ b/client/src/AdminDashboard/QuestionTable.tsx
@@ -4,35 +4,20 @@
*/
import React, { useEffect, useState } from 'react';
import CircularProgress from '@mui/material/CircularProgress';
-import { EnhancedEncryptionRounded } from '@mui/icons-material';
import { PaginationTable, TColumn } from '../components/PaginationTable';
-import DeleteUserButton from './DeleteUserButton';
import DeleteQuestionButton from './DeleteQuestionButton';
-import PromoteUserButton from './PromoteUserButton';
import { useData } from '../util/api';
-import { useAppSelector } from '../util/redux/hooks';
-import { selectUser } from '../util/redux/userSlice';
-import IUser from '../util/types/user';
import { IQuestion } from '../util/types/question';
-import { IResource } from '../util/types/resource';
import EditQuestionButton from './EditQuestionButton';
-import { deleteQuestion } from './api';
+import { deleteResource } from './api';
interface AdminDashboardRow {
key: string;
question: string;
- // promote: React.ReactElement;
+ deleteButton: React.ReactElement;
edit: React.ReactElement;
}
-// const testq: IQuestion = {
-// //required params: text, resultantAnswerIds, isQuestion
-// text: '',
-// resultantAnswerIds: [],
-// isQuestion: true,
-
-// };
-
/**
* The standalone table component for holding information about the users in
* the database and allowing admins to remove users and promote users to admins.
@@ -48,47 +33,31 @@ function QuestionTable() {
{ id: 'edit', label: 'Edit' },
];
- const [selectedRow, setSelectedRow] = useState({});
-
// Used to create the data type to create a row in the table
function createAdminDashboardRow(
question: IQuestion, // IUser, //fix this to question type
- // promote: React.ReactElement,
+ deleteButton: React.ReactElement,
edit: React.ReactElement,
): AdminDashboardRow {
- // const { _id, qstn } = user;
- const { _id, text, resultantAnswers, isQuestion } = question;
+ const { _id, text } = question;
return {
key: _id,
question: text,
- // resultantAnswerIds: resultantAnswerIds,
- // isQuestion: isQuestion,
- // promote,
+ deleteButton,
edit,
};
}
const [questionList, setQuestionList] = useState
([]);
const questions = useData('admin/allQuestions'); // this is a route for GETTING ALL question data; TODO: update later
- // TESTING:
- // const questions = testq;
-
- // const self = useAppSelector(selectUser);
// Upon getting the list of users for the database, set the state of the userList to contain all users except for logged in user
useEffect(() => {
- setQuestionList(
- // questions?.data.filter( //don't actually need the filter i think but it's fine just making sure text isn't empty
- // (entry: IQuestion) => entry && entry.text,// && entry.text !== self.text,
- // ),
- questions?.data,
- // TESTING:
- // [questions, questions], //testing
- );
- }, [questions]); // [questions, self]); //should i actually be returning self here
+ setQuestionList(questions?.data);
+ }, [questions]);
// update state of userlist to remove a user from the frontend representation of the data
- const removeQuestion = (question: IQuestion) => {
+ const removeResource = (question: IQuestion) => {
setQuestionList(
questionList.filter(
(entry: IQuestion) =>
@@ -96,39 +65,22 @@ function QuestionTable() {
entry.text &&
entry.text !== question.text &&
// eslint-disable-next-line no-underscore-dangle
- entry._id !== question._id, //! == question.text,
+ entry._id !== question._id,
),
);
- deleteQuestion(question);
+ // eslint-disable-next-line no-underscore-dangle
+ deleteResource(question._id);
};
const handleEditChange = (oldQ: IQuestion, newQ: IQuestion) => {
- // setQuestionList(event.target.value);
- removeQuestion(oldQ);
- // addQuestion(newQ);
- console.log('value is:', newQ.text);
+ setQuestionList(
+ questionList.map((q: IQuestion) =>
+ // eslint-disable-next-line no-underscore-dangle
+ q.text === oldQ.text && q._id === oldQ._id ? newQ : q,
+ ),
+ );
};
- function editRow(row: IQuestion, newText: string) {
- console.log('khgfjgfsjgfliglkghd');
- // row.text = newText; // 'hello ' + row.text;
- }
-
- // idrk what this is but updated it for question
- // update state of userlist to promote a user on the frontend representation
- // const updateQuestion = (text: string) => {
- // setQuestionList(
- // questionList.map((entry) => {
- // if (entry.text !== text) {
- // return entry;
- // }
- // const newEntry = entry;
- // newEntry.isQuestion = true;
- // return newEntry;
- // }),
- // );
- // };
-
// if the questionlist is not yet populated, display a loading spinner
if (!questionList) {
return (
@@ -143,36 +95,17 @@ function QuestionTable() {
rows={questionList.map((question: IQuestion) =>
createAdminDashboardRow(
question,
- editRow(question, '')}
- // open up text editor
- // extract inputted text data from text editor GUI
- // if isQuestion true --> replace current question.text with data from text editor GUI
- // else (isQuestion false) --> take answer IDs and resource descriptions to replace all resource description text with the data from text editor GUI
- // embedded links (clickable)
- // save and turn off editing mode
+ removeRow={() => removeResource(question)}
/>,
-
- // ,
+ ,
),
)}
columns={columns}
/>
-
- // setSelectedRow(row)}
- // key={row.name}
- // sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
- // >
);
}
diff --git a/client/src/AdminDashboard/api.tsx b/client/src/AdminDashboard/api.tsx
index d4e52b75..a1c94f62 100644
--- a/client/src/AdminDashboard/api.tsx
+++ b/client/src/AdminDashboard/api.tsx
@@ -1,8 +1,7 @@
/**
* A file containing all the api calls for the admin dashboard.
*/
-import { deleteData, putData, postData } from '../util/api';
-import { IAnswer } from '../util/types/answer';
+import { deleteData, putData } from '../util/api';
import { IQuestion } from '../util/types/question';
/**
@@ -16,10 +15,8 @@ async function deleteUser(email: string) {
return true;
}
-async function deleteQuestion(question: IQuestion) {
- const res = await putData(`admin/deleteQuestion`, {
- question,
- });
+async function deleteResource(id: string) {
+ const res = await deleteData(`admin/resource/${id}`);
if (res.error) return false;
return true;
}
@@ -33,25 +30,6 @@ async function editQuestion(question: IQuestion) {
return true;
}
-async function deleteResource(question: IQuestion, resource: IAnswer) {
- // eslint-disable-next-line no-underscore-dangle
- const res = await putData(`admin/deleteResource`, {
- question,
- resource,
- });
- if (res.error) return false;
- return true;
-}
-
-// async function editAnswer(questionID: string, answer: string) {
-// const res = await putData(`admin/${questionID}`, { //put = add, post = create new
-// // call this for every answer
-// answer,
-// }); //does this edit or just add new question?
-// if (res.error) return false;
-// return true;
-// }
-
/**
* Sends a request to the server to promote a user to admin
* @param email - the email of the user to promote
@@ -63,10 +41,4 @@ async function upgradePrivilege(email: string) {
return true;
}
-export {
- deleteUser,
- deleteQuestion,
- editQuestion,
- deleteResource,
- upgradePrivilege,
-};
+export { deleteUser, editQuestion, deleteResource, upgradePrivilege };
diff --git a/client/src/components/EditResource.tsx b/client/src/components/EditResource.tsx
index 8502fb6e..5d4aa1e0 100644
--- a/client/src/components/EditResource.tsx
+++ b/client/src/components/EditResource.tsx
@@ -1,20 +1,8 @@
/* eslint-disable no-underscore-dangle */
import React, { useEffect, useRef, useState } from 'react';
import { useLocation } from 'react-router-dom';
-import {
- Typography,
- Container,
- Box,
- Alert,
- AlertTitle,
- Button,
-} from '@mui/material';
-import { sizing } from '@mui/system';
-import {
- deleteQuestion,
- deleteResource,
- editQuestion,
-} from '../AdminDashboard/api';
+import { Typography, Container, Box, Alert, AlertTitle } from '@mui/material';
+import { editQuestion } from '../AdminDashboard/api';
import { IAnswer } from '../util/types/answer';
import { IQuestion } from '../util/types/question';
import EditorGUI from './EditorGUI';
@@ -46,7 +34,7 @@ export default function EditResource() {
- ***Please make sure that any link you add starts with
+ Please make sure that any link you add starts with
"http://" or{' '}
"https://"!
diff --git a/server/src/controllers/admin.controller.ts b/server/src/controllers/admin.controller.ts
index 2cdf5b5c..62085175 100644
--- a/server/src/controllers/admin.controller.ts
+++ b/server/src/controllers/admin.controller.ts
@@ -6,6 +6,7 @@ import express from 'express';
import ApiError from '../util/apiError';
import StatusCode from '../util/statusCode';
import { IUser } from '../models/user.model';
+import { IQuestion } from '../models/question.model';
import {
upgradeUserToAdmin,
getUserByEmail,
@@ -15,10 +16,8 @@ import {
import {
editQuestion,
getAllQuestionsFromDB,
- // getQuestionById,
- // deleteQuestionById,
- deleteResource,
- deleteQuestion,
+ getQuestionById,
+ deleteQuestionById,
} from '../services/question.service';
/**
@@ -160,50 +159,32 @@ const editQuestionText = async (
};
/**
- * Delete resource
+ * Delete a resource question from the database. The id of the resource is expected to be in the request parameter (url). Send a 200 OK status code on success.
*/
-const deleteResourceFromQuestion = async (
+const deleteResource = async (
req: express.Request,
res: express.Response,
next: express.NextFunction,
) => {
- const { question, resource } = req.body;
- if (!question) {
- next(ApiError.missingFields(['question']));
+ const { id } = req.params;
+ if (!id) {
+ next(ApiError.missingFields(['id']));
return;
}
- if (!resource) {
- next(ApiError.missingFields(['resource']));
- return;
- }
- deleteResource(question, resource)
- .then(() => {
- res.sendStatus(StatusCode.OK);
- })
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- .catch((e) => {
- next(ApiError.internal('Unable to delete resource.'));
- });
-};
-const deleteQuestionFromDB = async (
- req: express.Request,
- res: express.Response,
- next: express.NextFunction,
-) => {
- const { question } = req.body;
- if (!question) {
- next(ApiError.missingFields(['question']));
+ // Check if resource to delete is an admin
+ const resource: IQuestion | null = await getQuestionById(parseInt(id, 10));
+ if (!resource) {
+ next(ApiError.notFound(`Resource with id ${id} does not exist`));
return;
}
- deleteQuestion(question)
- .then(() => {
- res.sendStatus(StatusCode.OK);
- })
+ // resource is a question
+ deleteQuestionById(resource._id)
+ .then(() => res.sendStatus(StatusCode.OK))
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.catch((e) => {
- next(ApiError.internal('Unable to delete question.'));
+ next(ApiError.internal('Failed to delete question.'));
});
};
@@ -213,6 +194,5 @@ export {
deleteUser,
getAllQuestions,
editQuestionText,
- deleteResourceFromQuestion,
- deleteQuestionFromDB,
+ deleteResource,
};
diff --git a/server/src/routes/admin.route.ts b/server/src/routes/admin.route.ts
index c5fa8718..f9a121ce 100644
--- a/server/src/routes/admin.route.ts
+++ b/server/src/routes/admin.route.ts
@@ -9,9 +9,8 @@ import {
upgradePrivilege,
deleteUser,
getAllQuestions,
+ deleteResource,
editQuestionText,
- deleteResourceFromQuestion,
- deleteQuestionFromDB,
} from '../controllers/admin.controller';
import { isAuthenticated } from '../controllers/auth.middleware';
import { approve } from '../controllers/auth.controller';
@@ -63,12 +62,6 @@ router.delete('/:email', isAuthenticated, isAdmin, deleteUser);
// router.get('/allQuestions', isAuthenticated, isAdmin, getAllQuestions);
router.get('/allQuestions', getAllQuestions);
-/**
- * A PUT route to delete certain question.
- * Expects an IQuestion
- */
-router.put('/deleteQuestion', deleteQuestionFromDB);
-
/**
* A PUT route to edit certain question. Checks first if the requestor is a
* authenticated and is an admin.
@@ -79,10 +72,11 @@ router.put('/deleteQuestion', deleteQuestionFromDB);
router.put('/editQuestion', editQuestionText);
/**
- * A DELETE route to delete resource from resultantAnswers of a resource question. Checks first if the requestor is a
- * authenticated and is an admin.
- * Expects an IAnswer component
+ * A PUT route to delete a resource. Checks first if the requestor
+ * is a authenticated and is an admin.
+ * Expects the following fields in the URL:
+ * resource id (string) - The id of the resource to be deleted
*/
-router.put('/deleteResource', deleteResourceFromQuestion);
+router.delete('/resource/:id', isAuthenticated, isAdmin, deleteResource);
export default router;
diff --git a/server/src/services/question.service.ts b/server/src/services/question.service.ts
index 7848cecd..f3ee42f0 100644
--- a/server/src/services/question.service.ts
+++ b/server/src/services/question.service.ts
@@ -107,6 +107,16 @@ const deleteQuestion = async (question: IQuestion) => {
await Question.findByIdAndDelete(qID).exec();
};
+/**
+ * A function that deletes a question from the database.
+ * @param id The id of the question to delete.
+ * @returns The deleted {@link Question}
+ */
+const deleteQuestionById = async (id: number) => {
+ const question = await Question.findByIdAndDelete(id).exec();
+ return question;
+};
+
export {
createQuestion,
getQuestionById,
@@ -116,4 +126,5 @@ export {
deleteResource,
deleteQuestion,
// deleteUserById,
+ deleteQuestionById,
};