diff --git a/tasky/src/routes/mod.rs b/tasky/src/routes/mod.rs index 4969386..7b43ef1 100644 --- a/tasky/src/routes/mod.rs +++ b/tasky/src/routes/mod.rs @@ -52,6 +52,7 @@ pub fn init_services(cfg: &mut web::ServiceConfig) { .service(solution::approve_solution) .service(solution::reject_solution) .service(solution::get_solution_files) + .service(solution::get_solutions_for_user_by_id) .service(solution::get_tutor_solutions) .service(assignment_wish::create_wish) .service(assignment_wish::get_wishes) diff --git a/tasky/src/routes/solution.rs b/tasky/src/routes/solution.rs index 5d4f289..12849c6 100644 --- a/tasky/src/routes/solution.rs +++ b/tasky/src/routes/solution.rs @@ -98,6 +98,29 @@ pub async fn get_solutions_for_user( Ok(HttpResponse::Ok().json(response)) } +#[get("/user/{id}/solutions")] +pub async fn get_solutions_for_user_by_id( + data: web::Data, + user: web::ReqData, + pagination: web::Query, + path: web::Path<(i32,)>, +) -> Result { + let user_data = user.into_inner(); + let conn = &mut data.db.db.get().unwrap(); + + if !StaticSecurity::is_granted(StaticSecurityAction::IsAdmin, &user_data) { + return Err(ApiError::Forbidden { + message: "This method is only allowed for admins".to_string(), + }); + } + + let solutions = + SolutionRepository::get_solutions_for_user(path.into_inner().0, pagination.page, conn); + + let response = SolutionsResponse::enrich(&solutions, &mut data.user_api.clone(), conn).await?; + Ok(HttpResponse::Ok().json(response)) +} + #[get("/tutor_solutions")] pub async fn get_tutor_solutions( data: web::Data, diff --git a/web/app/students/page.tsx b/web/app/students/page.tsx index d6c5578..1476739 100644 --- a/web/app/students/page.tsx +++ b/web/app/students/page.tsx @@ -1,15 +1,17 @@ "use client"; -import { GetStudentsResponse } from "@/service/types/usernator"; +import {GetStudentsResponse, UserRoles} from "@/service/types/usernator"; import useApiServiceClient from "@/hooks/useApiServiceClient"; -import { Container, Pagination, Title } from "@mantine/core"; -import EntityList, { EntityListCol } from "@/components/EntityList"; +import {Container, Pagination, Title} from "@mantine/core"; +import EntityList, {EntityListCol, EntityListRowAction} from "@/components/EntityList"; import useClientQuery from "@/hooks/useClientQuery"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; +import {useState} from "react"; +import {useTranslation} from "react-i18next"; +import {useRouter} from "next/navigation"; const StudentsPage = () => { const api = useApiServiceClient(); const [page, setPage] = useState(1); + const router = useRouter(); const [students] = useClientQuery( () => api.getStudents(page), [page], @@ -27,10 +29,19 @@ const StudentsPage = () => { }, ]; + const rowActions: EntityListRowAction[] = [ + { + auth: [UserRoles.Admin], + name: t('actions.view'), + onClick: (row) => router.push(`/user-solutions/${row.id}`), + color: 'indigo' + } + ]; + return ( {t("students")} - + { + const id = parseInt(`${params.id}`, 10); + const api = useApiServiceClient(); + const [page, setPage] = useState(1); + const [solutions] = useClientQuery(() => api.getUserSolutions(id, page), [id, page]); + const router = useRouter(); + const {t} = useTranslation(["common", "solution"]); + + const cols: EntityListCol[] = [ + { + field: "id", + label: t("cols.id"), + }, + { + field: "assignment", + label: t("solution:cols.assignment"), + getter: (row) => row.assignment.title, + }, + { + field: "approval_status", + label: t("solution:cols.approval-status"), + render: (value) => , + }, + ]; + + const rowActions: EntityListRowAction[] = [ + { + name: t("actions.view"), + onClick: (row) => router.push(`/solutions/${row.id}`), + color: undefined, + auth: [UserRoles.Student, UserRoles.Admin], + }, + ]; + + return ( + + + {t('solution:personal-solutions')} + + + + ); +} + +export default UserSolutionsPage; diff --git a/web/service/ApiService.ts b/web/service/ApiService.ts index 4556a41..828a11a 100644 --- a/web/service/ApiService.ts +++ b/web/service/ApiService.ts @@ -325,6 +325,10 @@ class ApiService { await this.delete(`/tasky/groups/${groupId}`); } + public async getUserSolutions(id: number, page: number): Promise { + return await this.get(`/tasky/user/${id}/solutions?page=${page}`); + } + public async getPendingSolutions(page: number): Promise { return await this.get(`/tasky/tutor_solutions?page=${page}`); }