Skip to content

Commit 242866a

Browse files
Merge pull request #50 from CS3219-AY2425S1/question-crud-auth-cherry
Question auth, Minor UI fixes to Collab Space
2 parents e990b68 + a10a0b7 commit 242866a

File tree

8 files changed

+94
-34
lines changed

8 files changed

+94
-34
lines changed

Backend/user-service/controller/auth-controller.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,13 @@ export async function handleVerifyToken(req, res) {
3939
return res.status(500).json({ message: err.message });
4040
}
4141
}
42+
43+
// Add function to handle verifying admin
44+
export async function handleVerifyAdmin(req, res) {
45+
try {
46+
const adminUser = req.user;
47+
return res.status(200).json({ message: "Admin status verified", data: adminUser});
48+
} catch (err) {
49+
return res.status(500).json({ message: err.message });
50+
}
51+
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import express from "express";
22

3-
import { handleLogin, handleVerifyToken } from "../controller/auth-controller.js";
4-
import { verifyAccessToken } from "../middleware/basic-access-control.js";
3+
import { handleLogin, handleVerifyAdmin, handleVerifyToken } from "../controller/auth-controller.js";
4+
import { verifyAccessToken, verifyIsAdmin } from "../middleware/basic-access-control.js";
55

66
const router = express.Router();
77

88
router.post("/login", handleLogin);
99

1010
router.get("/verify-token", verifyAccessToken, handleVerifyToken);
1111

12+
// add new route to check for admin
13+
router.get("/verify-admin", verifyAccessToken, verifyIsAdmin, handleVerifyAdmin);
14+
1215
export default router;

Frontend/src/components/collab/CodeSpace.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22
import { Editor } from '@monaco-editor/react'
33
import { Container, Stack, Spinner } from 'react-bootstrap'
44

5-
const CodeSpace = ({ handleEditorChange, loading, code, language, output }) => {
5+
const CodeSpace = ({ handleEditorChange, loading, code, language, output, isError }) => {
66
return (
77

88
<Stack gap={3} className='h-100'>
@@ -14,15 +14,17 @@ const CodeSpace = ({ handleEditorChange, loading, code, language, output }) => {
1414
onChange={handleEditorChange}
1515
theme='vs-dark'
1616
/>
17-
<Container style={{ height: '200px', border: '1px solid #ccc', borderRadius: '0.5rem', padding: '1rem', backgroundColor: '#f8f9fa'}}>
18-
<h5>Output</h5>
17+
<Container style={{ height: '225px', border: '1px solid #ccc', borderRadius: '0.5rem', padding: '1rem', backgroundColor: '#f8f9fa', padding: '20px'}}>
18+
<h4>Output</h4>
1919
{loading ? (
2020
<div className="d-flex justify-content-center align-items-center" style={{ height: '100%' }}>
2121
<Spinner animation="border" variant="primary" />
2222
<span className="ms-1">Running...</span>
2323
</div>
2424
): (
25-
<p style={{ fontFamily: 'monospace', whiteSpace: 'pre-wrap'}}>{output}</p>
25+
<div style={{ height: '150px', maxHeight: '150px', overflowY: 'auto', fontFamily: 'monospace', whiteSpace: 'pre-wrap', border: '1px solid rgba(0, 0, 0, 0.2)', borderRadius: '0.5rem'}}>
26+
<p style={{ color: isError ? 'red' : '#212529' }}>{output}</p>
27+
</div>
2628
)}
2729
</Container>
2830
</Stack>

Frontend/src/components/collab/CollabNavigationBar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const CollabNavigationBar = ({ handleExit, users, handleCodeRun, setLanguage, la
1818
</DropdownToggle>
1919
<DropdownMenu>
2020
<DropdownItem eventKey="python">Python</DropdownItem>
21-
<DropdownItem eventKey="c++">C++</DropdownItem>
21+
<DropdownItem eventKey="javascript">Javascript</DropdownItem>
2222
<DropdownItem eventKey="java">Java</DropdownItem>
2323
</DropdownMenu>
2424
</Dropdown>

Frontend/src/components/collab/CollaborationSpace.jsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ const CollaborationSpace = () => {
2626
const [output, setOutput] = useState("")
2727
const [messages, setMessages] = useState([])
2828
const [outputLoading, setOutputLoading] = useState(false)
29+
const [isError, setIsError] = useState(false);
2930

3031
// use https://emkc.org/api/v2/piston/runtimes to GET other languages
3132
const LANGUAGEVERSIONS = {
3233
"python" : "3.10.0",
3334
"java" : "15.0.2",
34-
"c++": "10.2.0"
35+
"javascript": "1.32.3"
3536
};
3637

3738
{/* State management for access denied toast */}
@@ -187,7 +188,14 @@ const CollaborationSpace = () => {
187188
collabService.getCodeOutput(code_message)
188189
.then(result => {
189190
setOutputLoading(false);
190-
console.log(result.data.run.output)
191+
192+
if (result.data.run.stderr != "") {
193+
console.log("There is an error");
194+
setIsError(true);
195+
} else {
196+
setIsError(false);
197+
}
198+
191199
setOutput(result.data.run.output)
192200
})
193201
.catch(err => console.log(err));
@@ -221,9 +229,9 @@ const CollaborationSpace = () => {
221229
}
222230

223231
return (
224-
<div style={{ textAlign: 'center' }}>
232+
<div>
225233
{showAccessDeniedToast ? (
226-
<ToastContainer className="p-3" position="top-center" style={{ zIndex: 1 }}>
234+
<ToastContainer className="p-3" position="top-center" style={{ zIndex: 1, textAlign: 'center' }}>
227235
<Toast
228236
onClose={handleCloseToast}
229237
show={showAccessDeniedToast}
@@ -255,7 +263,7 @@ const CollaborationSpace = () => {
255263
<Container fluid style={{ marginTop: '20px' }}>
256264
<Row>
257265
<Col md={8}>
258-
<CodeSpace handleEditorChange={handleEditorChange} loading={outputLoading} code={code} language={language} output={output}/>
266+
<CodeSpace handleEditorChange={handleEditorChange} loading={outputLoading} code={code} language={language} output={output} isError={isError}/>
259267
</Col>
260268
<Col md={4}>
261269
<QuestionDisplay/>

Frontend/src/components/question/Question.jsx

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import ButtonGroup from "react-bootstrap/ButtonGroup";
55
import CreateQn from "./CreateQn";
66
import EditQn from "./EditQn";
77
import questionService from "../../services/questions"
8+
import userService from "../../services/users";
89

910
function Question() {
1011
const [questions, setQuestions] = useState([]);
@@ -13,6 +14,7 @@ function Question() {
1314
const [questionToDelete, setQuestionToDelete] = useState(null);
1415
const [showEditModal, setShowEditModal] = useState(false);
1516
const [currentQuestion, setCurrentQuestion] = useState(null);
17+
const [isAdmin, setIsAdmin] = useState(false);
1618

1719
const handleShow = () => setShowComponent(true);
1820
const handleClose = () => setShowComponent(false);
@@ -25,6 +27,28 @@ function Question() {
2527
.catch(err => console.log(err));
2628
}, []);
2729

30+
{/* Added to check the authorization status to determine whether to show edit, delete, add buttons */}
31+
32+
useEffect(() => {
33+
const token = sessionStorage.getItem('jwt_token');
34+
const authHeader = {
35+
headers: {
36+
'Authorization': `Bearer ${token}`,
37+
},
38+
};
39+
40+
// verify token asynchronously, set auth status only after request completes
41+
userService.verifyAdmin(authHeader)
42+
.then(response => {
43+
if (response.status == 200) {
44+
setIsAdmin(true);
45+
}
46+
})
47+
.catch(e => {
48+
console.log('Error:', e);
49+
});
50+
}, []);
51+
2852
const easyQuestions = questions.filter(q => q.complexity === "Easy")
2953
const mediumQuestions = questions.filter(q => q.complexity === "Medium")
3054
const hardQuestions = questions.filter(q => q.complexity === "Hard")
@@ -85,7 +109,7 @@ function Question() {
85109
<th>Title</th>
86110
<th>Description</th>
87111
<th>Category</th>
88-
<th>Action</th>
112+
{isAdmin && (<th>Action</th>)}
89113
</tr>
90114
</thead>
91115
<tbody>
@@ -95,20 +119,22 @@ function Question() {
95119
<td>{question.title}</td>
96120
<td>{question.description}</td>
97121
<td>{question.category ? question.category.join(", ") : ''}</td>
98-
<td>
99-
<ButtonGroup className="mb-2">
100-
<button
101-
className='btn btn-success'
102-
onClick={() => handleShowEditModal(question)}
103-
>
104-
Edit
105-
</button>
106-
<button className='btn btn-danger' size="sm"
107-
onClick={() => handleShowDelete(question._id)}>
108-
Delete
109-
</button>
110-
</ButtonGroup>
111-
</td>
122+
{isAdmin && (
123+
<td>
124+
<ButtonGroup className="mb-2">
125+
<button
126+
className='btn btn-success'
127+
onClick={() => handleShowEditModal(question)}
128+
>
129+
Edit
130+
</button>
131+
<button className='btn btn-danger' size="sm"
132+
onClick={() => handleShowDelete(question._id)}>
133+
Delete
134+
</button>
135+
</ButtonGroup>
136+
</td>
137+
)}
112138
</tr>
113139
))}
114140
</tbody>
@@ -121,10 +147,11 @@ function Question() {
121147
<div className='bg-white rounded p-3 m-3'>
122148
<div className="d-flex justify-content-between">
123149
<h1>Questions</h1>
124-
<button className="btn btn-primary mt-3" onClick={() => handleShow()}>
125-
{showComponent ? 'Hide' : 'Add question'}
126-
</button>
127-
150+
{isAdmin && (
151+
<button className="btn btn-primary mt-3" onClick={() => handleShow()}>
152+
{showComponent ? 'Hide' : 'Add question'}
153+
</button>
154+
)}
128155
<Modal show={showComponent} onHide={handleClose}>
129156
<Modal.Header closeButton>
130157
<Modal.Title>Add New Question</Modal.Title>

Frontend/src/components/routes/ProtectedRoute.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ const ProtectedRoute = ({ children }) => {
2626
// verify token asynchronously, set auth status only after request completes
2727
userService.verifyToken(authHeader)
2828
.then(response => {
29-
console.log(response);
30-
setIsAuthenticated(true);
29+
//console.log(response.status);
30+
if (response.status == 200) {
31+
setIsAuthenticated(true);
32+
} else {
33+
setIsAuthenticated(false);
34+
}
35+
3136
})
3237
.catch(e => {
3338
console.log('Error:', e);

Frontend/src/services/users.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ const verifyToken = async (authHeader) => {
3131
return response;
3232
}
3333

34-
export default { createUser, getUser, loginUser, updateUser, verifyToken };
34+
const verifyAdmin = async (authHeader) => {
35+
const response = await axios.get(`${baseUrl}/${auth}/verify-admin`, authHeader);
36+
return response;
37+
}
38+
39+
export default { createUser, getUser, loginUser, updateUser, verifyToken, verifyAdmin };

0 commit comments

Comments
 (0)