diff --git a/backend/db/migrations/20220414171336_create_users.sql b/backend/db/migrations/20220414171336_create_users.sql index e489e42..24ad6e7 100644 --- a/backend/db/migrations/20220414171336_create_users.sql +++ b/backend/db/migrations/20220414171336_create_users.sql @@ -20,44 +20,52 @@ CREATE TYPE user_roles AS ENUM ('student', 'teacher'); CREATE TABLE users( - id SERIAL PRIMARY KEY, - username TEXT UNIQUE NOT NULL, + id serial PRIMARY KEY, + username text UNIQUE NOT NULL, role user_roles NOT NULL, - admin BOOLEAN NOT NULL, - jti uuid UNIQUE + admin boolean NOT NULL +); + +CREATE TABLE tokens( + id uuid PRIMARY KEY, + iat timestamp NOT NULL, + exp timestamp NOT NULL, + user_id int NOT NULL REFERENCES users(id) ); CREATE TABLE teachers( - id SERIAL PRIMARY KEY, - user_id INT NOT NULL UNIQUE REFERENCES users(id), - max_students INT NOT NULL + id serial PRIMARY KEY, + user_id int NOT NULL UNIQUE REFERENCES users(id), + max_students int NOT NULL ); CREATE TABLE students( - id SERIAL PRIMARY KEY, - user_id INT NOT NULL UNIQUE REFERENCES users(id) + id serial PRIMARY KEY, + user_id int NOT NULL UNIQUE REFERENCES users(id) ); CREATE TABLE votes( - id SERIAL PRIMARY KEY, - student_id INT NOT NULL UNIQUE REFERENCES students(id) + id serial PRIMARY KEY, + student_id int NOT NULL UNIQUE REFERENCES students(id) ); CREATE TABLE teacher_votes( - id SERIAL PRIMARY KEY, - vote_id INT NOT NULL REFERENCES votes(id), - teacher_id INT NOT NULL REFERENCES teachers(id), - priority INT NOT NULL + id serial PRIMARY KEY, + vote_id int NOT NULL REFERENCES votes(id), + teacher_id int NOT NULL REFERENCES teachers(id), + priority int NOT NULL ); CREATE TABLE assignments( - id SERIAL PRIMARY KEY, - student_id INT NOT NULL REFERENCES students(id), - teacher_id INT NOT NULL REFERENCES teachers(id) + id serial PRIMARY KEY, + student_id int NOT NULL REFERENCES students(id), + teacher_id int NOT NULL REFERENCES teachers(id) ); -- +micrate Down -- SQL section ' Down ' is executed when this migration is rolled back +DROP TABLE assignments; + DROP TABLE teacher_votes; DROP TABLE votes; @@ -68,6 +76,8 @@ DROP TABLE teachers; DROP TABLE students; +DROP TABLE tokens; + DROP TABLE users; DROP TYPE user_roles; \ No newline at end of file diff --git a/backend/src/backend/api/auth.cr b/backend/src/backend/api/auth.cr index 4c638d2..39ab8ca 100644 --- a/backend/src/backend/api/auth.cr +++ b/backend/src/backend/api/auth.cr @@ -31,16 +31,12 @@ module Backend struct Token include JSON::Serializable - getter iss : String - getter vrs : String getter iat : Int64 getter exp : Int64 getter jti : UUID getter context : Context def initialize( - @iss : String, - @vrs : String, @iat : Int64, @exp : Int64, @jti : UUID, @@ -54,8 +50,6 @@ module Backend def self.from_hash(token : Hash(String, JSON::Any)) : self self.new( - iss: token["iss"].as_s, - vrs: token["vrs"].as_s, iat: token["iat"].as_i64, exp: token["exp"].as_i64, jti: UUID.new(token["jti"].as_s), diff --git a/backend/src/backend/api/context.cr b/backend/src/backend/api/context.cr index bd90d2a..3eb8829 100644 --- a/backend/src/backend/api/context.cr +++ b/backend/src/backend/api/context.cr @@ -62,10 +62,7 @@ module Backend rescue @status = Status::JWTError else - pp! payload - if payload.iss != "Mentorenwahl" || payload.vrs != Backend::VERSION - @status = Status::JWTError - elsif @user = Db::User.find(payload.context.user) + if @user = Db::User.find(payload.context.user) @admin = user.not_nil!.admin @role = user.not_nil!.role.to_api @external = diff --git a/backend/src/backend/api/schema/mutation.cr b/backend/src/backend/api/schema/mutation.cr index c1d1246..b290f73 100644 --- a/backend/src/backend/api/schema/mutation.cr +++ b/backend/src/backend/api/schema/mutation.cr @@ -32,15 +32,20 @@ module Backend user = Db::User.query.find { var(:username) == username } raise Errors::Authentication.new unless user && Ldap.authenticate?(Ldap::DN.uid(username), password) - jti = UUID.random(Random::Secure) + token = Db::Token.create!( + id: UUID.random(Random::Secure), + iat: Time.utc, + exp: Time.utc + Backend.config.api.jwt_expiration.minutes, + user_id: user.id + ) + pp! token, typeof(token.id) + LoginPayload.new( user: User.new(user), token: Auth::Token.new( - iss: "Mentorenwahl", - vrs: Backend::VERSION, - iat: Time.utc.to_unix, - exp: (Time.utc + Backend.config.api.jwt_expiration.minutes).to_unix, - jti: jti, + iat: token.iat.to_unix, + exp: token.exp.to_unix, + jti: token.id.not_nil!, context: Auth::Context.new(user.id.not_nil!) ).encode ) diff --git a/backend/src/backend/db/token.cr b/backend/src/backend/db/token.cr new file mode 100644 index 0000000..f927d13 --- /dev/null +++ b/backend/src/backend/db/token.cr @@ -0,0 +1,13 @@ +module Backend::Db + class Token + include Clear::Model + self.table = :tokens + + primary_key type: :uuid + + column iat : Time + column exp : Time + + belongs_to user : User + end +end diff --git a/backend/src/backend/db/user.cr b/backend/src/backend/db/user.cr index e959c9f..82290af 100644 --- a/backend/src/backend/db/user.cr +++ b/backend/src/backend/db/user.cr @@ -30,10 +30,11 @@ module Backend column username : String column role : UserRole column admin : Bool = false - column jti : UUID? has_one student : Student?, foreign_key: :user_id has_one teacher : Teacher?, foreign_key: :user_id + + has_many tokens : Token, foreign_key: :user_id end end end diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 95193c5..89b98bd 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -26,8 +26,9 @@ WORKDIR /usr/src/public COPY --from=builder /usr/src/frontend/dist . RUN minify . -r -o . -FROM alpine as binaryen -RUN apk add --no-cache binaryen +# FROM alpine as binaryen +# RUN apk add --no-cache binaryen +FROM niklasei/wasm-opt-action:v2.1.0 as binaryen WORKDIR /usr/src/public COPY --from=public /usr/src/public . RUN find . -name "*.wasm" -type f | xargs -I % wasm-opt % -o % -O --intrinsic-lowering -Oz diff --git a/frontend/src/routes/home/student_vote.rs b/frontend/src/routes/home/student_vote.rs index 32dfc0e..c527104 100644 --- a/frontend/src/routes/home/student_vote.rs +++ b/frontend/src/routes/home/student_vote.rs @@ -24,6 +24,9 @@ pub enum Msg { }, Submit, Vote(Option>), + AddSlot, + RemoveSlot, + Reset, } #[derive(Properties, PartialEq)] @@ -37,7 +40,8 @@ pub struct StudentVote { can_vote: bool, errors: Option>, min: usize, - teachers: Option>, + slots: usize, + teachers: Vec, votes: HashMap>, } @@ -68,7 +72,8 @@ impl Component for StudentVote { can_vote: false, errors: None, min: 0, - teachers: None, + slots: 0, + teachers: vec![], votes: HashMap::new(), } } @@ -109,6 +114,7 @@ impl Component for StudentVote { Msg::DoneFetchingConfig { errors, min } => { self.errors = errors; self.min = min; + self.slots = self.min; let client = graphql::client(Some(&ctx.props().token)).unwrap(); ctx.link().send_future(async move { @@ -131,7 +137,7 @@ impl Component for StudentVote { Msg::DoneFetchingTeachers { errors, teachers } => { self.fetching = false; self.errors = errors; - self.teachers = Some(teachers); + self.teachers = teachers; true } Msg::RadioSelect { priority, teacher } => { @@ -178,6 +184,27 @@ impl Component for StudentVote { true } } + Msg::AddSlot => { + if self.slots < self.teachers.len() { + self.slots += 1; + true + } else { + false + } + } + Msg::RemoveSlot => { + if self.slots > self.min { + self.votes.remove(&(self.slots - 1)); + self.slots -= 1; + true + } else { + false + } + } + Msg::Reset => { + self.slots = self.min; + true + } } } @@ -202,7 +229,7 @@ impl Component for StudentVote { <>

{ "Wähle deine Wunschmentoren aus:" }

- { for (0..self.min).map(|i| { + { for (0..self.slots).map(|i| { let curr_t = self.votes.get(&i); if let Some(te) = curr_t { if let Some(t) = te { @@ -216,7 +243,7 @@ impl Component for StudentVote {
{ format!("{}. Wahl", i + 1) } - { for self.teachers.as_ref().unwrap().iter().enumerate().filter_map(|(j, t)| { + { for self.teachers.iter().enumerate().filter_map(|(j, t)| { let checked = curr_t == Some(&Some(t.id)); if teachers.contains(&t.id) && !checked { @@ -243,16 +270,35 @@ impl Component for StudentVote { } }) }
- if i < self.min - 1 { + if i < self.slots - 1 {
} } }) } +
+ + +
+
- +