Update frontend dockerfile
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Dominic Grimm 2022-11-13 18:41:53 +01:00
parent 2b568d37f6
commit 7e1eda596c
No known key found for this signature in database
GPG Key ID: 6F294212DEAAC530
8 changed files with 111 additions and 44 deletions

View File

@ -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;

View File

@ -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),

View File

@ -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 =

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -24,6 +24,9 @@ pub enum Msg {
},
Submit,
Vote(Option<Vec<String>>),
AddSlot,
RemoveSlot,
Reset,
}
#[derive(Properties, PartialEq)]
@ -37,7 +40,8 @@ pub struct StudentVote {
can_vote: bool,
errors: Option<Vec<String>>,
min: usize,
teachers: Option<Vec<graphql::queries::teachers::teachers::TeachersTeachers>>,
slots: usize,
teachers: Vec<graphql::queries::teachers::teachers::TeachersTeachers>,
votes: HashMap<usize, Option<i64>>,
}
@ -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 {
<>
<h3>{ "Wähle deine Wunschmentoren aus:" }</h3>
<form {onsubmit}>
{ 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 {
<fieldset>
<legend>{ format!("{}. Wahl", i + 1) }</legend>
{ 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 {
}
}) }
</fieldset>
if i < self.min - 1 {
if i < self.slots - 1 {
<br />
}
</>
}
}) }
<div>
<button
onclick={ctx.link().callback(|e: MouseEvent| {
e.prevent_default();
Msg::AddSlot
})}
>
{ "+" }
</button>
<button
onclick={ctx.link().callback(|e: MouseEvent| {
e.prevent_default();
Msg::RemoveSlot
})}
>
{ "-" }
</button>
</div>
<div>
<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
<input type="reset" value="Reset" onclick={ctx.link().callback(|_| Msg::Reset)} />
</div>
<components::graphql_errors::GraphQLErrors errors={self.errors.clone()} />