Add student vote enable toggle to admin panel
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
f7d32ac08c
commit
d6dbd18090
|
@ -14,7 +14,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
FROM docker.io/crystallang/crystal:1.6.2-alpine as crystal
|
FROM docker.io/crystallang/crystal:1.7.2-alpine as crystal
|
||||||
FROM tdewolff/minify:latest as minify
|
FROM tdewolff/minify:latest as minify
|
||||||
|
|
||||||
FROM crystal as micrate-deps
|
FROM crystal as micrate-deps
|
||||||
|
|
|
@ -72,8 +72,25 @@ CREATE TABLE assignments(
|
||||||
teacher_id int NOT NULL REFERENCES teachers(id)
|
teacher_id int NOT NULL REFERENCES teachers(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE configs(
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
active boolean NOT NULL,
|
||||||
|
can_vote boolean NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX ON configs(active)
|
||||||
|
WHERE
|
||||||
|
active;
|
||||||
|
|
||||||
|
INSERT INTO
|
||||||
|
configs(active, can_vote)
|
||||||
|
VALUES
|
||||||
|
(TRUE, FALSE);
|
||||||
|
|
||||||
-- +micrate Down
|
-- +micrate Down
|
||||||
-- SQL section ' Down ' is executed when this migration is rolled back
|
-- SQL section ' Down ' is executed when this migration is rolled back
|
||||||
|
DROP TABLE configs;
|
||||||
|
|
||||||
DROP TABLE assignments;
|
DROP TABLE assignments;
|
||||||
|
|
||||||
DROP TABLE teacher_votes;
|
DROP TABLE teacher_votes;
|
||||||
|
|
|
@ -8,7 +8,7 @@ targets:
|
||||||
micrate:
|
micrate:
|
||||||
main: src/micrate.cr
|
main: src/micrate.cr
|
||||||
|
|
||||||
crystal: 1.7.1
|
crystal: 1.7.2
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
micrate:
|
micrate:
|
||||||
|
|
|
@ -26,7 +26,7 @@ targets:
|
||||||
backend:
|
backend:
|
||||||
main: src/backend.cr
|
main: src/backend.cr
|
||||||
|
|
||||||
crystal: 1.6.2
|
crystal: 1.7.2
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
clear:
|
clear:
|
||||||
|
|
|
@ -216,6 +216,18 @@ module Backend
|
||||||
|
|
||||||
Vote.new(vote)
|
Vote.new(vote)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@[GraphQL::Field]
|
||||||
|
# Sets if students are allowed to vote
|
||||||
|
def set_voting(context : Context, state : Bool) : Bool?
|
||||||
|
context.admin!
|
||||||
|
|
||||||
|
config = Db::Config.query.where { active == true }.first!
|
||||||
|
config.can_vote = state
|
||||||
|
config.save!
|
||||||
|
|
||||||
|
state
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -143,9 +143,10 @@ module Backend
|
||||||
@[GraphQL::Field]
|
@[GraphQL::Field]
|
||||||
# Students can vote
|
# Students can vote
|
||||||
def students_can_vote : Bool
|
def students_can_vote : Bool
|
||||||
teacher_role_count = Db::User.query.where(role: Db::UserRole::Teacher).count
|
# teacher_role_count = Db::User.query.where(role: Db::UserRole::Teacher).count
|
||||||
|
|
||||||
teacher_role_count > 0 && teacher_role_count == Db::Teacher.query.count
|
# teacher_role_count > 0 && teacher_role_count == Db::Teacher.query.count
|
||||||
|
Db::Config.query.select(:can_vote).where { active == true }.first!.can_vote
|
||||||
end
|
end
|
||||||
|
|
||||||
@[GraphQL::Field]
|
@[GraphQL::Field]
|
||||||
|
|
|
@ -102,13 +102,13 @@ module Backend
|
||||||
|
|
||||||
@[GraphQL::Field]
|
@[GraphQL::Field]
|
||||||
# User's external ID
|
# User's external ID
|
||||||
def external_id : Int32
|
def external_id : Int32?
|
||||||
case @model.role.to_api
|
case @model.role
|
||||||
when Db::UserRole::Teacher
|
when Db::UserRole::Teacher
|
||||||
@model.teacher
|
@model.teacher.try(&.id)
|
||||||
when Db::UserRole::Student
|
when Db::UserRole::Student
|
||||||
@model.student
|
@model.student.try(&.id)
|
||||||
end.not_nil!.id
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@[GraphQL::Field]
|
@[GraphQL::Field]
|
||||||
|
|
11
backend/src/backend/db/config.cr
Normal file
11
backend/src/backend/db/config.cr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module Backend::Db
|
||||||
|
class Config
|
||||||
|
include Clear::Model
|
||||||
|
self.table = :configs
|
||||||
|
|
||||||
|
primary_key type: serial
|
||||||
|
|
||||||
|
column active : Bool
|
||||||
|
column can_vote : Bool
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Benutzeraccounts | Mentorenwahl</title>
|
<title>Benutzerexport</title>
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||||
<link href="https://fonts.bunny.net/css?family=jetbrains-mono:400" rel="stylesheet" />
|
<link href="https://fonts.bunny.net/css?family=jetbrains-mono:400" rel="stylesheet" />
|
||||||
|
@ -68,6 +68,12 @@
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background: black;
|
background: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: small;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -123,6 +129,7 @@
|
||||||
<%- group.each do |student| %>
|
<%- group.each do |student| %>
|
||||||
<%- if student -%>
|
<%- if student -%>
|
||||||
<td class="border padded">
|
<td class="border padded">
|
||||||
|
<span class="link">mentorenwahl.dergrimm.net</span>
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
@ -170,10 +177,11 @@
|
||||||
<%- group.each do |teacher| %>
|
<%- group.each do |teacher| %>
|
||||||
<%- if teacher -%>
|
<%- if teacher -%>
|
||||||
<td class="border padded">
|
<td class="border padded">
|
||||||
|
<span class="link">mentorenwahl.dergrimm.net</span>
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<%= teacher.last_name %>, <%= teacher.first_name %>
|
<%= (teacher.first_name ? "#{teacher.last_name}, #{teacher.first_name}" : teacher.last_name).rstrip.rchop(',') %>
|
||||||
<hr />
|
<hr />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
3
frontend/graphql/mutations/set_voting.graphql
Normal file
3
frontend/graphql/mutations/set_voting.graphql
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mutation SetVoting($state: Boolean!) {
|
||||||
|
setVoting(state: $state)
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ query Users {
|
||||||
lastName
|
lastName
|
||||||
username
|
username
|
||||||
role
|
role
|
||||||
|
externalId
|
||||||
admin
|
admin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ scalar UUID
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
admin: Boolean!
|
admin: Boolean!
|
||||||
externalId: Int!
|
externalId: Int
|
||||||
firstName: String!
|
firstName: String!
|
||||||
id: Int!
|
id: Int!
|
||||||
lastName: String!
|
lastName: String!
|
||||||
|
@ -162,11 +162,11 @@ type LoginPayload {
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
createVote(input: VoteCreateInput!): Vote
|
createVote(input: VoteCreateInput!): Vote
|
||||||
deleteUser(id: Int!): Int
|
|
||||||
login(password: String!, username: String!): LoginPayload
|
login(password: String!, username: String!): LoginPayload
|
||||||
logout: UUID
|
logout: UUID
|
||||||
registerTeacher(input: TeacherInput!): Teacher!
|
registerTeacher(input: TeacherInput!): Teacher!
|
||||||
revokeToken(token: UUID!): UUID!
|
revokeToken(token: UUID!): UUID!
|
||||||
|
setVoting(state: Boolean!): Boolean
|
||||||
startAssignment: Boolean
|
startAssignment: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,6 @@ pub mod login;
|
||||||
pub mod logout;
|
pub mod logout;
|
||||||
pub mod register_teacher;
|
pub mod register_teacher;
|
||||||
pub mod revoke_token;
|
pub mod revoke_token;
|
||||||
|
pub mod set_voting;
|
||||||
pub mod start_assignment;
|
pub mod start_assignment;
|
||||||
pub mod vote;
|
pub mod vote;
|
||||||
|
|
10
frontend/src/graphql/mutations/set_voting.rs
Normal file
10
frontend/src/graphql/mutations/set_voting.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use graphql_client::GraphQLQuery;
|
||||||
|
|
||||||
|
#[derive(GraphQLQuery)]
|
||||||
|
#[graphql(
|
||||||
|
schema_path = "graphql/schema.graphql",
|
||||||
|
query_path = "graphql/mutations/set_voting.graphql",
|
||||||
|
response_derives = "Debug",
|
||||||
|
skip_serializing_none
|
||||||
|
)]
|
||||||
|
pub struct SetVoting;
|
|
@ -7,15 +7,15 @@ use crate::graphql;
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
DoneFetchingCanVote {
|
DoneFetchingCanVote {
|
||||||
errors: Option<Vec<String>>,
|
errors: graphql::Errors,
|
||||||
can_vote: bool,
|
can_vote: bool,
|
||||||
},
|
},
|
||||||
DoneFetchingConfig {
|
DoneFetchingConfig {
|
||||||
errors: Option<Vec<String>>,
|
errors: graphql::Errors,
|
||||||
min: usize,
|
min: usize,
|
||||||
},
|
},
|
||||||
DoneFetchingTeachers {
|
DoneFetchingTeachers {
|
||||||
errors: Option<Vec<String>>,
|
errors: graphql::Errors,
|
||||||
teachers: Vec<graphql::queries::teachers::teachers::TeachersTeachers>,
|
teachers: Vec<graphql::queries::teachers::teachers::TeachersTeachers>,
|
||||||
},
|
},
|
||||||
RadioSelect {
|
RadioSelect {
|
||||||
|
@ -23,7 +23,7 @@ pub enum Msg {
|
||||||
teacher: i64,
|
teacher: i64,
|
||||||
},
|
},
|
||||||
Submit,
|
Submit,
|
||||||
Vote(Option<Vec<String>>),
|
Vote(graphql::Errors),
|
||||||
AddSlot,
|
AddSlot,
|
||||||
RemoveSlot,
|
RemoveSlot,
|
||||||
Reset,
|
Reset,
|
||||||
|
@ -38,7 +38,7 @@ pub struct StudentVoteProps {
|
||||||
pub struct StudentVote {
|
pub struct StudentVote {
|
||||||
fetching: bool,
|
fetching: bool,
|
||||||
can_vote: bool,
|
can_vote: bool,
|
||||||
errors: Option<Vec<String>>,
|
errors: graphql::Errors,
|
||||||
min: usize,
|
min: usize,
|
||||||
slots: usize,
|
slots: usize,
|
||||||
teachers: Vec<graphql::queries::teachers::teachers::TeachersTeachers>,
|
teachers: Vec<graphql::queries::teachers::teachers::TeachersTeachers>,
|
||||||
|
|
|
@ -83,16 +83,19 @@ impl Component for TeacherRegistration {
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<form {onsubmit}>
|
<form {onsubmit}>
|
||||||
<div>
|
<div class={classes!("field")}>
|
||||||
<label for="max_students">
|
<label for="max_students">
|
||||||
{ "Maximale Anzahl von Schülern:" }
|
{ "Maximale Anzahl von Schülern:" }
|
||||||
<br />
|
|
||||||
<input ref={self.max_students.clone()} type="number" id="max_students" name="max_students" min=0 />
|
|
||||||
</label>
|
</label>
|
||||||
|
<div class={classes!("control")}>
|
||||||
|
<input ref={self.max_students.clone()} type="number" id="max_students" name="max_students" min=0 class={classes!("input")} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class={classes!("field")}>
|
||||||
<input type="submit" value="Submit" />
|
<div class={classes!("control")}>
|
||||||
|
<input type="submit" value="Speichern" class={classes!("button", "is-success")} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<components::graphql_errors::GraphQLErrors errors={self.errors.clone()} />
|
<components::graphql_errors::GraphQLErrors errors={self.errors.clone()} />
|
||||||
|
|
|
@ -5,6 +5,12 @@ use crate::components;
|
||||||
use crate::graphql;
|
use crate::graphql;
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
|
DoneFetchingCanVote {
|
||||||
|
errors: graphql::Errors,
|
||||||
|
can_vote: bool,
|
||||||
|
},
|
||||||
|
UpdateCanVote,
|
||||||
|
UpdateCanVoteDone(graphql::Errors),
|
||||||
StartAssignment,
|
StartAssignment,
|
||||||
StartAssignmentDone(Option<Vec<String>>),
|
StartAssignmentDone(Option<Vec<String>>),
|
||||||
}
|
}
|
||||||
|
@ -16,18 +22,71 @@ pub struct AssignmentsProps {
|
||||||
|
|
||||||
pub struct Assignments {
|
pub struct Assignments {
|
||||||
errors: Option<Vec<String>>,
|
errors: Option<Vec<String>>,
|
||||||
|
fetching_students_can_vote: bool,
|
||||||
|
students_can_vote: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Assignments {
|
impl Component for Assignments {
|
||||||
type Message = Msg;
|
type Message = Msg;
|
||||||
type Properties = AssignmentsProps;
|
type Properties = AssignmentsProps;
|
||||||
|
|
||||||
fn create(_ctx: &Context<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
Self { errors: None }
|
let client = graphql::client(Some(&ctx.props().token)).unwrap();
|
||||||
|
ctx.link().send_future(async move {
|
||||||
|
let response = post_graphql::<graphql::queries::students_can_vote::StudentsCanVote, _>(
|
||||||
|
&client,
|
||||||
|
graphql::URL.as_str(),
|
||||||
|
graphql::queries::students_can_vote::students_can_vote::Variables,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Msg::DoneFetchingCanVote {
|
||||||
|
errors: graphql::convert(response.errors),
|
||||||
|
can_vote: response.data.unwrap().students_can_vote,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
errors: None,
|
||||||
|
fetching_students_can_vote: true,
|
||||||
|
students_can_vote: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
|
Msg::DoneFetchingCanVote { errors, can_vote } => {
|
||||||
|
self.errors = errors;
|
||||||
|
self.students_can_vote = can_vote;
|
||||||
|
self.fetching_students_can_vote = false;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Msg::UpdateCanVote => {
|
||||||
|
self.students_can_vote = !self.students_can_vote;
|
||||||
|
|
||||||
|
let state = self.students_can_vote;
|
||||||
|
let client = graphql::client(Some(&ctx.props().token)).unwrap();
|
||||||
|
ctx.link().send_future(async move {
|
||||||
|
let response = post_graphql::<graphql::mutations::set_voting::SetVoting, _>(
|
||||||
|
&client,
|
||||||
|
graphql::URL.as_str(),
|
||||||
|
graphql::mutations::set_voting::set_voting::Variables { state },
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Msg::UpdateCanVoteDone(graphql::convert(response.errors))
|
||||||
|
});
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Msg::UpdateCanVoteDone(errors) => {
|
||||||
|
self.errors = errors;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
Msg::StartAssignment => {
|
Msg::StartAssignment => {
|
||||||
let client = graphql::client(Some(&ctx.props().token)).unwrap();
|
let client = graphql::client(Some(&ctx.props().token)).unwrap();
|
||||||
ctx.link().send_future(async move {
|
ctx.link().send_future(async move {
|
||||||
|
@ -60,20 +119,34 @@ impl Component for Assignments {
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{ "Aktion" }</th>
|
<th>{ "Aktion" }</th>
|
||||||
<th>{ "Optionen" }</th>
|
<th>{ "Option" }</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
if self.fetching_students_can_vote {
|
||||||
|
<td><components::fetching::Fetching /></td>
|
||||||
|
} else {
|
||||||
|
<td>{ "Wahl erlauben" }</td>
|
||||||
|
<td>
|
||||||
|
<button onclick={ctx.link().callback(|_| Msg::UpdateCanVote)}
|
||||||
|
class={classes!("button", if self.students_can_vote { "is-success" } else { "is-danger" })}
|
||||||
|
>
|
||||||
|
if self.students_can_vote {
|
||||||
|
{ "An" }
|
||||||
|
} else {
|
||||||
|
{ "Aus" }
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{ "Zuweisung starten" }</td>
|
<td>{ "Zuweisung starten" }</td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<button onclick={ctx.link().callback(|_| Msg::StartAssignment)} class={classes!("button")}>
|
||||||
<li>
|
{ "Ausführen" }
|
||||||
<button class={classes!("button")} onclick={ctx.link().callback(|_| Msg::StartAssignment)}>
|
</button>
|
||||||
{ "Ausführen" }
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::graphql;
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
DoneFetching {
|
DoneFetching {
|
||||||
errors: graphql::Errors,
|
errors: graphql::Errors,
|
||||||
|
users: Option<Vec<graphql::queries::users::users::UsersUsers>>,
|
||||||
students: Option<Vec<graphql::queries::users_by_role::students::StudentsStudents>>,
|
students: Option<Vec<graphql::queries::users_by_role::students::StudentsStudents>>,
|
||||||
teachers: Option<Vec<graphql::queries::users_by_role::teachers::TeachersTeachers>>,
|
teachers: Option<Vec<graphql::queries::users_by_role::teachers::TeachersTeachers>>,
|
||||||
},
|
},
|
||||||
|
@ -29,6 +30,7 @@ pub struct Users {
|
||||||
tab: UsersTab,
|
tab: UsersTab,
|
||||||
fetching: bool,
|
fetching: bool,
|
||||||
errors: graphql::Errors,
|
errors: graphql::Errors,
|
||||||
|
users: Option<Vec<graphql::queries::users::users::UsersUsers>>,
|
||||||
students: Option<Vec<graphql::queries::users_by_role::students::StudentsStudents>>,
|
students: Option<Vec<graphql::queries::users_by_role::students::StudentsStudents>>,
|
||||||
teachers: Option<Vec<graphql::queries::users_by_role::teachers::TeachersTeachers>>,
|
teachers: Option<Vec<graphql::queries::users_by_role::teachers::TeachersTeachers>>,
|
||||||
}
|
}
|
||||||
|
@ -40,6 +42,13 @@ impl Component for Users {
|
||||||
fn create(ctx: &Context<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
let client = graphql::client(Some(&ctx.props().token)).unwrap();
|
let client = graphql::client(Some(&ctx.props().token)).unwrap();
|
||||||
ctx.link().send_future(async move {
|
ctx.link().send_future(async move {
|
||||||
|
let users_response = post_graphql::<graphql::queries::users::Users, _>(
|
||||||
|
&client,
|
||||||
|
graphql::URL.as_str(),
|
||||||
|
graphql::queries::users::users::Variables,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let students_response = post_graphql::<graphql::queries::users_by_role::Students, _>(
|
let students_response = post_graphql::<graphql::queries::users_by_role::Students, _>(
|
||||||
&client,
|
&client,
|
||||||
graphql::URL.as_str(),
|
graphql::URL.as_str(),
|
||||||
|
@ -56,20 +65,32 @@ impl Component for Users {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let x = [
|
let x = [
|
||||||
|
users_response.errors.map_or_else(|| vec![], |e| e),
|
||||||
students_response.errors.map_or_else(|| vec![], |e| e),
|
students_response.errors.map_or_else(|| vec![], |e| e),
|
||||||
teachers_response.errors.map_or_else(|| vec![], |e| e),
|
teachers_response.errors.map_or_else(|| vec![], |e| e),
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
|
|
||||||
if x.is_empty() {
|
if x.is_empty() {
|
||||||
|
let mut users = users_response.data.unwrap().users.unwrap();
|
||||||
|
users.sort_by_key(|x| x.id);
|
||||||
|
|
||||||
|
let mut students = students_response.data.unwrap().students.unwrap();
|
||||||
|
students.sort_by_key(|x| x.id);
|
||||||
|
|
||||||
|
let mut teachers = teachers_response.data.unwrap().teachers;
|
||||||
|
teachers.sort_by_key(|x| x.id);
|
||||||
|
|
||||||
Msg::DoneFetching {
|
Msg::DoneFetching {
|
||||||
errors: None,
|
errors: None,
|
||||||
students: Some(students_response.data.unwrap().students.unwrap()),
|
users: Some(users),
|
||||||
teachers: Some(teachers_response.data.unwrap().teachers),
|
students: Some(students),
|
||||||
|
teachers: Some(teachers),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Msg::DoneFetching {
|
Msg::DoneFetching {
|
||||||
errors: graphql::convert(Some(x)),
|
errors: graphql::convert(Some(x)),
|
||||||
|
users: None,
|
||||||
students: None,
|
students: None,
|
||||||
teachers: None,
|
teachers: None,
|
||||||
}
|
}
|
||||||
|
@ -80,6 +101,7 @@ impl Component for Users {
|
||||||
tab: UsersTab::All,
|
tab: UsersTab::All,
|
||||||
fetching: true,
|
fetching: true,
|
||||||
errors: None,
|
errors: None,
|
||||||
|
users: None,
|
||||||
students: None,
|
students: None,
|
||||||
teachers: None,
|
teachers: None,
|
||||||
}
|
}
|
||||||
|
@ -89,11 +111,14 @@ impl Component for Users {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::DoneFetching {
|
Msg::DoneFetching {
|
||||||
errors,
|
errors,
|
||||||
|
users,
|
||||||
students,
|
students,
|
||||||
teachers,
|
teachers,
|
||||||
} => {
|
} => {
|
||||||
self.fetching = false;
|
self.fetching = false;
|
||||||
self.errors = errors;
|
self.errors = errors;
|
||||||
|
|
||||||
|
self.users = users;
|
||||||
self.students = students;
|
self.students = students;
|
||||||
self.teachers = teachers;
|
self.teachers = teachers;
|
||||||
|
|
||||||
|
@ -142,58 +167,39 @@ impl Component for Users {
|
||||||
<th>{ "Vorname" }</th>
|
<th>{ "Vorname" }</th>
|
||||||
<th>{ "Benutzername" }</th>
|
<th>{ "Benutzername" }</th>
|
||||||
<th>{ "Rolle" }</th>
|
<th>{ "Rolle" }</th>
|
||||||
<th><abbr title="ID des externen Benutzerobjekts">{ "Externe Rollen-ID" }</abbr></th>
|
<th><abbr title="ID des externen Benutzerobjekts">{ "Rollen-ID" }</abbr></th>
|
||||||
<th>{ "Admin" }</th>
|
<th>{ "Admin" }</th>
|
||||||
<th><abbr title="Wenn Schüler, dann ob Lehrer gewählt wurde">{ "Gewählt" }</abbr></th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{
|
{
|
||||||
for self.students.as_ref().unwrap().iter().map(|s| html! {
|
for self.users.as_ref().unwrap().iter().map(|u| html! {
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>{ &s.user.id }</code></td>
|
<td><code>{ &u.id }</code></td>
|
||||||
<td>{ &s.user.last_name }</td>
|
<td>{ &u.last_name }</td>
|
||||||
<td>{ &s.user.first_name }</td>
|
<td>{ &u.first_name }</td>
|
||||||
<td><code>{ &s.user.username }</code></td>
|
<td><code>{ &u.username }</code></td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<code>
|
<code>
|
||||||
{
|
{
|
||||||
match &s.user.role {
|
match &u.role {
|
||||||
graphql::queries::users_by_role::students::UserRole::Student => "S",
|
graphql::queries::users::users::UserRole::Student => "S",
|
||||||
graphql::queries::users_by_role::students::UserRole::Teacher => "T",
|
graphql::queries::users::users::UserRole::Teacher => "T",
|
||||||
graphql::queries::users_by_role::students::UserRole::Other(_) => "N/A",
|
graphql::queries::users::users::UserRole::Other(_) => "N/A",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</code>
|
</code>
|
||||||
</td>
|
</td>
|
||||||
<td><code>{ &s.id }</code></td>
|
// <td><code>{ if let Some(id) = u.external_id { id } else { "N/A" } }</code></td>
|
||||||
<td><code>{ if s.user.admin { 1 } else { 0 } }</code></td>
|
|
||||||
<td><code>{ if s.vote.is_some() { 1 } else { 0 } }</code></td>
|
|
||||||
</tr>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{
|
|
||||||
for self.teachers.as_ref().unwrap().iter().map(|t| html! {
|
|
||||||
<tr>
|
|
||||||
<td><code>{ &t.user.id }</code></td>
|
|
||||||
<td>{ &t.user.last_name }</td>
|
|
||||||
<td>{ &t.user.first_name }</td>
|
|
||||||
<td><code>{ &t.user.username }</code></td>
|
|
||||||
<td>
|
<td>
|
||||||
<code>
|
if let Some(id) = u.external_id {
|
||||||
{
|
<code>{ id }</code>
|
||||||
match &t.user.role {
|
} else {
|
||||||
graphql::queries::users_by_role::teachers::UserRole::Student => "S",
|
<i>{ "N/A" }</i>
|
||||||
graphql::queries::users_by_role::teachers::UserRole::Teacher => "T",
|
}
|
||||||
graphql::queries::users_by_role::teachers::UserRole::Other(_) => "N/A",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code>
|
|
||||||
</td>
|
</td>
|
||||||
<td><code>{ &t.id }</code></td>
|
<td><code>{ if u.admin { 1 } else { 0 } }</code></td>
|
||||||
<td><code>{ if t.user.admin { 1 } else { 0 } }</code></td>
|
|
||||||
<td><code>{ "N/A" }</code></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -238,7 +244,6 @@ impl Component for Users {
|
||||||
<th>{ "Nachname" }</th>
|
<th>{ "Nachname" }</th>
|
||||||
<th>{ "Vorname" }</th>
|
<th>{ "Vorname" }</th>
|
||||||
<th>{ "Benutzername" }</th>
|
<th>{ "Benutzername" }</th>
|
||||||
<th>{ "Email" }</th>
|
|
||||||
<th>{ "Benutzer-ID" }</th>
|
<th>{ "Benutzer-ID" }</th>
|
||||||
<th>{ "Admin" }</th>
|
<th>{ "Admin" }</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -251,17 +256,6 @@ impl Component for Users {
|
||||||
<td>{ &t.user.last_name }</td>
|
<td>{ &t.user.last_name }</td>
|
||||||
<td>{ &t.user.first_name }</td>
|
<td>{ &t.user.first_name }</td>
|
||||||
<td><code>{ &t.user.username }</code></td>
|
<td><code>{ &t.user.username }</code></td>
|
||||||
<td>
|
|
||||||
<code>
|
|
||||||
{
|
|
||||||
match &t.user.role {
|
|
||||||
graphql::queries::users_by_role::teachers::UserRole::Student => "S",
|
|
||||||
graphql::queries::users_by_role::teachers::UserRole::Teacher => "T",
|
|
||||||
graphql::queries::users_by_role::teachers::UserRole::Other(_) => "N/A",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code>
|
|
||||||
</td>
|
|
||||||
<td><code>{ &t.user.id }</code></td>
|
<td><code>{ &t.user.id }</code></td>
|
||||||
<td><code>{ if t.user.admin { 1 } else { 0 } }</code></td>
|
<td><code>{ if t.user.admin { 1 } else { 0 } }</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Loading…
Reference in a new issue