Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tasky/src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions tasky/src/routes/solution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<AppState>,
user: web::ReqData<UserData>,
pagination: web::Query<PaginationParams>,
path: web::Path<(i32,)>,
) -> Result<HttpResponse, ApiError> {
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<AppState>,
Expand Down
23 changes: 17 additions & 6 deletions web/app/students/page.tsx
Original file line number Diff line number Diff line change
@@ -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<GetStudentsResponse>(
() => api.getStudents(page),
[page],
Expand All @@ -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 (
<Container fluid>
<Title>{t("students")}</Title>
<EntityList cols={cols} rows={students?.students ?? []} />
<EntityList cols={cols} rows={students?.students ?? []} rowActions={rowActions} />
<Pagination
total={Math.ceil((students?.total ?? 0) / 50)}
value={page}
Expand Down
66 changes: 66 additions & 0 deletions web/app/user-solutions/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"use client";
import useApiServiceClient from "@/hooks/useApiServiceClient";
import useClientQuery from "@/hooks/useClientQuery";
import {useState} from "react";
import {Container, Pagination, Title} from "@mantine/core";
import NavigateBack from "@/components/NavigateBack";
import {useTranslation} from "react-i18next";
import EntityList, {EntityListCol, EntityListRowAction} from "@/components/EntityList";
import SolutionBadge from "@/components/solution/SolutionBadge";
import {UserRoles} from "@/service/types/usernator";
import {useRouter} from "next/navigation";


const UserSolutionsPage = ({ params }: { params: { id: string } }) => {
const id = parseInt(`${params.id}`, 10);
const api = useApiServiceClient();
const [page, setPage] = useState<number>(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) => <SolutionBadge status={value as string} />,
},
];

const rowActions: EntityListRowAction[] = [
{
name: t("actions.view"),
onClick: (row) => router.push(`/solutions/${row.id}`),
color: undefined,
auth: [UserRoles.Student, UserRoles.Admin],
},
];

return (
<Container fluid>
<NavigateBack />
<Title>{t('solution:personal-solutions')}</Title>
<EntityList
cols={cols}
rowActions={rowActions}
rows={solutions?.solutions ?? []}
/>
<Pagination
total={Math.ceil((solutions?.total ?? 0) / 50)}
value={page}
onChange={setPage}
/>
</Container>
);
}

export default UserSolutionsPage;
4 changes: 4 additions & 0 deletions web/service/ApiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ class ApiService {
await this.delete<any>(`/tasky/groups/${groupId}`);
}

public async getUserSolutions(id: number, page: number): Promise<SolutionsResponse> {
return await this.get<SolutionsResponse>(`/tasky/user/${id}/solutions?page=${page}`);
}

public async getPendingSolutions(page: number): Promise<SolutionsResponse> {
return await this.get<SolutionsResponse>(`/tasky/tutor_solutions?page=${page}`);
}
Expand Down