From c7299f1a1b205ae61896886915c9ff11c7db427d Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Fri, 9 May 2025 23:13:49 +0200 Subject: [PATCH 01/10] fix: Group search bug --- docker-compose.yml | 12 ++++++------ tasky/src/models/group.rs | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ce5688e..44cab3c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: postgres: image: postgres:latest - ports: + ports: - "5434:5432" volumes: - db_data:/var/lib/postgresql/data @@ -10,7 +10,7 @@ services: - POSTGRES_USER=admin mongodb: image: mongodb/mongodb-community-server:latest - ports: + ports: - "27017:27017" environment: - MONGO_INITDB_ROOT_USERNAME=admin @@ -22,7 +22,7 @@ services: - "1025:1025" usernator: build: ./usernator - ports: + ports: - "3001:3000" - "3004:3001" environment: @@ -45,7 +45,7 @@ services: context: ./authy args: - ARCH=aarch64 - ports: + ports: - "3002:3000" environment: - JWT_SECRET=secret @@ -59,7 +59,7 @@ services: context: ./tasky args: - ARCH=aarch64 - ports: + ports: - "3005:3000" - "3006:3001" environment: @@ -104,4 +104,4 @@ services: depends_on: - executor volumes: - db_data: \ No newline at end of file + db_data: diff --git a/tasky/src/models/group.rs b/tasky/src/models/group.rs index f7be0f2..763f614 100644 --- a/tasky/src/models/group.rs +++ b/tasky/src/models/group.rs @@ -4,9 +4,12 @@ use super::{PaginatedModel, DB}; use crate::schema::group_members; use crate::schema::groups::dsl; use chrono::NaiveDateTime; +use diesel::debug_query; use diesel::dsl::count_star; +use diesel::pg::Pg; use diesel::prelude::*; use diesel::{associations::HasTable, dsl::not}; +use log::info; use serde::{Deserialize, Serialize}; #[derive(diesel_derive_enum::DbEnum, Debug, Clone, Deserialize, Serialize, PartialEq)] @@ -127,7 +130,7 @@ impl GroupRepository { } } - /// Gets all groups a user is member or tutor of + /// Gets all groups a user is no member or tutor of pub fn get_groups_for_not_member( member_id: i32, page: i64, @@ -139,10 +142,11 @@ impl GroupRepository { .map(|x| x.group_id) .collect(); - let base_predicate = not(dsl::tutor - .eq(member_id) - .or(dsl::id.eq_any(requested)) - .or(group_members::dsl::member_id.eq(member_id))); + let base_predicate = not(dsl::tutor.eq(member_id).or(dsl::id.eq_any(requested)).or( + group_members::dsl::member_id + .eq(member_id) + .and(group_members::dsl::group_id.is_not_null()), + )); let total_base_query = dsl::groups .left_join(group_members::dsl::group_members) @@ -150,6 +154,9 @@ impl GroupRepository { .filter(base_predicate.clone()) .into_boxed(); + let sql_string = debug_query::(&total_base_query).to_string(); + println!("{}", sql_string); + let total = match search.clone() { None => total_base_query .get_result::(conn) @@ -177,7 +184,8 @@ impl GroupRepository { .load::(conn), }; - if results.is_err() { + if let Err(e) = results { + info!("Error from database: {}", e); return PaginatedModel { total: 0, results: vec![], From 60f841430a99bce36752fcb9abcafc0ff1b0876c Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Fri, 9 May 2025 23:37:52 +0200 Subject: [PATCH 02/10] fix(#173): File structure display --- web/components/assignments/CreateSolutionModal.tsx | 7 ++++--- web/utils/FileStructure.ts | 13 +++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/web/components/assignments/CreateSolutionModal.tsx b/web/components/assignments/CreateSolutionModal.tsx index c77a847..34af204 100644 --- a/web/components/assignments/CreateSolutionModal.tsx +++ b/web/components/assignments/CreateSolutionModal.tsx @@ -21,7 +21,8 @@ const CreateSolutionModal = ({ const [files, setFiles] = useState([]); const api = useApiServiceClient(); const router = useRouter(); - const { t } = useTranslation(["common", "assignment"]); + const { t } = useTranslation(["common"]); + const { t: t2 } = useTranslation(["assignment"]); const requiredFiles = useMemo( () => @@ -41,7 +42,7 @@ const CreateSolutionModal = ({ if (missingFiles.length > 0) { notifications.show({ title: t("messages.error"), - message: `${t("errors.missing-files")} ${missingFiles.join(", ")}`, + message: `${t2("errors.missing-files")} ${missingFiles.join(", ")}`, color: "red", }); return; @@ -54,7 +55,7 @@ const CreateSolutionModal = ({
diff --git a/web/utils/FileStructure.ts b/web/utils/FileStructure.ts index ab93bbb..7143236 100644 --- a/web/utils/FileStructure.ts +++ b/web/utils/FileStructure.ts @@ -4,7 +4,6 @@ import { FileStructureFile, FileStructureTree, } from "@/components/FileStructure"; -import { FileWithPath } from "@mantine/dropzone"; /** * Builds the mantine tree data from structure @@ -231,9 +230,19 @@ export const filterFileStructureForDisplayMode = ( const newFolders = []; for (const folder of structure.folders ?? []) { if (folder.files.length !== 0 || (folder.folders ?? []).length !== 0) { - newFolders.push(filterFileStructureForDisplayMode(folder, displayMode)); + const childFolder = filterFileStructureForDisplayMode( + folder, + displayMode, + ); + if ( + childFolder.files.length !== 0 || + (childFolder.folders ?? []).length !== 0 + ) { + newFolders.push(folder); + } } } + structure.folders = newFolders; return structure; }; From 9f63b0963a497578a3fa8744bf3bae4499b92929 Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Fri, 9 May 2025 23:42:06 +0200 Subject: [PATCH 03/10] fix(#170): Group notifications --- tasky/src/routes/notifications.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tasky/src/routes/notifications.rs b/tasky/src/routes/notifications.rs index 4fe7098..72657a0 100644 --- a/tasky/src/routes/notifications.rs +++ b/tasky/src/routes/notifications.rs @@ -99,12 +99,18 @@ pub async fn get_system_wide_notifications( Ok(HttpResponse::Ok().json(notifications)) } +#[derive(Deserialize)] +struct CreateNotificationForGroupRequest { + pub title: String, + pub content: String, +} + /// Endpoint to create group notification #[post("/groups/{id}/notifications")] pub async fn create_group_notification( data: web::Data, user: web::ReqData, - body: web::Json, + body: web::Json, path: web::Path<(i32,)>, ) -> Result { let conn = &mut data.db.db.get().unwrap(); From 0ad1b7573554d3dc57435f834051a9366b86b3fb Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Fri, 9 May 2025 23:45:03 +0200 Subject: [PATCH 04/10] feat: Changed sorting of notifications --- tasky/src/models/notification.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tasky/src/models/notification.rs b/tasky/src/models/notification.rs index 7587303..143ed66 100644 --- a/tasky/src/models/notification.rs +++ b/tasky/src/models/notification.rs @@ -102,6 +102,7 @@ impl NotificationRepository { .left_join(notification_targets::table) .filter(notification_targets::user_id.eq(user_id)) .select(Notification::as_select()) + .order(dsl::created_at.desc()) .get_results::(conn) .expect("Cannot get notifications for user") } From 510b4653be25ddec8b3bfc0d4454574c55832d56 Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Fri, 9 May 2025 23:50:08 +0200 Subject: [PATCH 05/10] fix(#169): User removal --- tasky/src/routes/group.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasky/src/routes/group.rs b/tasky/src/routes/group.rs index 4d60ab7..361ba2b 100644 --- a/tasky/src/routes/group.rs +++ b/tasky/src/routes/group.rs @@ -292,7 +292,7 @@ pub async fn remove_user( }); } - GroupMemberRepository::remove_membership(group.id, user.user_id, conn); + GroupMemberRepository::remove_membership(group.id, path_data.1, conn); Ok(HttpResponse::Ok().finish()) } From 6818f2e00a61a3464580f0fa16fba596fbf0d85d Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Sat, 10 May 2025 00:09:59 +0200 Subject: [PATCH 06/10] fix(#179): Enlisting users --- executor/go.mod | 5 +++-- tasky/src/routes/group.rs | 3 ++- usernator/internal/grpc/user.go | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/executor/go.mod b/executor/go.mod index e657962..d820466 100644 --- a/executor/go.mod +++ b/executor/go.mod @@ -1,7 +1,8 @@ module executor -go 1.22 -toolchain go1.23.7 +go 1.23.0 + +toolchain go1.23.9 require ( github.com/knadh/koanf/maps v0.1.1 diff --git a/tasky/src/routes/group.rs b/tasky/src/routes/group.rs index 361ba2b..f72fa51 100644 --- a/tasky/src/routes/group.rs +++ b/tasky/src/routes/group.rs @@ -218,12 +218,13 @@ pub async fn get_enlistable_users( .into_iter() .map(|x| x.into()) .collect(); + println!("{:?}", users); let response_uids: Vec = users.iter().map(|u| i32::try_from(u.id).unwrap()).collect(); let enlisted_uids = GroupMemberRepository::get_enlisted_from_selection(group.id, response_uids, conn); let filtered_users: Vec<&User> = users .iter() - .filter(|u| enlisted_uids.contains(&i32::try_from(u.id).unwrap())) + .filter(|u| !enlisted_uids.contains(&i32::try_from(u.id).unwrap())) .collect(); Ok(HttpResponse::Ok().json(filtered_users)) } diff --git a/usernator/internal/grpc/user.go b/usernator/internal/grpc/user.go index dd442e4..2f2c7cb 100644 --- a/usernator/internal/grpc/user.go +++ b/usernator/internal/grpc/user.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "strings" "usernator/api" "usernator/internal/models" "usernator/internal/shared" @@ -42,7 +41,7 @@ func (s *GrpcServer) GetUsers(ctx context.Context, in *api.UsersRequest) (*api.U func (s *GrpcServer) SearchStudents(ctx context.Context, in *api.SearchStudentsRequest) (*api.UsersResponse, error) { var users []models.User shared.Database.Where( - "roles @> ARRAY['ROLE_STUDENT'] AND to_tsvector('english', username) @@ to_tsquery('english', ?)", strings.Join(strings.Split(" ", in.Search), "&")).Limit(30).Find(&users) + "roles @> ARRAY['ROLE_STUDENT'] AND username LIKE ?", "%"+in.Search+"%").Limit(30).Find(&users) var responseUsers []*api.UserResponse for _, user := range users { responseUsers = append(responseUsers, &api.UserResponse{ From 2da94285defa4cf7acdfb312b715518570d97b63 Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Sat, 10 May 2025 00:18:35 +0200 Subject: [PATCH 07/10] fix(#181): Sentry error --- web/components/SsrHeader.tsx | 6 +- web/service/ApiService.ts | 131 +++++++++++++++++++++++++++-------- 2 files changed, 108 insertions(+), 29 deletions(-) diff --git a/web/components/SsrHeader.tsx b/web/components/SsrHeader.tsx index 68dc8b8..cd4566f 100644 --- a/web/components/SsrHeader.tsx +++ b/web/components/SsrHeader.tsx @@ -44,7 +44,11 @@ const SsrHeader: React.FC = ({ user }) => { useState(false); const clearAllNotifications = async () => { - await api.removeAllNotificationsForUser(); + try { + await api.removeAllNotificationsForUser(); + } catch (e) { + console.error(e); + } refetch(); }; diff --git a/web/service/ApiService.ts b/web/service/ApiService.ts index 84e13a5..a4c8003 100644 --- a/web/service/ApiService.ts +++ b/web/service/ApiService.ts @@ -18,7 +18,11 @@ import { AssignmentWish, CodeComment, AssignmentWishesResponse, - Notification, GroupJoinRequestPolicy, TaskyUser, GroupMembersResponse, AssignmentCompletionsResponse, + Notification, + GroupJoinRequestPolicy, + TaskyUser, + GroupMembersResponse, + AssignmentCompletionsResponse, } from "@/service/types/tasky"; import { FileStructureTree } from "@/components/FileStructure"; import { Spotlight3Response } from "@/service/types/spotlight"; @@ -61,16 +65,34 @@ class ApiService { ); } - public async createGroup(title: string, join_policy: GroupJoinRequestPolicy): Promise { - return await this.post(`/tasky/create_group`, { title, join_policy }); + public async createGroup( + title: string, + join_policy: GroupJoinRequestPolicy, + ): Promise { + return await this.post(`/tasky/create_group`, { + title, + join_policy, + }); } - public async updateGroup(groupId: number, title: string, join_policy: GroupJoinRequestPolicy): Promise { - return await this.post(`/tasky/groups/${groupId}`, { title, join_policy }); + public async updateGroup( + groupId: number, + title: string, + join_policy: GroupJoinRequestPolicy, + ): Promise { + return await this.post(`/tasky/groups/${groupId}`, { + title, + join_policy, + }); } - public async getGroups(page?: number, search?: string): Promise { - return await this.get(`/tasky/groups?page=${page ?? 1}&search=${search ?? ""}`); + public async getGroups( + page?: number, + search?: string, + ): Promise { + return await this.get( + `/tasky/groups?page=${page ?? 1}&search=${search ?? ""}`, + ); } public async getMyGroups(page?: number): Promise { @@ -117,7 +139,10 @@ class ApiService { ); } - public async removeUserFromGroup(groupId: number, memberId: number): Promise { + public async removeUserFromGroup( + groupId: number, + memberId: number, + ): Promise { await this.delete(`/tasky/groups/${groupId}/members/${memberId}`); } @@ -294,7 +319,11 @@ class ApiService { } public async getNotifications(): Promise { - return await this.get(`/tasky/notifications`); + try { + return await this.get(`/tasky/notifications`); + } catch { + return []; + } } public async removeNotificationForUser(id: number): Promise { @@ -305,8 +334,13 @@ class ApiService { await this.delete("/tasky/notifications"); } - public async searchUsersToEnlist(groupId: number, search: string): Promise { - return await this.get(`/tasky/groups/${groupId}/enlistable?search=${search}`); + public async searchUsersToEnlist( + groupId: number, + search: string, + ): Promise { + return await this.get( + `/tasky/groups/${groupId}/enlistable?search=${search}`, + ); } public async enlistUser(groupId: number, userId: number): Promise { @@ -325,20 +359,35 @@ 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 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}`); + return await this.get( + `/tasky/tutor_solutions?page=${page}`, + ); } - public async getPendingWishes(page: number): Promise { - return await this.get(`/tasky/tutor_assignment_wishes?page=${page}`); + public async getPendingWishes( + page: number, + ): Promise { + return await this.get( + `/tasky/tutor_assignment_wishes?page=${page}`, + ); } - public async getPendingAssignments(page: number): Promise { - return await this.get(`/tasky/student_pending_assignments?page=${page}`); + public async getPendingAssignments( + page: number, + ): Promise { + return await this.get( + `/tasky/student_pending_assignments?page=${page}`, + ); } public async verify(groupId: number): Promise { @@ -349,28 +398,54 @@ class ApiService { await this.post(`/tasky/groups/${groupId}/unverify`, {}); } - public async getGroupMembers(groupId: number, page: number): Promise { - return await this.get(`/tasky/groups/${groupId}/members?page=${page}`); + public async getGroupMembers( + groupId: number, + page: number, + ): Promise { + return await this.get( + `/tasky/groups/${groupId}/members?page=${page}`, + ); } - public async getAssignmentCompletions(groupId: number, assignmentId: number, page: number): Promise { - return await this.get(`/tasky/groups/${groupId}/assignments/${assignmentId}/completions?page=${page}`); + public async getAssignmentCompletions( + groupId: number, + assignmentId: number, + page: number, + ): Promise { + return await this.get( + `/tasky/groups/${groupId}/assignments/${assignmentId}/completions?page=${page}`, + ); } - public async createGroupNotification(groupId: number, title: string, content: string): Promise { - await this.post(`/tasky/groups/${groupId}/notifications`, {title, content}) + public async createGroupNotification( + groupId: number, + title: string, + content: string, + ): Promise { + await this.post(`/tasky/groups/${groupId}/notifications`, { + title, + content, + }); } public async getSystemWideNotification(): Promise { - return await this.get('/tasky/system_wide_notifications'); + return await this.get("/tasky/system_wide_notifications"); } - public async createSystemWideNotification(title: string, content: string, show_until: Date): Promise { - await this.post('/tasky/system_wide_notifications', {title, content, show_until}); + public async createSystemWideNotification( + title: string, + content: string, + show_until: Date, + ): Promise { + await this.post("/tasky/system_wide_notifications", { + title, + content, + show_until, + }); } public async deleteSystemWideNotifications(id: number): Promise { - await this.delete('/tasky/system_wide_notifications/'+id, {}); + await this.delete("/tasky/system_wide_notifications/" + id, {}); } public async createOrUpdateCodeTests( From 461c2b9dcdf879cea93465e6b41355e03c4789b4 Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Sat, 10 May 2025 01:37:18 +0200 Subject: [PATCH 08/10] fix(#183): Pending assignments --- tasky/src/models/assignment.rs | 29 ++++++---- tasky/src/models/mod.rs | 12 +++- web/app/pending-assignments/page.tsx | 55 ++++++++++--------- .../assignments/CreateSolutionModal.tsx | 13 ++++- 4 files changed, 68 insertions(+), 41 deletions(-) diff --git a/tasky/src/models/assignment.rs b/tasky/src/models/assignment.rs index d8478ce..c8e8fbe 100644 --- a/tasky/src/models/assignment.rs +++ b/tasky/src/models/assignment.rs @@ -1,7 +1,7 @@ use super::notification::NotificationRepository; use super::{Paginate, PaginatedModel, DB}; use crate::schema::assignments::dsl; -use crate::schema::{self, group_members}; +use crate::schema::{self, group_members, groups, solutions}; use chrono::NaiveDateTime; use diesel::associations::HasTable; use diesel::dsl::not; @@ -164,21 +164,26 @@ impl AssignmentRepository { conn: &mut DB, ) -> PaginatedModel { dsl::assignments - .left_join(crate::schema::groups::table) - .left_join(crate::schema::solutions::table) - .left_join( - schema::group_members::table.on(schema::groups::id.eq(group_members::group_id)), - ) + .inner_join(groups::table.on(dsl::group_id.eq(groups::dsl::id))) + .inner_join(group_members::table.on(groups::id.eq(group_members::group_id))) .filter(group_members::dsl::member_id.eq(student_id)) - .filter(not(crate::schema::solutions::dsl::submitter_id - .eq(student_id) - .and( - crate::schema::solutions::dsl::approval_status.eq("APPROVED"), - ))) + .filter(not(dsl::id.eq_any( + solutions::dsl::solutions + .filter( + solutions::submitter_id + .eq(student_id) + .and(solutions::approval_status.eq("APPROVED")), + ) + .select(solutions::assignment_id), + ))) .select(Assignment::as_select()) .group_by(dsl::id) .paginate(page) .load_and_count_pages::(conn) - .expect("Cannot fetch pending assignments for student") + .map_err(|x| { + println!("{}", x.to_string()); + x + }) + .expect("jsdfl") } } diff --git a/tasky/src/models/mod.rs b/tasky/src/models/mod.rs index 7fd5183..7f77f6a 100644 --- a/tasky/src/models/mod.rs +++ b/tasky/src/models/mod.rs @@ -73,7 +73,17 @@ impl Paginated { .query .clone() .select(count_star()) - .get_result::(conn)?; + .get_result::(conn) + .optional()? + .unwrap_or(0); + + if total == 0 { + return Ok(PaginatedModel { + results: vec![], + page: self.page, + total, + }); + } let results = self .query diff --git a/web/app/pending-assignments/page.tsx b/web/app/pending-assignments/page.tsx index 0afd8cd..6040e4f 100644 --- a/web/app/pending-assignments/page.tsx +++ b/web/app/pending-assignments/page.tsx @@ -1,34 +1,39 @@ "use client"; import useApiServiceClient from "@/hooks/useApiServiceClient"; -import {useState} from "react"; +import { useState } from "react"; import useClientQuery from "@/hooks/useClientQuery"; -import {useTranslation} from "react-i18next"; -import {Container, Pagination, Stack, Title} from "@mantine/core"; +import { useTranslation } from "react-i18next"; +import { Container, Pagination, Stack, Title } from "@mantine/core"; import AssignmentCard from "@/components/assignments/AssignmentCard"; - const PendingAssignmentsPage = () => { + const api = useApiServiceClient(); + const [page, setPage] = useState(1); + const [assignments] = useClientQuery( + () => api.getPendingAssignments(page), + [page], + ); + const { t } = useTranslation("assignment"); - const api = useApiServiceClient(); - const [page, setPage] = useState(1); - const [assignments] = useClientQuery(() => api.getPendingAssignments(page), [page]); - const { t } = useTranslation("assignment"); - - return ( - - {t('assignment:titles.pending-assignments')} - - {(assignments?.assignments ?? []).map((assignment) => ( - - ))} - - - - ); -} + return ( + + {t("assignment:titles.pending-assignments")} + + {(assignments?.assignments ?? []).map((assignment) => ( + + ))} + + + + ); +}; export default PendingAssignmentsPage; diff --git a/web/components/assignments/CreateSolutionModal.tsx b/web/components/assignments/CreateSolutionModal.tsx index 34af204..153efcc 100644 --- a/web/components/assignments/CreateSolutionModal.tsx +++ b/web/components/assignments/CreateSolutionModal.tsx @@ -4,7 +4,7 @@ import { FormEvent, useMemo, useState } from "react"; import { FileWithPath } from "@mantine/dropzone"; import { extractFilesFromFileStructure } from "@/utils/FileStructure"; import InternalDropzone from "@/components/InternalDropzone"; -import { notifications } from "@mantine/notifications"; +import { notifications, showNotification } from "@mantine/notifications"; import useApiServiceClient from "@/hooks/useApiServiceClient"; import { useRouter } from "next/navigation"; import { useTranslation } from "react-i18next"; @@ -47,8 +47,15 @@ const CreateSolutionModal = ({ }); return; } - const resp = await api.createSolution(assignment.id, files); - router.push(`/solutions/${resp.id}`); + try { + const resp = await api.createSolution(assignment.id, files); + router.push(`/solutions/${resp.id}`); + } catch (e: any) { + showNotification({ + title: t("common:messages.error"), + message: e?.message ?? "", + }); + } }; return ( From 3d535111070d60cfb4d6b39397cdccd8d004704f Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Sat, 10 May 2025 01:38:49 +0200 Subject: [PATCH 09/10] chore: Updated release note --- web/app/dashboard/page.tsx | 59 ++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/web/app/dashboard/page.tsx b/web/app/dashboard/page.tsx index f571b3e..ae5abb0 100644 --- a/web/app/dashboard/page.tsx +++ b/web/app/dashboard/page.tsx @@ -1,11 +1,21 @@ "use client"; import useCurrentUser from "@/hooks/useCurrentUser"; -import {Container, Title, Text, Card, Grid, Group, Flex, Box, Blockquote} from "@mantine/core"; -import {IconInfoCircle, IconTrophyFilled} from "@tabler/icons-react"; +import { + Container, + Title, + Text, + Card, + Grid, + Group, + Flex, + Box, + Blockquote, +} from "@mantine/core"; +import { IconInfoCircle, IconTrophyFilled } from "@tabler/icons-react"; import { useTranslation } from "react-i18next"; import useApiServiceClient from "@/hooks/useApiServiceClient"; import useClientQuery from "@/hooks/useClientQuery"; -import {Carousel} from "@mantine/carousel"; +import { Carousel } from "@mantine/carousel"; import RichTextDisplay from "@/components/display/RichTextDisplay"; const DashboardPage = () => { @@ -20,21 +30,29 @@ const DashboardPage = () => { {t("welcome-back")} {user?.username}! {notifications && notifications?.length > 0 && ( - - {notifications.map((notification) => ( - - - - {notification.title} - - - - - ))} - + + {notifications.map((notification) => ( + + + + {notification.title} + + + + + ))} + )} -
} mt="xl" cite="~ Development team"> - {t('development-status')} +
} + mt="xl" + cite="~ Development team" + > + {t("development-status")}
@@ -50,14 +68,11 @@ const DashboardPage = () => { - Release v0.2.2-stable + Release v0.2.2-fix We had some groundbreaking changes within our app for the current release: -
- - Improved scalability
- - Group and system wide notifications
- - Limited runner options for unverified groups
+
- Fixed some bugs
From e932757a2290d29f07f56f188f146c9167ebad19 Mon Sep 17 00:00:00 2001 From: Mathis Burger Date: Sat, 10 May 2025 01:44:23 +0200 Subject: [PATCH 10/10] fix: Linting errors --- tasky/src/handler/solution.rs | 10 +++++----- tasky/src/models/assignment.rs | 8 ++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tasky/src/handler/solution.rs b/tasky/src/handler/solution.rs index a6c4763..c358a18 100644 --- a/tasky/src/handler/solution.rs +++ b/tasky/src/handler/solution.rs @@ -188,11 +188,11 @@ fn handle_questions( } } solution.question_result = serde_json::to_value(result).ok(); - solution.approval_status = Some( - all_correct - .then(|| ApprovalStatus::Successful.string()) - .unwrap_or(ApprovalStatus::Failed.string()), - ); + solution.approval_status = Some(if all_correct { + ApprovalStatus::Successful.string() + } else { + ApprovalStatus::Failed.string() + }); Ok(()) } diff --git a/tasky/src/models/assignment.rs b/tasky/src/models/assignment.rs index c8e8fbe..ab95ac5 100644 --- a/tasky/src/models/assignment.rs +++ b/tasky/src/models/assignment.rs @@ -1,7 +1,7 @@ use super::notification::NotificationRepository; use super::{Paginate, PaginatedModel, DB}; use crate::schema::assignments::dsl; -use crate::schema::{self, group_members, groups, solutions}; +use crate::schema::{group_members, groups, solutions}; use chrono::NaiveDateTime; use diesel::associations::HasTable; use diesel::dsl::not; @@ -180,10 +180,6 @@ impl AssignmentRepository { .group_by(dsl::id) .paginate(page) .load_and_count_pages::(conn) - .map_err(|x| { - println!("{}", x.to_string()); - x - }) - .expect("jsdfl") + .expect("Cannot loading pending assignments") } }