Compare commits
11 Commits
improve-lo
...
bf3a4c686a
Author | SHA1 | Date | |
---|---|---|---|
bf3a4c686a | |||
5fb9e0fbba | |||
![]() |
f58e7d1307 | ||
374fed9e3b | |||
![]() |
b9f2382cba | ||
![]() |
aab3a15488 | ||
83b93fba09 | |||
3b5ff70d1d | |||
2af9ac20b1 | |||
![]() |
5331ac71fa | ||
6098aedb74 |
@@ -115,7 +115,7 @@ test("Cox can start and finish trip", async ({ page }, testInfo) => {
|
||||
await page.getByPlaceholder("Passwort").press("Enter");
|
||||
|
||||
await page.goto("/log/show");
|
||||
await page.getByText('(cox2)').click();
|
||||
await page.getByRole('link', { name: 'Joe' }).nth(1).click();
|
||||
page.once("dialog", (dialog) => {
|
||||
dialog.accept().catch(() => {});
|
||||
});
|
||||
@@ -208,7 +208,6 @@ test("Kiosk can start and finish trip", async ({ page }, testInfo) => {
|
||||
|
||||
await page.getByRole('link', { name: 'Logbuch' }).click();
|
||||
await expect(page.locator('body')).toContainText('Joe');
|
||||
await expect(page.locator('body')).toContainText('(cox2)');
|
||||
await expect(page.locator('body')).toContainText('Ottensheim (25 km)');
|
||||
await expect(page.locator('body')).toContainText('Ruderer: cox2, rower2');
|
||||
|
||||
@@ -225,7 +224,7 @@ test("Kiosk can start and finish trip", async ({ page }, testInfo) => {
|
||||
await page.getByPlaceholder("Passwort").press("Enter");
|
||||
|
||||
await page.goto("/log/show");
|
||||
await page.getByText('(cox2)').click();
|
||||
await page.getByRole('link', { name: 'Joe' }).nth(1).click();
|
||||
page.once("dialog", (dialog) => {
|
||||
dialog.accept().catch(() => {});
|
||||
});
|
||||
@@ -286,7 +285,6 @@ test("Cox can start and finish trip with cox steering only", async ({ page }, te
|
||||
|
||||
await page.goto('/log/show');
|
||||
await expect(page.locator('body')).toContainText('cox_only_steering_boat');
|
||||
await expect(page.locator('body')).toContainText('(cox2 - handgesteuert)');
|
||||
await expect(page.locator('body')).toContainText('Ottensheim (25 km)');
|
||||
|
||||
|
||||
@@ -302,7 +300,7 @@ test("Cox can start and finish trip with cox steering only", async ({ page }, te
|
||||
await page.getByPlaceholder("Passwort").press("Enter");
|
||||
|
||||
await page.goto("/log/show");
|
||||
await page.getByText('(cox2 - handgesteuert)').click();
|
||||
await page.getByRole("link", { name: "cox_only_steering_boat" }).click();
|
||||
page.once("dialog", (dialog) => {
|
||||
dialog.accept().catch(() => {});
|
||||
});
|
||||
@@ -371,7 +369,7 @@ test("Kiosk can start and finish trip in one stop", async ({ page }, testInfo) =
|
||||
await page.getByPlaceholder("Passwort").press("Enter");
|
||||
|
||||
await page.goto("/log/show");
|
||||
await page.getByText('(cox2)').click();
|
||||
await page.getByRole('link', { name: 'Joe' }).nth(1).click();
|
||||
page.once("dialog", (dialog) => {
|
||||
dialog.accept().catch(() => {});
|
||||
});
|
||||
|
@@ -1,20 +1,21 @@
|
||||
use std::{fmt::Display, ops::DerefMut};
|
||||
|
||||
use argon2::{password_hash::SaltString, Argon2, PasswordHasher};
|
||||
use argon2::{Argon2, PasswordHasher, password_hash::SaltString};
|
||||
use chrono::{Datelike, Local, NaiveDate};
|
||||
use log::info;
|
||||
use rocket::async_trait;
|
||||
use rocket::{
|
||||
Request,
|
||||
http::{Cookie, Status},
|
||||
request::{FromRequest, Outcome},
|
||||
time::{Duration, OffsetDateTime},
|
||||
Request,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||
|
||||
use super::activity::ActivityBuilder;
|
||||
use super::{
|
||||
Day,
|
||||
log::Log,
|
||||
logbook::Logbook,
|
||||
mail::Mail,
|
||||
@@ -23,7 +24,6 @@ use super::{
|
||||
role::Role,
|
||||
stat::Stat,
|
||||
tripdetails::TripDetails,
|
||||
Day,
|
||||
};
|
||||
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
|
||||
use scheckbuch::ScheckbuchUser;
|
||||
@@ -577,10 +577,6 @@ ASKÖ Ruderverein Donau Linz", self.name),
|
||||
.execute(db)
|
||||
.await
|
||||
.unwrap(); //Okay, because we can only create a User of a valid id
|
||||
ActivityBuilder::new(&format!("User {self} hat sich eingeloggt."))
|
||||
.relevant_for_user(self)
|
||||
.save(db)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn delete(&self, db: &SqlitePool, deleted_by: &ManageUserUser) {
|
||||
@@ -982,17 +978,21 @@ mod test {
|
||||
#[sqlx::test]
|
||||
fn wrong_pw() {
|
||||
let pool = testdb!();
|
||||
assert!(User::login(&pool, "admin".into(), "admi".into())
|
||||
assert!(
|
||||
User::login(&pool, "admin".into(), "admi".into())
|
||||
.await
|
||||
.is_err());
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
fn wrong_username() {
|
||||
let pool = testdb!();
|
||||
assert!(User::login(&pool, "admi".into(), "admin".into())
|
||||
assert!(
|
||||
User::login(&pool, "admi".into(), "admin".into())
|
||||
.await
|
||||
.is_err());
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
@@ -1011,9 +1011,11 @@ mod test {
|
||||
let pool = testdb!();
|
||||
let user = User::find_by_id(&pool, 1).await.unwrap();
|
||||
|
||||
assert!(User::login(&pool, "admin".into(), "abc".into())
|
||||
assert!(
|
||||
User::login(&pool, "admin".into(), "abc".into())
|
||||
.await
|
||||
.is_err());
|
||||
.is_err()
|
||||
);
|
||||
|
||||
user.update_pw(&pool, "abc".into()).await;
|
||||
|
||||
|
@@ -3,13 +3,14 @@ use crate::model::{
|
||||
user::{AdminUser, UserWithDetails, VorstandUser},
|
||||
};
|
||||
use rocket::{
|
||||
FromForm, Route, State,
|
||||
form::Form,
|
||||
get, post,
|
||||
request::FlashMessage,
|
||||
response::{Flash, Redirect},
|
||||
routes, FromForm, Route, State,
|
||||
routes,
|
||||
};
|
||||
use rocket_dyn_templates::{tera::Context, Template};
|
||||
use rocket_dyn_templates::{Template, tera::Context};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
#[get("/role")]
|
||||
|
@@ -7,11 +7,11 @@ use crate::{
|
||||
mail::valid_mails,
|
||||
role::Role,
|
||||
user::{
|
||||
AdminUser, AllowedToEditPaymentStatusUser, ManageUserUser, User, UserWithDetails,
|
||||
UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser,
|
||||
clubmember::ClubMemberUser, foerdernd::FoerderndUser, member::Member,
|
||||
regular::RegularUser, scheckbuch::ScheckbuchUser, schnupperant::SchnupperantUser,
|
||||
schnupperinterest::SchnupperInterestUser, unterstuetzend::UnterstuetzendUser,
|
||||
AdminUser, AllowedToEditPaymentStatusUser, ManageUserUser, User, UserWithDetails,
|
||||
UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser,
|
||||
},
|
||||
},
|
||||
tera::Config,
|
||||
@@ -19,6 +19,7 @@ use crate::{
|
||||
use chrono::NaiveDate;
|
||||
use futures::future::join_all;
|
||||
use rocket::{
|
||||
FromForm, Request, Route, State,
|
||||
form::Form,
|
||||
fs::TempFile,
|
||||
get,
|
||||
@@ -26,9 +27,9 @@ use rocket::{
|
||||
post,
|
||||
request::{FlashMessage, FromRequest, Outcome},
|
||||
response::{Flash, Redirect},
|
||||
routes, FromForm, Request, Route, State,
|
||||
routes,
|
||||
};
|
||||
use rocket_dyn_templates::{tera::Context, Template};
|
||||
use rocket_dyn_templates::{Template, tera::Context};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
// Custom request guard to extract the Referer header
|
||||
@@ -135,7 +136,7 @@ async fn view(
|
||||
if user.name == "Externe Steuerperson" {
|
||||
return Err(Flash::error(
|
||||
Redirect::to("/admin/user"),
|
||||
"Diese besondere Person kannst du dir leider nicht anschauen, mein lieber neugieriger Ruderant!"
|
||||
"Diese besondere Person kannst du dir leider nicht anschauen, mein lieber neugieriger Ruderant!",
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@ use rocket_dyn_templates::{Template, context, tera};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::model::{
|
||||
activity::ActivityBuilder,
|
||||
log::Log,
|
||||
user::{LoginError, User},
|
||||
};
|
||||
@@ -82,13 +83,12 @@ async fn login(
|
||||
|
||||
cookies.add_private(Cookie::new("loggedin_user", format!("{}", user.id)));
|
||||
|
||||
Log::create(
|
||||
db,
|
||||
format!(
|
||||
"Succ login of {} with this useragent: {}",
|
||||
login.name, agent.0
|
||||
),
|
||||
)
|
||||
ActivityBuilder::new(&format!(
|
||||
"{user} hat sich eingeloggt (User-Agent: {})",
|
||||
agent.0
|
||||
))
|
||||
.relevant_for_user(&user)
|
||||
.save(db)
|
||||
.await;
|
||||
|
||||
// Check for redirect_url cookie and redirect accordingly
|
||||
|
@@ -1,6 +1,7 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
use rocket::{
|
||||
Request, Route, State,
|
||||
form::Form,
|
||||
get,
|
||||
http::{Cookie, CookieJar},
|
||||
@@ -9,9 +10,8 @@ use rocket::{
|
||||
response::{Flash, Redirect},
|
||||
routes,
|
||||
time::{Duration, OffsetDateTime},
|
||||
Request, Route, State,
|
||||
};
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
use rocket_dyn_templates::{Template, context};
|
||||
use sqlx::SqlitePool;
|
||||
use tera::Context;
|
||||
|
||||
@@ -585,7 +585,7 @@ mod test {
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::model::logbook::Logbook;
|
||||
use crate::tera::{log::Boat, User};
|
||||
use crate::tera::{User, log::Boat};
|
||||
use crate::testdb;
|
||||
|
||||
#[sqlx::test]
|
||||
|
@@ -8,19 +8,16 @@
|
||||
<summary class="px-3 cursor-pointer text-md font-bold text-primary-950 dark:text-white">
|
||||
Neue Person hinzufügen
|
||||
</summary>
|
||||
|
||||
<div class="grid sm:grid-cols-3 gap-3 mt-3">
|
||||
<button type="button"
|
||||
onclick="document.getElementById('add-clubuser').showModal()"
|
||||
class="btn btn-primary">Vereinsmitglied</button>
|
||||
class="btn btn-primary">🥳 Vereinsmitglied</button>
|
||||
<button type="button"
|
||||
onclick="document.getElementById('add-scheckbuch').showModal()"
|
||||
class="btn btn-dark">Scheckbuch</button>
|
||||
class="btn btn-dark">🧑🏫 Scheckbuch</button>
|
||||
<button type="button"
|
||||
onclick="document.getElementById('add-schnupperkurs').showModal()"
|
||||
class="btn btn-dark">Schnupperkurs</button>
|
||||
|
||||
|
||||
class="btn btn-dark">👨🎓 Schnupperkurs</button>
|
||||
</div>
|
||||
<dialog id="add-clubuser"
|
||||
class="max-w-screen-sm w-full dark:bg-primary-900 dark:text-white rounded-md"
|
||||
@@ -67,7 +64,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="add-scheckbuch"
|
||||
class="max-w-screen-sm w-full dark:bg-primary-900 dark:text-white rounded-md"
|
||||
onclick="document.getElementById('add-scheckbuch').close()">
|
||||
@@ -99,7 +95,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="add-schnupperkurs"
|
||||
class="max-w-screen-sm w-full dark:bg-primary-900 dark:text-white rounded-md"
|
||||
onclick="document.getElementById('add-schnupperkurs').close()">
|
||||
@@ -122,7 +117,6 @@
|
||||
enctype="multipart/form-data"
|
||||
class="grid gap-3">
|
||||
<h2 class="h3 mb-3">Neuer Schnupperant</h2>
|
||||
|
||||
<div>
|
||||
<label for="schnupper_type" class="text-sm text-gray-600 dark:text-gray-100">Typ</label>
|
||||
<select name="schnupper_type" id="schnupper_type" class="input rounded-md ">
|
||||
|
@@ -4,7 +4,9 @@
|
||||
{% block content %}
|
||||
<div class="max-w-screen-lg w-full">
|
||||
{% if "admin" in loggedin_user.roles or "Vorstand" in loggedin_user.roles %}
|
||||
<div class="mb-5 lg:mb-0">
|
||||
<a href="/admin/user" class="link link-primary link-no-underline">← Userverwaltung</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h1 class="h1">{{ user.name }}</h1>
|
||||
<div class="grid sm:grid-cols-2 gap-8 my-8">
|
||||
@@ -119,12 +121,12 @@
|
||||
</div>
|
||||
{% if allowed_to_edit %}
|
||||
<div class="py-3">
|
||||
<div class="mt-3 text-right">
|
||||
<div class="text-right">
|
||||
<button type="button"
|
||||
onclick="document.getElementById('change-member-type').showModal()"
|
||||
class="btn btn-dark">Mitgliedsstatus ändern</button>
|
||||
<a href="/admin/user/{{ user.id }}/delete"
|
||||
class="btn btn-alert"
|
||||
class="btn btn-alert mt-3"
|
||||
onclick="return confirm('Ist {{ user.name }} wirklich aus dem Verein ausgetreten?');">
|
||||
{% include "includes/delete-icon" %}
|
||||
Mitglied ist ausgetreten
|
||||
@@ -385,9 +387,11 @@
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if "paid" in user.roles %}
|
||||
✅ {% for key, value in member %}
|
||||
✅
|
||||
{% for key, value in member %}
|
||||
{% if loop.first %}{{ key }}{% endif %}
|
||||
{% endfor %} hat schon bezahlt
|
||||
{% endfor %}
|
||||
hat schon bezahlt
|
||||
{% else %}
|
||||
❌
|
||||
{% for key, value in member %}
|
||||
@@ -402,11 +406,13 @@
|
||||
{% endif %}
|
||||
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow">
|
||||
<h2 class="h2">Aktivitäten</h2>
|
||||
<div class="mx-3 divide-y divide-gray-200 dark:divide-primary-600">
|
||||
<div class="mx-3 max-h-60 overflow-y-scroll">
|
||||
<div class="py-3">
|
||||
<ul class="list-disc ms-4">
|
||||
{% for activity in activities %}
|
||||
<li>{{ activity.created_at | date(format="%d. %m. %Y") }}: {{ activity.text }}</li>
|
||||
<li>
|
||||
<strong>{{ activity.created_at | date(format="%d. %m. %Y") }}:</strong> <small>{{ activity.text }}</small>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>Noch keine Aktivität... Stay tuned 😆</li>
|
||||
{% endfor %}
|
||||
|
@@ -202,9 +202,7 @@
|
||||
onclick="document.getElementById('change-{{ log.id }}').showModal()"
|
||||
class="link link-black font-bold">{{ log.boat.name }}</a>
|
||||
{% else %}
|
||||
<strong class="text-black dark:text-white">
|
||||
{{ log.boat.name }}
|
||||
</strong>
|
||||
<strong class="text-black dark:text-white">{{ log.boat.name }}</strong>
|
||||
{% endif %}
|
||||
<small class="text-gray-600 dark:text-gray-100">({{ log.shipmaster_user.name -}}
|
||||
{% if log.shipmaster_only_steering %}
|
||||
@@ -286,8 +284,14 @@
|
||||
name="steering_person"
|
||||
value="{{ log.steering_person }}" />
|
||||
{{ macros::checkbox(label='Handgesteuert', name='shipmaster_only_steering', id=log.shipmaster_only_steering,checked=log.shipmaster_only_steering) }}
|
||||
<input type="datetime-local" class="input rounded-md" name="departure" value="{{ log.departure }}" />
|
||||
<input type="datetime-local" class="input rounded-md" name="arrival" value="{{ log.arrival }}" />
|
||||
<input type="datetime-local"
|
||||
class="input rounded-md"
|
||||
name="departure"
|
||||
value="{{ log.departure }}" />
|
||||
<input type="datetime-local"
|
||||
class="input rounded-md"
|
||||
name="arrival"
|
||||
value="{{ log.arrival }}" />
|
||||
<input type="hidden" name="destination" value="{{ log.destination }}" />
|
||||
<input type="hidden" name="distance_in_km" value="{{ log.distance_in_km }}" />
|
||||
<input type="hidden" name="comments" value="{{ log.comments }}" />
|
||||
|
@@ -26,7 +26,7 @@
|
||||
{% for log in logs %}
|
||||
{% set_global allowed_to_edit = false %}
|
||||
{% if loggedin_user %}
|
||||
{% if "Vorstand" in loggedin_user.roles %}
|
||||
{% if "Vorstand" in loggedin_user.roles or "admin" in loggedin_user.roles %}
|
||||
{% set_global allowed_to_edit = true %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
Reference in New Issue
Block a user