diff --git a/backend/src/backend/api/schema/mutation.cr b/backend/src/backend/api/schema/mutation.cr index fe1dcc2..b475bbf 100644 --- a/backend/src/backend/api/schema/mutation.cr +++ b/backend/src/backend/api/schema/mutation.cr @@ -103,7 +103,7 @@ module Backend @[GraphQL::Field] # Starts assignment job of mentors to students - def assign_students(context : Context) : Bool? + def start_assignment(context : Context) : Bool? context.admin! Worker::Jobs::AssignStudentsJob.new.enqueue diff --git a/backend/src/backend/worker/jobs/assignment_job.cr b/backend/src/backend/worker/jobs/assignment_job.cr index 8dfd2fc..372b4ba 100644 --- a/backend/src/backend/worker/jobs/assignment_job.cr +++ b/backend/src/backend/worker/jobs/assignment_job.cr @@ -54,115 +54,8 @@ module Backend teachers = Db::Teacher.query .where do raw("EXISTS (SELECT 1 FROM teacher_votes WHERE teacher_id = teachers.id)") & - (max_students > 0) + max_students > 0 end - .with_teacher_votes - .to_a - vote_index = Hash.zip(teachers.map(&.id), [0] * teachers.size) - teacher_votes : Hash(Int32, Array(TeacherVote)) = Hash.zip( - teachers.map(&.id), - teachers.map do |t| - t.teacher_votes.map do |tv| - vote_index[t.id] += 1 - - { - student: tv.vote.student.id, - priority: tv.priority, - } - end - end - ) - teachers.sort_by! { |t| vote_index[t.id] } - - students = Db::Student.query - .with_vote(&.with_teacher_votes(&.order_by(priority: :asc))) - .to_a - student_ids = students.map(&.id) - votes = Hash.zip( - student_ids, - students.map do |s| - s.vote.not_nil!.teacher_votes - .to_a - .select { |tv| teacher_votes.has_key?(tv.teacher.id) } - .map do |tv| - { - teacher: tv.teacher.id, - teacher_max_students: tv.teacher.max_students, - } - end - end - ) - - best_assignment = { - assignment: {} of Int32 => Assignment, - score: Float32::INFINITY, - } - - Backend.config.assignment_possibility_count.times.each do - assignment = {} of Int32 => Assignment - assignment_count = Hash.zip(teachers.map(&.id), [0] * teachers.size) - # teachers.each do |t| - # queue = Deque.new(teacher_votes[t.id].shuffle) - - # count = 1 - # while count < t.max_students - # break unless x = queue.shift? - # tv = x.not_nil! - - # if assignment[tv[:student]]?.nil? || assignment[tv[:student]][:priority] <= tv[:priority] - # assignment[tv[:student]] = {teacher: t.id, priority: tv[:priority]} - # count += 1 - # end - # end - # end - votes.to_a.shuffle.each do |s, tvs| - tvs.each_with_index do |tv, i| - if assignment[s]?.nil? - assignment_count[tv[:teacher]] += 1 - assignment[s] = {teacher: tv[:teacher], priority: i} - elsif assignment_count[tv[:teacher]] < tv[:teacher_max_students] - assignment_count[assignment[s][:teacher]] -= 1 - assignment_count[tv[:teacher]] += 1 - assignment[s] = {teacher: tv[:teacher], priority: i} - end - end - end - - pp! assignment, assignment_count - - score = 0_f32 - # positivity = 0 - # assignment.each do |s, a| - # ratio = (vote_sizes[s] - a[:priority]) / vote_sizes[s] - # score += 2 ** ratio - # positivity += ratio > 0.5 ? 1 : -1 - # end - assignment.each do |s, a| - size = votes[s].size - p! a[:priority], (votes[s].size - a[:priority]) / size - # score += 1 if ((votes[s].size - a[:priority]) / size) >= 0.5 - score += a[:priority] - end - - # full_score = score ** positivity - if score < best_assignment[:score] - best_assignment = { - assignment: assignment, - score: score, - } - end - end - - pp! best_assignment - - str = String.build do |str| - str << "===========================\n" - best_assignment[:assignment].each do |s, a| - str << "#{Db::Student.query.find!(s).user.username} : #{Db::Teacher.query.find!(a[:teacher]).user.username} (#{a[:priority]} / #{votes[s].size})\n" - end - str << "===========================\n" - end - print str end end end diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 8de8f74..35bb5a1 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -2,7 +2,6 @@ FROM lukemathwalker/cargo-chef:latest-rust-1.65.0 as chef WORKDIR /usr/src/frontend FROM chef as planner -WORKDIR /usr/src/frontend RUN mkdir src && touch src/main.rs COPY ./Cargo.toml . RUN cargo chef prepare --recipe-path recipe.json @@ -11,10 +10,10 @@ FROM chef as builder WORKDIR /usr/local/bin ARG TRUNK_VERSION="v0.16.0" RUN wget -qO- https://github.com/thedodd/trunk/releases/download/${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- -WORKDIR /usr/src/frontend RUN rustup target add wasm32-unknown-unknown -COPY ./.cargo ./.cargo +WORKDIR /usr/src/frontend COPY --from=planner /usr/src/frontend/recipe.json . +COPY ./.cargo ./.cargo RUN cargo chef cook --release --recipe-path recipe.json COPY ./index.html . COPY ./graphql ./graphql diff --git a/frontend/graphql/mutations/login.graphql b/frontend/graphql/mutations/login.graphql index 64e3cd4..2ba6200 100644 --- a/frontend/graphql/mutations/login.graphql +++ b/frontend/graphql/mutations/login.graphql @@ -1,5 +1,8 @@ mutation Login($username: String!, $password: String!) { login(username: $username, password: $password) { token + user { + admin + } } } diff --git a/frontend/graphql/mutations/start_assignment.graphql b/frontend/graphql/mutations/start_assignment.graphql new file mode 100644 index 0000000..f26cf9e --- /dev/null +++ b/frontend/graphql/mutations/start_assignment.graphql @@ -0,0 +1,3 @@ +mutation StartAssignment { + startAssignment +} diff --git a/frontend/graphql/schema.graphql b/frontend/graphql/schema.graphql index c55dc98..224a00b 100644 --- a/frontend/graphql/schema.graphql +++ b/frontend/graphql/schema.graphql @@ -86,7 +86,6 @@ type LoginPayload { } type Mutation { - assignStudents: Boolean createUser(checkLdap: Boolean! = true, input: UserCreateInput!): User createVote(input: VoteCreateInput!): Vote deleteUser(id: Int!): Int @@ -94,6 +93,7 @@ type Mutation { logout: UUID registerTeacher(input: TeacherInput!): Teacher revokeToken(token: UUID!): UUID! + startAssignment: Boolean } input TeacherInput { diff --git a/frontend/index.html b/frontend/index.html index aefc1fe..42304f0 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,6 +5,10 @@ + +
diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 8b2b43d..80007c3 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -3,6 +3,12 @@ events { } http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + server_tokens off; more_clear_headers Server; diff --git a/frontend/src/components/logged_in_handler.rs b/frontend/src/components/logged_in_handler.rs index d6205fc..aef86bf 100644 --- a/frontend/src/components/logged_in_handler.rs +++ b/frontend/src/components/logged_in_handler.rs @@ -3,7 +3,7 @@ use yew_agent::{Bridge, Bridged}; use yew_router::prelude::*; use crate::agents; -use crate::cookie_names; +use crate::cookies; use crate::routes; pub enum Msg { @@ -38,7 +38,7 @@ impl Component for LoggedInHandler { Msg::LoggedIn(x) => { if self.logged_in && !x { log::info!("Global logout!"); - wasm_cookies::delete(cookie_names::TOKEN); + cookies::logout_clear(); ctx.link().history().unwrap().push(routes::Route::Login); } self.logged_in = x; diff --git a/frontend/src/cookie_names.rs b/frontend/src/cookie_names.rs deleted file mode 100644 index 18e5aa0..0000000 --- a/frontend/src/cookie_names.rs +++ /dev/null @@ -1,4 +0,0 @@ -use const_format::concatcp; - -pub const BASE: &str = "mentorenwahl_"; -pub const TOKEN: &str = concatcp!(BASE, "token"); diff --git a/frontend/src/cookies.rs b/frontend/src/cookies.rs new file mode 100644 index 0000000..ac61f64 --- /dev/null +++ b/frontend/src/cookies.rs @@ -0,0 +1,14 @@ +use const_format::concatcp; + +const BASE: &str = "mentorenwahl_"; + +pub const TOKEN: &str = concatcp!(BASE, "token"); +pub const ADMIN: &str = concatcp!(BASE, "admin"); + +pub const DELETE_ON_LOGOUT: [&str; 2] = [TOKEN, ADMIN]; + +pub fn logout_clear() { + for x in DELETE_ON_LOGOUT { + wasm_cookies::delete(x); + } +} diff --git a/frontend/src/graphql/mutations/mod.rs b/frontend/src/graphql/mutations/mod.rs index da438a2..48cf68f 100644 --- a/frontend/src/graphql/mutations/mod.rs +++ b/frontend/src/graphql/mutations/mod.rs @@ -2,4 +2,5 @@ pub mod login; pub mod logout; pub mod register_teacher; pub mod revoke_token; +pub mod start_assignment; pub mod vote; diff --git a/frontend/src/graphql/mutations/start_assignment.rs b/frontend/src/graphql/mutations/start_assignment.rs new file mode 100644 index 0000000..a8c7829 --- /dev/null +++ b/frontend/src/graphql/mutations/start_assignment.rs @@ -0,0 +1,10 @@ +use graphql_client::GraphQLQuery; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/mutations/start_assignment.graphql", + response_derives = "Debug", + skip_serializing_none +)] +pub struct StartAssignment; diff --git a/frontend/src/lib.rs b/frontend/src/lib.rs index b0dc0bd..7f6b0f7 100644 --- a/frontend/src/lib.rs +++ b/frontend/src/lib.rs @@ -1,6 +1,6 @@ pub mod agents; pub mod components; -pub mod cookie_names; +pub mod cookies; pub mod graphql; pub mod layouts; pub mod routes; diff --git a/frontend/src/main.rs b/frontend/src/main.rs index c9911f6..49bd18d 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -33,6 +33,7 @@ impl Component for App { } fn main() { + #[cfg(target_arch = "wasm32")] wasm_logger::init(wasm_logger::Config::default()); yew::start_app::