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
12 changes: 6 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
postgres:
image: postgres:latest
ports:
ports:
- "5434:5432"
volumes:
- db_data:/var/lib/postgresql/data
Expand All @@ -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
Expand All @@ -22,7 +22,7 @@ services:
- "1025:1025"
usernator:
build: ./usernator
ports:
ports:
- "3001:3000"
- "3004:3001"
environment:
Expand All @@ -45,7 +45,7 @@ services:
context: ./authy
args:
- ARCH=aarch64
ports:
ports:
- "3002:3000"
environment:
- JWT_SECRET=secret
Expand All @@ -59,7 +59,7 @@ services:
context: ./tasky
args:
- ARCH=aarch64
ports:
ports:
- "3005:3000"
- "3006:3001"
environment:
Expand Down Expand Up @@ -104,4 +104,4 @@ services:
depends_on:
- executor
volumes:
db_data:
db_data:
5 changes: 3 additions & 2 deletions executor/go.mod
Original file line number Diff line number Diff line change
@@ -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
Expand Down
10 changes: 5 additions & 5 deletions tasky/src/handler/solution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down
25 changes: 13 additions & 12 deletions tasky/src/models/assignment.rs
Original file line number Diff line number Diff line change
@@ -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::{group_members, groups, solutions};
use chrono::NaiveDateTime;
use diesel::associations::HasTable;
use diesel::dsl::not;
Expand Down Expand Up @@ -164,21 +164,22 @@ impl AssignmentRepository {
conn: &mut DB,
) -> PaginatedModel<Assignment> {
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::<Assignment>(conn)
.expect("Cannot fetch pending assignments for student")
.expect("Cannot loading pending assignments")
}
}
20 changes: 14 additions & 6 deletions tasky/src/models/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
Expand All @@ -139,17 +142,21 @@ 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)
.select(count_star())
.filter(base_predicate.clone())
.into_boxed();

let sql_string = debug_query::<Pg, _>(&total_base_query).to_string();
println!("{}", sql_string);

let total = match search.clone() {
None => total_base_query
.get_result::<i64>(conn)
Expand Down Expand Up @@ -177,7 +184,8 @@ impl GroupRepository {
.load::<Group>(conn),
};

if results.is_err() {
if let Err(e) = results {
info!("Error from database: {}", e);
return PaginatedModel {
total: 0,
results: vec![],
Expand Down
12 changes: 11 additions & 1 deletion tasky/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,17 @@ impl<T> Paginated<T> {
.query
.clone()
.select(count_star())
.get_result::<i64>(conn)?;
.get_result::<i64>(conn)
.optional()?
.unwrap_or(0);

if total == 0 {
return Ok(PaginatedModel {
results: vec![],
page: self.page,
total,
});
}

let results = self
.query
Expand Down
1 change: 1 addition & 0 deletions tasky/src/models/notification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Notification>(conn)
.expect("Cannot get notifications for user")
}
Expand Down
5 changes: 3 additions & 2 deletions tasky/src/routes/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,13 @@ pub async fn get_enlistable_users(
.into_iter()
.map(|x| x.into())
.collect();
println!("{:?}", users);
let response_uids: Vec<i32> = 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))
}
Expand Down Expand Up @@ -292,7 +293,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())
}

Expand Down
8 changes: 7 additions & 1 deletion tasky/src/routes/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<AppState>,
user: web::ReqData<UserData>,
body: web::Json<CreateNotificationRequest>,
body: web::Json<CreateNotificationForGroupRequest>,
path: web::Path<(i32,)>,
) -> Result<HttpResponse, ApiError> {
let conn = &mut data.db.db.get().unwrap();
Expand Down
3 changes: 1 addition & 2 deletions usernator/internal/grpc/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package grpc

import (
"context"
"strings"
"usernator/api"
"usernator/internal/models"
"usernator/internal/shared"
Expand Down Expand Up @@ -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{
Expand Down
59 changes: 37 additions & 22 deletions web/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -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 = () => {
Expand All @@ -20,21 +30,29 @@ const DashboardPage = () => {
{t("welcome-back")} {user?.username}!
</Title>
{notifications && notifications?.length > 0 && (
<Carousel withIndicators height={200}>
{notifications.map((notification) => (
<Carousel.Slide key={notification.id}>
<Card h={200}>
<Box mx="xl">
<Title order={2}>{notification.title}</Title>
<RichTextDisplay content={notification.content} fullSize={false} />
</Box>
</Card>
</Carousel.Slide>
))}
</Carousel>
<Carousel withIndicators height={200}>
{notifications.map((notification) => (
<Carousel.Slide key={notification.id}>
<Card h={200}>
<Box mx="xl">
<Title order={2}>{notification.title}</Title>
<RichTextDisplay
content={notification.content}
fullSize={false}
/>
</Box>
</Card>
</Carousel.Slide>
))}
</Carousel>
)}
<Blockquote color="indigo" icon={<IconInfoCircle />} mt="xl" cite="~ Development team">
{t('development-status')}
<Blockquote
color="indigo"
icon={<IconInfoCircle />}
mt="xl"
cite="~ Development team"
>
{t("development-status")}
</Blockquote>
<Grid>
<Grid.Col span={4}>
Expand All @@ -50,14 +68,11 @@ const DashboardPage = () => {
</Grid.Col>
<Grid.Col span={8}>
<Card shadow="sm" padding="xl" mt={20}>
<Title order={2}>Release v0.2.2-stable</Title>
<Title order={2}>Release v0.2.2-fix</Title>
<Text>
We had some groundbreaking changes within our app for the current
release:
<br />
- Improved scalability <br/>
- Group and system wide notifications <br/>
- Limited runner options for unverified groups <br/>
<br />- Fixed some bugs
</Text>
</Card>
</Grid.Col>
Expand Down
Loading
Loading