Manage students page #51
@@ -24,7 +24,6 @@ def check_data(data, required_fields):
|
|||||||
def instructor_required(func):
|
def instructor_required(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def dec(*args, **kwargs):
|
def dec(*args, **kwargs):
|
||||||
print(current_user)
|
|
||||||
if current_user.role != "instructor":
|
if current_user.role != "instructor":
|
||||||
return error_response(400, "User is not instructor!")
|
return error_response(400, "User is not instructor!")
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
@@ -173,3 +172,28 @@ def enroll_student(uid, cid):
|
|||||||
resp = {"user": u.to_dict(), "course": c.to_dict()}
|
resp = {"user": u.to_dict(), "course": c.to_dict()}
|
||||||
return jsonify(resp)
|
return jsonify(resp)
|
||||||
|
|
||||||
|
@bp.route("/user/<string:username>/enroll/<int:cid>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
@instructor_required
|
||||||
|
def enroll_student_by_username(username, cid):
|
||||||
|
u = User.query.filter_by(username=username).first()
|
||||||
|
if not u:
|
||||||
|
return error_response(400, f"User with username {username} does not exist")
|
||||||
|
|
||||||
|
c = Course.query.get(cid)
|
||||||
|
if not c:
|
||||||
|
return error_response(400, f"Course with id {cid} does not exist")
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
if not u.enroll(c):
|
||||||
|
return error_response(
|
||||||
|
400, f"User {u.id} is already enrolled in course {cid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
elif request.method == "DELETE":
|
||||||
|
if not u.unenroll(c):
|
||||||
|
return error_response(400, f"User {u.id} is not enrolled in course {cid}")
|
||||||
|
|
||||||
|
resp = {"user": u.to_dict(), "course": c.to_dict()}
|
||||||
|
return jsonify(resp)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import LogoutPage from "./pages/LogoutPage";
|
|||||||
import RegisterPage from "./pages/RegisterPage";
|
import RegisterPage from "./pages/RegisterPage";
|
||||||
import CoursePage from "./pages/CoursePage";
|
import CoursePage from "./pages/CoursePage";
|
||||||
import ManagePage from "./pages/ManagePage";
|
import ManagePage from "./pages/ManagePage";
|
||||||
|
import ManageStudentsPage from "./pages/ManageStudentsPage";
|
||||||
import AuthenticatedRoute from "./components/AuthenticatedRoute";
|
import AuthenticatedRoute from "./components/AuthenticatedRoute";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@@ -22,7 +23,7 @@ function App() {
|
|||||||
</AuthenticatedRoute>
|
</AuthenticatedRoute>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/register">
|
<Route path="/register">
|
||||||
<AuthenticatedRoute>
|
<AuthenticatedRoute isAuthenticated={false}>
|
||||||
<RegisterPage />
|
<RegisterPage />
|
||||||
</AuthenticatedRoute>
|
</AuthenticatedRoute>
|
||||||
</Route>
|
</Route>
|
||||||
@@ -47,6 +48,16 @@ function App() {
|
|||||||
<ManagePage />
|
<ManagePage />
|
||||||
</AuthenticatedRoute>
|
</AuthenticatedRoute>
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<Route path="/manage/:cid/students">
|
||||||
|
{(params) => {
|
||||||
|
return (
|
||||||
|
<AuthenticatedRoute>
|
||||||
|
<ManageStudentsPage cid={params.cid} />
|
||||||
|
</AuthenticatedRoute>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Route>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
123
frontend/src/pages/ManageStudentsPage.jsx
Normal file
123
frontend/src/pages/ManageStudentsPage.jsx
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Container, Table, Button, Form } from "react-bootstrap";
|
||||||
|
import MyNavbar from "../components/MyNavbar";
|
||||||
|
import { makeRequest } from "../utils.ts";
|
||||||
|
|
||||||
|
const ManageStutentsPage = ({ cid }) => {
|
||||||
|
const [studentData, setStudentData] = useState([]);
|
||||||
|
const [showAddStudentForm, setShowAddStudentForm] = useState(false);
|
||||||
|
|
||||||
|
const submitStudentForm = async (username) => {
|
||||||
|
await makeRequest({
|
||||||
|
url: `http://localhost:5000/user/${username}/enroll/${cid}`,
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
window.location.reload();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AddStudentForm = () => {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Form
|
||||||
|
className="my-4 p-2 border"
|
||||||
|
onSubmit={() => {
|
||||||
|
submitStudentForm(username);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form.Group controlId="studentUsername">
|
||||||
|
<Form.Label>Username</Form.Label>
|
||||||
|
<Form.Control
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter student's username"
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Form.Text>
|
||||||
|
Make sure that a user with the username exists and is not already
|
||||||
|
enrolled in this course
|
||||||
|
</Form.Text>
|
||||||
|
</Form.Group>
|
||||||
|
<Button className="my-2" type="submit" variant="success">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
makeRequest({
|
||||||
|
url: `http://localhost:5000/course/${cid}/students`,
|
||||||
|
method: "GET",
|
||||||
|
})
|
||||||
|
.then((req) => req.json())
|
||||||
|
.then(async (data) => {
|
||||||
|
setStudentData(data.students);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const sendUnenrollRequest = (uid) => {
|
||||||
|
makeRequest({
|
||||||
|
url: `http://localhost:5000/user/${uid}/enroll/${cid}`,
|
||||||
|
method: "DELETE",
|
||||||
|
}).then((resp) => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<MyNavbar />
|
||||||
|
<Container className="p-5 border">
|
||||||
|
<h1 className="mb-4">Manage Students</h1>
|
||||||
|
<Button
|
||||||
|
className="my-3"
|
||||||
|
variant="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setShowAddStudentForm(!showAddStudentForm);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(showAddStudentForm && "-") || "+"} Add student
|
||||||
|
</Button>
|
||||||
|
{showAddStudentForm && <AddStudentForm />}
|
||||||
|
<Table bordered striped hover>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{studentData.map((student, k) => {
|
||||||
|
return (
|
||||||
|
<tr key={k}>
|
||||||
|
<td>{student.id}</td>
|
||||||
|
<td>{student.username}</td>
|
||||||
|
<td>{student.email}</td>
|
||||||
|
<td>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
variant="danger"
|
||||||
|
onClick={() => sendUnenrollRequest(student.id)}
|
||||||
|
>
|
||||||
|
Unenroll
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ManageStutentsPage;
|
||||||
Reference in New Issue
Block a user