forked from Ruderverein-Donau-Linz/rowt
push
This commit is contained in:
parent
9a72413934
commit
432962f5a9
@ -18,11 +18,7 @@ impl MigrationTrait for Migration {
|
|||||||
.integer()
|
.integer()
|
||||||
.default(0),
|
.default(0),
|
||||||
)
|
)
|
||||||
.col(
|
.col(ColumnDef::new(Day::PlannedStartingTime).string())
|
||||||
ColumnDef::new(Day::PlannedStartingTime)
|
|
||||||
.string()
|
|
||||||
.default(""),
|
|
||||||
)
|
|
||||||
.col(
|
.col(
|
||||||
ColumnDef::new(Day::OpenRegistration)
|
ColumnDef::new(Day::OpenRegistration)
|
||||||
.boolean()
|
.boolean()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use sea_orm_migration::prelude::*;
|
use sea_orm_migration::prelude::*;
|
||||||
|
use sea_query::Expr;
|
||||||
|
|
||||||
use crate::m20230208_114547_create_day::Day;
|
use crate::m20230208_114547_create_day::Day;
|
||||||
use crate::m20230209_063357_create_user::User;
|
use crate::m20230209_063357_create_user::User;
|
||||||
@ -40,7 +41,7 @@ impl MigrationTrait for Migration {
|
|||||||
ColumnDef::new(Trip::Created)
|
ColumnDef::new(Trip::Created)
|
||||||
.timestamp()
|
.timestamp()
|
||||||
.not_null()
|
.not_null()
|
||||||
.default("CURRENT_TIMESTAMP"),
|
.default(Expr::current_timestamp()),
|
||||||
)
|
)
|
||||||
.primary_key(Index::create().col(Trip::Day).col(Trip::UserId))
|
.primary_key(Index::create().col(Trip::Day).col(Trip::UserId))
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
|
@ -18,6 +18,9 @@ pub struct Model {
|
|||||||
pub is_admin: bool,
|
pub is_admin: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct AdminUser(Model);
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
pub async fn find_or_create_user(name: &str, db: &DatabaseConnection) -> Model {
|
pub async fn find_or_create_user(name: &str, db: &DatabaseConnection) -> Model {
|
||||||
let user = Entity::find()
|
let user = Entity::find()
|
||||||
@ -42,6 +45,7 @@ impl Model {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum UserError {
|
pub enum UserError {
|
||||||
NoCookieSet,
|
NoCookieSet,
|
||||||
|
NoAdmin,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
@ -61,6 +65,27 @@ impl<'r> FromRequest<'r> for Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromRequest<'r> for AdminUser {
|
||||||
|
type Error = UserError;
|
||||||
|
|
||||||
|
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
|
||||||
|
match req.cookies().get("name") {
|
||||||
|
Some(name) => {
|
||||||
|
let db = req.guard::<&'r State<DatabaseConnection>>();
|
||||||
|
let name = name.value();
|
||||||
|
let user = Model::find_or_create_user(name, db.await.unwrap().inner()).await;
|
||||||
|
if user.is_admin {
|
||||||
|
Outcome::Success(AdminUser(user))
|
||||||
|
} else {
|
||||||
|
Outcome::Failure((Status::Unauthorized, UserError::NoAdmin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Outcome::Failure((Status::Unauthorized, UserError::NoCookieSet)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
mod restday;
|
mod restday;
|
||||||
mod restreg;
|
mod restreg;
|
||||||
|
mod restuser;
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use chrono::{Duration, Local, NaiveDate};
|
use chrono::{Datelike, Duration, Local, NaiveDate};
|
||||||
use rocket::{
|
use rocket::{
|
||||||
form::{self, Form, ValueField},
|
form::{self, Form, ValueField},
|
||||||
fs::FileServer,
|
fs::FileServer,
|
||||||
@ -37,7 +38,17 @@ impl Deref for NaiveDateForm {
|
|||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn index(db: &State<DatabaseConnection>, user: user::Model) -> Template {
|
async fn index(db: &State<DatabaseConnection>, user: user::Model) -> Template {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
for i in 0..6 {
|
|
||||||
|
let mut show_next_n_days = 6;
|
||||||
|
if user.is_cox {
|
||||||
|
let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 5, 31).unwrap();
|
||||||
|
show_next_n_days = end_of_year
|
||||||
|
.signed_duration_since(Local::now().date_naive())
|
||||||
|
.num_days()
|
||||||
|
+ 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..show_next_n_days {
|
||||||
let date = (Local::now() + Duration::days(i)).date_naive();
|
let date = (Local::now() + Duration::days(i)).date_naive();
|
||||||
let day = day::Model::find_or_create_day(date, db.inner()).await;
|
let day = day::Model::find_or_create_day(date, db.inner()).await;
|
||||||
data.push(DayWithTrips::new(day, db.inner()).await);
|
data.push(DayWithTrips::new(day, db.inner()).await);
|
||||||
@ -62,6 +73,12 @@ fn savename(name: Form<NameForm>, cookies: &CookieJar) -> Redirect {
|
|||||||
Redirect::to("/")
|
Redirect::to("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/logout")]
|
||||||
|
fn logout(cookies: &CookieJar) -> Redirect {
|
||||||
|
cookies.remove(Cookie::new("name", ""));
|
||||||
|
Redirect::to("/")
|
||||||
|
}
|
||||||
|
|
||||||
#[catch(401)] //unauthorized
|
#[catch(401)] //unauthorized
|
||||||
fn unauthorized_error() -> Redirect {
|
fn unauthorized_error() -> Redirect {
|
||||||
Redirect::to("/name")
|
Redirect::to("/name")
|
||||||
@ -72,8 +89,9 @@ pub async fn start() -> Rocket<Build> {
|
|||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
.manage(Database::connect("sqlite://db.sqlite").await.unwrap())
|
.manage(Database::connect("sqlite://db.sqlite").await.unwrap())
|
||||||
.mount("/public", FileServer::from("static/"))
|
.mount("/public", FileServer::from("static/"))
|
||||||
.mount("/", routes![index, name, savename])
|
.mount("/", routes![index, name, savename, logout])
|
||||||
.mount("/day", restday::routes())
|
.mount("/day", restday::routes())
|
||||||
.mount("/register", restreg::routes())
|
.mount("/register", restreg::routes())
|
||||||
|
.mount("/user", restuser::routes())
|
||||||
.register("/", catchers![unauthorized_error])
|
.register("/", catchers![unauthorized_error])
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ async fn register(db: &State<DatabaseConnection>, register: Form<RegisterForm>)
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.expect("There's no trip on this date (yet)");
|
.expect("There's no trip on this date (yet)");
|
||||||
|
|
||||||
|
if !day.open_registration {
|
||||||
|
return Redirect::to("/");
|
||||||
|
}
|
||||||
|
|
||||||
let user = user::Model::find_or_create_user(®ister.name, db.inner()).await;
|
let user = user::Model::find_or_create_user(®ister.name, db.inner()).await;
|
||||||
|
|
||||||
let day = format!("{}", day.day.format("%Y-%m-%d"));
|
let day = format!("{}", day.day.format("%Y-%m-%d"));
|
||||||
|
42
src/rest/restuser.rs
Normal file
42
src/rest/restuser.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use rocket::{form::Form, response::Redirect, Route, State};
|
||||||
|
use rocket_dyn_templates::{context, Template};
|
||||||
|
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set};
|
||||||
|
|
||||||
|
use crate::models::{day, user};
|
||||||
|
|
||||||
|
use super::NaiveDateForm;
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn index(db: &State<DatabaseConnection>, user: user::AdminUser) -> Template {
|
||||||
|
let users = user::Entity::find().all(db.inner()).await.unwrap();
|
||||||
|
|
||||||
|
Template::render("user/index", context! {user, users})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct UserEditForm {
|
||||||
|
is_cox: bool,
|
||||||
|
is_admin: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[put("/<id>", data = "<data>")]
|
||||||
|
async fn update(
|
||||||
|
db: &State<DatabaseConnection>,
|
||||||
|
id: i32,
|
||||||
|
data: Form<UserEditForm>,
|
||||||
|
_user: user::AdminUser,
|
||||||
|
) -> Redirect {
|
||||||
|
let new_user = user::ActiveModel {
|
||||||
|
id: Set(id),
|
||||||
|
is_cox: Set(data.is_cox),
|
||||||
|
is_admin: Set(data.is_admin),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
new_user.update(db.inner()).await.unwrap();
|
||||||
|
|
||||||
|
Redirect::to("/user")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn routes() -> Vec<Route> {
|
||||||
|
routes![index, update]
|
||||||
|
}
|
@ -37,6 +37,12 @@
|
|||||||
<!-- Primary Page Layout
|
<!-- Primary Page Layout
|
||||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{% if user %}
|
||||||
|
{% if user.is_admin %}
|
||||||
|
<a href="/user">USER</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="/logout">LOGOUT</a>
|
||||||
|
{% endif %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -5,22 +5,30 @@
|
|||||||
{% set day = day_with_trip.day %}
|
{% set day = day_with_trip.day %}
|
||||||
{% set day_string = day.day | date(format="%Y-%m-%d") %}
|
{% set day_string = day.day | date(format="%Y-%m-%d") %}
|
||||||
{% set trips = day_with_trip.trips %}
|
{% set trips = day_with_trip.trips %}
|
||||||
{{ day.day | date(format="%d.%m.%Y")}}
|
<h1>{{ day.day | date(format="%d.%m.%Y")}}</h1>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
||||||
{% if day.planned_amount_cox > 0%}
|
{% if day.planned_amount_cox > 0%}
|
||||||
Geplante Steuerpersonen: {{ day.planned_amount_cox}}<br />
|
|
||||||
|
{% set cox = trips | filter(attribute="user.is_cox", value=true) %}
|
||||||
|
{% set amount_cox = cox | length %}
|
||||||
|
{% set rowers = trips | filter(attribute="user.is_cox", value=false) %}
|
||||||
|
{% if amount_cox < day.planned_amount_cox %}
|
||||||
|
{% set cox_left = day.planned_amount_cox - amount_cox %}
|
||||||
|
Es {{ cox_left | pluralize(singular="wird", plural="werden")}} noch {{ cox_left }} Steuerperson{{ cox_left | pluralize(plural="en")}} gesucht!<br />
|
||||||
|
{% endif %}
|
||||||
Geplante Abfahrtszeit: {{ day.planned_starting_time }}<br />
|
Geplante Abfahrtszeit: {{ day.planned_starting_time }}<br />
|
||||||
|
|
||||||
Angemeldete Personen:
|
{{ trips | length }} angemeldete Person{{ trips | length | pluralize(plural="en") }}: {{ cox | length }} Steuerperson{{ cox | length | pluralize(plural="en") }} ({% for c in cox %}{{ c.user.name }} {% endfor %}), {{ rowers | length }} Ruderer:
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
{% for trip in trips %}
|
{% for r in rowers %}
|
||||||
<li>{{ trip.user.name }}</li>
|
<li>{{ r.user.name }} (angemeldet seit {{ r.trip.created }})</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
{% if day.open_registration %}
|
{% if day.open_registration or user.is_cox %}
|
||||||
<details>
|
<details>
|
||||||
<summary class="button">+</summary>
|
<summary class="button">+</summary>
|
||||||
<form method="post" action="/register">
|
<form method="post" action="/register">
|
||||||
@ -44,6 +52,7 @@
|
|||||||
(Noch) keine Ausfahrt geplant
|
(Noch) keine Ausfahrt geplant
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if user.is_admin %}
|
||||||
<details>
|
<details>
|
||||||
<summary class="button">✎</summary>
|
<summary class="button">✎</summary>
|
||||||
<form method="post" action="/day">
|
<form method="post" action="/day">
|
||||||
@ -69,7 +78,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
|
{% endif %}
|
||||||
<hr />
|
<hr />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{% extends "base" %}
|
{% extends "base" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
What's your name?
|
|
||||||
<form action="/name" method="post">
|
<form action="/name" method="post">
|
||||||
<input type="hidden" name="_method" value="put" />
|
<input type="hidden" name="_method" value="put" />
|
||||||
<input type="text" name="name"/>
|
<label for="name">Bitte deinen Namen eingeben</label>
|
||||||
<input type="submit" value="Speichern"/>
|
<input type="text" id="name" name="name"/>
|
||||||
|
<input type="submit" value="Weiter"/>
|
||||||
</form>
|
</form>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
|
35
templates/user/index.html.tera
Normal file
35
templates/user/index.html.tera
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{% extends "base" %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class="u-full-width">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Cox</th>
|
||||||
|
<th>Admin</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user in users %}
|
||||||
|
<tr>
|
||||||
|
<form action="/user/{{ user.id }}" method="post">
|
||||||
|
<input type="hidden" name="_method" value="put" />
|
||||||
|
<td>{{user.name}}</td>
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" name="is_cox" {% if user.is_cox %} checked="true"{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" name="is_admin" {% if user.is_admin %} checked="true"{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input class="button-primary" type="submit" value="Speichern">
|
||||||
|
</td>
|
||||||
|
</form>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user