diff --git a/back-end/app.js b/back-end/app.js
index a74b2c4..58fc4a1 100644
--- a/back-end/app.js
+++ b/back-end/app.js
@@ -7,7 +7,6 @@ import url from "url";
import path from "path";
import login from "./src/routes/login.js";
import studentIssues from "./src/routes/studentIssues.js";
-import studentIssueViewDetails from "./src/routes/studentIssueViewDetails.js";
import studentIssueUpdate from "./src/routes/studentIssueUpdate.js";
import adminIssues from "./src/routes/adminIssues.js";
import adminIssueViewDetails from "./src/routes/adminIssueViewDetails.js";
diff --git a/back-end/package.json b/back-end/package.json
index 1362df7..3e62595 100644
--- a/back-end/package.json
+++ b/back-end/package.json
@@ -4,11 +4,11 @@
"description": "The back-end of your project will live in this directory.",
"main": "index.js",
"scripts": {
- "test": "NODE_ENV=test mocha test/**/*.test.js",
+ "test": "mocha test/**/*.test.js",
"start": "node server.js",
"dev": "nodemon server.js",
"lint": "eslint **/*.js",
- "coverage": "NODE_ENV=test c8 mocha test/**/*.test.js"
+ "coverage": "c8 mocha test/**/*.test.js"
},
"keywords": [],
"author": "",
diff --git a/back-end/src/controllers/adminIssuesHandler.js b/back-end/src/controllers/adminIssuesHandler.js
index f71d5b4..23f178d 100644
--- a/back-end/src/controllers/adminIssuesHandler.js
+++ b/back-end/src/controllers/adminIssuesHandler.js
@@ -4,8 +4,8 @@ export async function issueRetrievalHandler(req, res) {
const { paramName } = req.params;
try {
+ // Check if issues exist for the department
const issues = await IssueModel.find({ "departments": paramName });
-
res.json(issues);
} catch (error) {
console.error("Error retrieving data:", error.message);
diff --git a/back-end/src/controllers/studentIssueViewDetailsHandler.js b/back-end/src/controllers/studentIssueViewDetailsHandler.js
index b996bbf..fe5f1dd 100644
--- a/back-end/src/controllers/studentIssueViewDetailsHandler.js
+++ b/back-end/src/controllers/studentIssueViewDetailsHandler.js
@@ -1,35 +1,29 @@
import Issue from '../../models/issueModel.js';
-// The function retrieves all the issues related to this student
export async function studentIssueViewDetailsHandler(req, res) {
- const { paramName } = req.params;
- const { studentNetID } = req.params;
+ const { paramName } = req.params; // Get the issue index from request params
+ const { studentNetID } = req.params; // Get the studentNetID from request params
+ // Check if studentNetID is missing or invalid
if (!studentNetID) {
return res.status(400).send("Missing or invalid studentNetID.");
}
+ // Check if paramName (issue index) is missing or invalid
if (!paramName) {
return res.status(400).send("Missing or invalid issue index.");
}
try {
+ // Query the database to find issues that match both studentNetID and index
+ const response = await Issue.find({ studentNetID: studentNetID, index: paramName });
- const response = await Issue.find({ index: paramName });
-
- // Check if any data is returned for the student
+ // Check if no matching issues are found
if (!response || response.length === 0) {
- return res.status(500).send("No issues found for the given studentNetID.");
- }
-
- // Check if the specific issue index exists
- if (response.length === 0) {
- return res.status(500).send("Issue with the given index not found.");
+ return res.status(500).send("No issues found for the given studentNetID and index.");
}
-
- res.json(response); // Send only the data that matches the specific issue index
+ res.json(response);
} catch (error) {
- // Log the error and send an appropriate response
console.error("Error retrieving data:", error.message);
res.status(500).send("An error occurred while retrieving the data.");
}
diff --git a/back-end/test/adminIssueRetrieval.test.js b/back-end/test/adminIssueRetrieval.test.js
deleted file mode 100644
index f143e7a..0000000
--- a/back-end/test/adminIssueRetrieval.test.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/* eslint-disable */
-// Unit Testing
-import chai, { assert } from "chai";
-import sinon from "sinon";
-import axios from "axios";
-import fs from "fs/promises";
-import { issueRetrievalHandler } from "../src/controllers/adminIssuesHandler.js";
-import chaiHttp from "chai-http";
-
-const data = await fs.readFile("./public/json/mockapi.json", "utf8");
-const mockData = JSON.parse(data);
-const filteredData = mockData.filter((item) => item.departments.includes("IT"));
-
-describe("Unit Tests for Admin Dashboard", () => {
- let req, res, axiosGetStub;
- let sendSpy, jsonSpy;
-
- beforeEach(() => {
- req = { params: { paramName: "IT" } };
- res = {
- json: sinon.spy(),
- status: sinon.stub().returns({ send: sinon.spy() })
- };
- sendSpy = res.status().send;
- jsonSpy = res.json;
- axiosGetStub = sinon.stub(axios, "get");
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it('should filter and return the correct number of data records for "IT" department', async () => {
- axiosGetStub.resolves({ data: mockData });
-
- await issueRetrievalHandler(req, res);
-
- assert.isTrue(axiosGetStub.calledOnce, "axios.get should be called once");
- assert.equal(
- res.json.firstCall.args[0].length,
- filteredData.length,
- "Number of records should match the filtered data length"
- );
- assert.deepEqual(
- res.json.firstCall.args[0],
- filteredData,
- "Returned data should match the filtered data"
- );
- });
-
- // Error Handling Test Case
- it('should handle errors when axios request fails', async () => {
- axiosGetStub.rejects(new Error('Axios request failed'));
- await issueRetrievalHandler(req, res);
- assert.isTrue(axiosGetStub.calledOnce, "axios.get should be called once");
- assert.isTrue(sendSpy.calledOnce, "res.status().send should be called once");
- assert.equal(sendSpy.firstCall.args[0], "An error occurred while retrieving the data.", "Error message should be sent");
- });
-
- // Edge Case Test Case
- it('should return an empty array when paramName is not found in any data records', async () => {
- req.params.paramName = "blackMagic";
- axiosGetStub.resolves({ data: mockData });
- await issueRetrievalHandler(req, res);
- assert.isTrue(axiosGetStub.calledOnce, "axios.get should be called once");
- assert.equal(
- res.json.firstCall.args[0].length,
- 0,
- "Number of records should be 0 when paramName is not found"
- );
- });
-
-});
-
-
-// Integration Testing
-
-chai.use(chaiHttp);
-
-describe("Integration Tests for Admin Issue Retrieval Endpoints", () => {
- describe("GET /api/issues/admin/:paramName", () => {
- it("should retrieve issues for a given department and match all records", async () => {
- const currentDept = "IT";
- const res = await chai
- .request("http://localhost:5000")
- .get(`/api/issues/admin/${currentDept}`);
-
- assert.strictEqual(res.status, 200, "Response status should be 200");
- assert.isArray(res.body, "Response body should be an array");
- assert.lengthOf(
- res.body,
- filteredData.length,
- `Response body should have ${filteredData.length} records`
- );
-
- res.body.forEach((record, index) => {
- assert.deepEqual(
- record,
- filteredData[index],
- `Record at index ${index} should match the expected data`
- );
- });
- });
- });
-});
-/* eslint-enable */
diff --git a/back-end/test/adminIssues.test.js b/back-end/test/adminIssues.test.js
new file mode 100644
index 0000000..94d39ab
--- /dev/null
+++ b/back-end/test/adminIssues.test.js
@@ -0,0 +1,39 @@
+/* eslint-disable */
+import chai, { assert } from "chai";
+import IssueModel from "../models/issueModel.js";
+import chaiHttp from "chai-http";
+import server from "../app.js";
+
+chai.use(chaiHttp);
+
+process.env.NODE_ENV = "test";
+
+// Integration tests for the adminIssues.js file
+describe("Integration Tests for Admin Issue Handler Endpoint", () => {
+ describe("GET /api/issues/admin/:paramName", () => {
+ it("should retrieve all issues for a valid admin user", async () => {
+ const paramName = "admin";
+ const res = await chai
+ .request(server)
+ .get(`/api/issues/admin/${paramName}`);
+ // Check that the response is correct
+ assert.equal(res.status, 200);
+ // Check that the response is an array
+ assert.isArray(res.body);
+ // Check that the response is the same length as the number of issues
+ const userIssues = await IssueModel.find({ "departments": paramName });
+ // Check that the response is the same length as the number of issues of that user
+ assert.equal(res.body.length, userIssues.length);
+ });
+
+ it("should handle errors gracefully for an invalid admin user", async () => {
+ const paramName = "invalid";
+ const res = await chai
+ .request(server)
+ .get(`/api/issues/admin/${paramName}`);
+ assert.equal(res.status, 200);
+ assert.deepEqual(res.body, []);
+ });
+ });
+});
+/* eslint-enable */
diff --git a/back-end/test/dummy.test.js b/back-end/test/dummy.test.js
deleted file mode 100644
index db6f725..0000000
--- a/back-end/test/dummy.test.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*eslint-disable*/
-import { assert } from "chai";
-
-describe("Sample Test Suite", () => {
- it("should pass this test", () => {
- assert.equal(1 + 1, 2);
- });
-
- it("should fail this test", () => {
- assert.equal(2 * 2, 5);
- });
-});
-/*eslint-enable*/
\ No newline at end of file
diff --git a/back-end/test/login.test.js b/back-end/test/login.test.js
index e4c4f8b..a7b6eaa 100644
--- a/back-end/test/login.test.js
+++ b/back-end/test/login.test.js
@@ -4,6 +4,8 @@ import chaiHttp from "chai-http";
import server from "../app.js";
chai.use(chaiHttp);
+process.env.NODE_ENV = "test";
+
// Integration tests for the login.js file
describe("Integration Tests for Login Endpoints", () => {
// Check student login
diff --git a/back-end/test/studentIssueDetails.test.js b/back-end/test/studentIssueDetails.test.js
deleted file mode 100644
index 5372561..0000000
--- a/back-end/test/studentIssueDetails.test.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import chai, { assert } from "chai";
-import chaiHttp from "chai-http";
-import sinon from "sinon";
-import axios from "axios";
-import fs from "fs/promises";
-import {studentIssueViewDetailsHandler} from "../src/controllers/studentIssueViewDetailsHandler.js";
-
-let server = "http://localhost:5000";
-
-const data = await fs.readFile("./public/json/mockapi.json", "utf8");
-const mockResponse = JSON.parse(data);
-
-// Unit Testing
-
-describe("Unit Tests for studentIssueViewDetailsHandler", () => {
- let req, res, axiosGetStub, sendSpy, jsonSpy, statusSpy;
-
- beforeEach(() => {
- req = { params: { paramName: "123", studentNetID: "s123456" } };
- res = {
- json: sinon.spy(),
- status: sinon.stub().returns({ send: sinon.spy() })
- };
- sendSpy = res.status().send;
- jsonSpy = res.json;
- statusSpy = res.status;
- axiosGetStub = sinon.stub(axios, "get");
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should return 400 error if studentNetID is missing", async () => {
- delete req.params.studentNetID;
- await studentIssueViewDetailsHandler(req, res);
- assert.isTrue(statusSpy.calledWith(400));
- assert.isTrue(sendSpy.calledWith("Missing or invalid studentNetID."));
- });
-
- it("should return 400 error if paramName is missing", async () => {
- delete req.params.paramName;
- await studentIssueViewDetailsHandler(req, res);
- assert.isTrue(statusSpy.calledWith(400));
- assert.isTrue(sendSpy.calledWith("Missing or invalid issue index."));
- });
-
- it("should return filtered data for a valid request", async () => {
- const mockData = [{ index: "123", detail: "Issue details" }];
- axiosGetStub.resolves({ data: mockData });
- await studentIssueViewDetailsHandler(req, res);
- assert.isTrue(jsonSpy.calledWith([mockData[0]]));
- });
-
- it("should return 500 error if no data found for student", async () => {
- axiosGetStub.resolves({ data: [] });
- await studentIssueViewDetailsHandler(req, res);
- assert.isTrue(statusSpy.calledWith(500));
- assert.isTrue(sendSpy.calledWith("No issues found for the given studentNetID."));
- });
-
- it("should return 500 error if issue index not found", async () => {
- const mockData = [{ index: "124", detail: "Issue details" }];
- axiosGetStub.resolves({ data: mockData });
- await studentIssueViewDetailsHandler(req, res);
- assert.isTrue(statusSpy.calledWith(500));
- assert.isTrue(sendSpy.calledWith("Issue with the given index not found."));
- });
-
- it("should handle axios errors", async () => {
- axiosGetStub.rejects(new Error("Axios error"));
- await studentIssueViewDetailsHandler(req, res);
- assert.isTrue(statusSpy.calledWith(500));
- assert.isTrue(sendSpy.calledWith("An error occurred while retrieving the data."));
- });
-});
-
-// Integration Testing
-
-chai.use(chaiHttp);
-
-describe("Integration Tests for Student Issue Details", () => {
- // Stub for axios
- let req, res, axiosStub;
-
- before(() => {
- req = { params: { paramName: "tm2005" } };
- res = {
- json: sinon.spy(),
- status: sinon.stub().returns({ send: sinon.spy() }) // Stubbed here
- };
- axiosStub = sinon.stub(axios, 'get');
- });
-
- after(() => {
- axiosStub.restore();
- });
-
- it("should retrieve and filter specific student issue correctly", async () => {
- // const mockResponse = {
- // data: [
- // {
- // "index": 6,
- // "studentNetID": ["tm2005"],
- // "studentName": ["Ted Mosby"],
- // "title": "Global Programs Information Session",
- // "description": "When is the next information session for global education programs?",
- // "attachments": [null],
- // "departments": ["GlobalEd"],
- // "comments": [
- // "Our international student office can assist you with the visa process."
- // ],
- // "dateCreated": "05/01/2023",
- // "timeCreated": "21:51",
- // "currentStatus": "Action Required",
- // "currentPriority": "High Priority"
- // },
- // {
- // "index": 7,
- // "studentNetID": ["tm2005"],
- // "studentName": ["Ted Mosby"],
- // "title": "Career Fair Event Details",
- // "description": "Could you provide the details for the upcoming career fair event?",
- // "attachments": [null],
- // "departments": ["CDC", "Facilities"],
- // "comments": ["Details for the career fair have been sent to your email."],
- // "dateCreated": "11/09/2023",
- // "timeCreated": "16:20",
- // "currentStatus": "Action Required",
- // "currentPriority": "High Priority"
- // }
- // ]
- // };
-
- // Execute the handler
- await studentIssueViewDetailsHandler(req, res);
-
- axiosStub.resolves(mockResponse);
-
- const studentNetID = "tm2005";
- const paramName = "6";
- const response = await chai.request(server)
- .get(`/api/issues/student/${studentNetID}/${paramName}`); // Update this with the correct route
-
- // response= response.filter(
- // (item) => String(item.index) === String(paramName)
- // )
-
- // assert(axiosStub.called);
- assert.equal(response.status, 200);
- assert.deepEqual(response.body, [{
- "index": 6,
- "studentNetID": ["tm2005"],
- "studentName": ["Ted Mosby"],
- "title": "Global Programs Information Session",
- "description": "When is the next information session for global education programs?",
- "attachments": [null],
- "departments": ["GlobalEd"],
- "comments": [
- "Our international student office can assist you with the visa process."
- ],
- "dateCreated": "05/01/2023",
- "timeCreated": "21:51",
- "currentStatus": "Action Required",
- "currentPriority": "High Priority"
- }]);
- });
-
- it("should handle errors gracefully", async () => {
- // axiosStub.rejects(new Error("Network error"));
-
- const studentNetID = "tm2005";
- const paramName = "9999";
- const response = await chai.request(server)
- .get(`/api/issues/student/${studentNetID}/${paramName}`) // Update this with the correct route
- // .query({ studentNetID: 'tm2005', paramName: '6' });
-
- // assert(axiosStub.called);
- assert.equal(response.status, 500);
- assert.equal(response.text, "Issue with the given index not found.");
- });
-});
diff --git a/back-end/test/studentIssuesHandler.test.js b/back-end/test/studentIssues.test.js
similarity index 50%
rename from back-end/test/studentIssuesHandler.test.js
rename to back-end/test/studentIssues.test.js
index 4a0e61a..b3e33f6 100644
--- a/back-end/test/studentIssuesHandler.test.js
+++ b/back-end/test/studentIssues.test.js
@@ -3,9 +3,12 @@ import chai, { assert } from "chai";
import IssueModel from "../models/issueModel.js";
import chaiHttp from "chai-http";
import server from "../app.js";
+
chai.use(chaiHttp);
-// Integration tests for the studentIssuesHandler.js file
+process.env.NODE_ENV = "test";
+
+// Integration tests for the studentIssues.js file
describe("Integration Tests for Student Issue Handler Endpoint", () => {
describe("GET /api/issues/student/:paramName", () => {
it("should retrieve all issues for a valid student NetID", async () => {
@@ -32,6 +35,34 @@ describe("Integration Tests for Student Issue Handler Endpoint", () => {
assert.equal(res.text, "User does not exist.");
});
});
+
+ describe("GET /api/issues/student/:studentNetID/:paramName", () => {
+ it("should retrieve all issues for a valid student NetID and issue index", async () => {
+ const studentNetID = "student";
+ const paramName = "101";
+ const res = await chai
+ .request(server)
+ .get(`/api/issues/student/${studentNetID}/${paramName}`);
+ // Check that the response is correct
+ assert.equal(res.status, 200);
+ // Check that the response is an array
+ assert.isArray(res.body);
+ // Check that the response is the same length as the number of issues
+ const userIssues = await IssueModel.find({ "studentNetID": studentNetID, "index": paramName });
+ // Check that the response is the same length as the number of issues of that user
+ assert.equal(res.body.length, userIssues.length);
+ });
+
+ it("should handle errors gracefully for an invalid issue index", async () => {
+ const studentNetID = "student";
+ const paramName = "01";
+ const res = await chai
+ .request(server)
+ .get(`/api/issues/student/${studentNetID}/${paramName}`);
+ assert.equal(res.status, 500);
+ assert.equal(res.text, "No issues found for the given studentNetID and index.");
+ });
+ });
});
/* eslint-enable */
diff --git a/front-end/src/components/student/StudentIssueOverlay/DesktopIssueDetails.css b/front-end/src/components/student/StudentIssueOverlay/StudentIssueDetails.css
similarity index 100%
rename from front-end/src/components/student/StudentIssueOverlay/DesktopIssueDetails.css
rename to front-end/src/components/student/StudentIssueOverlay/StudentIssueDetails.css
diff --git a/front-end/src/components/student/StudentIssueOverlay/DesktopIssueDetails.js b/front-end/src/components/student/StudentIssueOverlay/StudentIssueDetails.js
similarity index 95%
rename from front-end/src/components/student/StudentIssueOverlay/DesktopIssueDetails.js
rename to front-end/src/components/student/StudentIssueOverlay/StudentIssueDetails.js
index 2b095e4..af9e1f0 100644
--- a/front-end/src/components/student/StudentIssueOverlay/DesktopIssueDetails.js
+++ b/front-end/src/components/student/StudentIssueOverlay/StudentIssueDetails.js
@@ -1,17 +1,13 @@
import { useState, useEffect } from 'react';
import axios from 'axios';
-import './DesktopIssueDetails.css';
+import './StudentIssueDetails.css';
-const DesktopIssueDetails = ({ index }) => {
+const StudentIssueDetails = ({ studentNetID, index }) => {
const [issue, setIssue] = useState(null);
const [comment, setComment] = useState('');
// const [comments, setComments] = useState([]); // Assuming comments is an array
const [changeOccured, setChangeOccured] = useState(false); // To force a re-render
const BACKEND_BASE_URL = process.env.REACT_APP_BACKEND_URL;
- const mockStudent = {
- name: "Ted Mosby",
- netid: "tm2005"
- };
const handleCommentChange = (event) => {
setComment(event.target.value);
@@ -23,7 +19,7 @@ const DesktopIssueDetails = ({ index }) => {
try {
const response = await axios
.post(
- `${BACKEND_BASE_URL}/api/actions/student/${mockStudent.netid}/${index}`,
+ `${BACKEND_BASE_URL}/api/actions/student/${studentNetID}/${index}`,
{
issueindex: index,
comments: comment
@@ -49,7 +45,7 @@ const DesktopIssueDetails = ({ index }) => {
const postMarkAsResolved = async () => {
try {
await axios.post(
- `${BACKEND_BASE_URL}/api/actions/student/${mockStudent.netid}/${index}`,
+ `${BACKEND_BASE_URL}/api/actions/student/${studentNetID}/${index}`,
{
issueindex: index,
currentStatus: "Resolved"
@@ -62,7 +58,7 @@ const DesktopIssueDetails = ({ index }) => {
const postReopen = async (event) => {
try {
await axios.post(
- `${BACKEND_BASE_URL}/api/actions/student/${mockStudent.netid}/${index}`,
+ `${BACKEND_BASE_URL}/api/actions/student/${studentNetID}/${index}`,
{
issueindex: index,
currentStatus: "Open"
@@ -92,7 +88,7 @@ const DesktopIssueDetails = ({ index }) => {
try {
// Attempt to make an HTTP GET request using axios.
const response = await axios.get(
- `${BACKEND_BASE_URL}/api/issues/student/${mockStudent.netid}/${index}`
+ `${BACKEND_BASE_URL}/api/issues/student/${studentNetID}/${index}`
);
// If the request is successful, take the first item from the response data
// (assuming the response data is an array) and update the `issue` state with it.
@@ -274,4 +270,4 @@ const DesktopIssueDetails = ({ index }) => {
);
};
-export default DesktopIssueDetails;
+export default StudentIssueDetails;
diff --git a/front-end/src/layouts/StudentDashboard/StudentDashboard.js b/front-end/src/layouts/StudentDashboard/StudentDashboard.js
index 9354a80..3ed9ba6 100644
--- a/front-end/src/layouts/StudentDashboard/StudentDashboard.js
+++ b/front-end/src/layouts/StudentDashboard/StudentDashboard.js
@@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useContext } from "react";
import "./StudentDashboard.css";
import StudentNavbar from "../../components/student/StudentNavbar/StudentNavbar";
import StudentViewFilter from "../../components/student/StudentViewFilter/StudentViewFilter";
-import DesktopIssueDetails from "../../components/student/StudentIssueOverlay/DesktopIssueDetails";
+import StudentIssueDetails from "../../components/student/StudentIssueOverlay/StudentIssueDetails";
import SiteWideFooter from "../../components/general/SiteWideFooter/SiteWideFooter";
import { CreateRequest } from "../../components/student/CreateRequest/CreateRequest.js";
import { AuthContext } from '../../components/general/AuthContext/AuthContext';
@@ -617,7 +617,7 @@ const StudentDashboard = () => {
X
-
+
)}