1 Commits

Author SHA1 Message Date
Marie Birner
8500ba826f [TASK] try to include boat and shipmaster in update popup
Some checks failed
CI/CD Pipeline / test (push) Failing after 22m47s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
2025-05-05 21:41:52 +02:00
11 changed files with 317 additions and 310 deletions

View File

@@ -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.getByRole('link', { name: 'Joe' }).nth(1).click();
await page.getByText('(cox2)').click();
page.once("dialog", (dialog) => {
dialog.accept().catch(() => {});
});
@@ -208,6 +208,7 @@ 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');
@@ -224,7 +225,7 @@ test("Kiosk can start and finish trip", async ({ page }, testInfo) => {
await page.getByPlaceholder("Passwort").press("Enter");
await page.goto("/log/show");
await page.getByRole('link', { name: 'Joe' }).nth(1).click();
await page.getByText('(cox2)').click();
page.once("dialog", (dialog) => {
dialog.accept().catch(() => {});
});
@@ -285,6 +286,7 @@ 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)');
@@ -300,7 +302,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.getByRole("link", { name: "cox_only_steering_boat" }).click();
await page.getByText('(cox2 - handgesteuert)').click();
page.once("dialog", (dialog) => {
dialog.accept().catch(() => {});
});
@@ -369,7 +371,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.getByRole('link', { name: 'Joe' }).nth(1).click();
await page.getByText('(cox2)').click();
page.once("dialog", (dialog) => {
dialog.accept().catch(() => {});
});

View File

@@ -1,21 +1,20 @@
use std::{fmt::Display, ops::DerefMut};
use argon2::{Argon2, PasswordHasher, password_hash::SaltString};
use argon2::{password_hash::SaltString, Argon2, PasswordHasher};
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,
@@ -24,6 +23,7 @@ use super::{
role::Role,
stat::Stat,
tripdetails::TripDetails,
Day,
};
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
use scheckbuch::ScheckbuchUser;
@@ -577,6 +577,10 @@ 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) {
@@ -863,8 +867,8 @@ special_user!(SteeringUser, +"cox", +"Bootsführer");
special_user!(AdminUser, +"admin");
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch", +"Förderndes Mitglied");
special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied"); // TODO:
// remove ->
// RegularUser
// remove ->
// RegularUser
special_user!(SchnupperBetreuerUser, +"schnupper-betreuer");
special_user!(VorstandUser, +"admin", +"Vorstand");
special_user!(EventUser, +"manage_events");
@@ -978,21 +982,17 @@ 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,11 +1011,9 @@ 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;

View File

@@ -3,14 +3,13 @@ use crate::model::{
user::{AdminUser, UserWithDetails, VorstandUser},
};
use rocket::{
FromForm, Route, State,
form::Form,
get, post,
request::FlashMessage,
response::{Flash, Redirect},
routes,
routes, FromForm, Route, State,
};
use rocket_dyn_templates::{Template, tera::Context};
use rocket_dyn_templates::{tera::Context, Template};
use sqlx::SqlitePool;
#[get("/role")]

View File

@@ -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,7 +19,6 @@ use crate::{
use chrono::NaiveDate;
use futures::future::join_all;
use rocket::{
FromForm, Request, Route, State,
form::Form,
fs::TempFile,
get,
@@ -27,9 +26,9 @@ use rocket::{
post,
request::{FlashMessage, FromRequest, Outcome},
response::{Flash, Redirect},
routes,
routes, FromForm, Request, Route, State,
};
use rocket_dyn_templates::{Template, tera::Context};
use rocket_dyn_templates::{tera::Context, Template};
use sqlx::SqlitePool;
// Custom request guard to extract the Referer header
@@ -136,7 +135,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!"
));
}

View File

@@ -14,7 +14,6 @@ use rocket_dyn_templates::{Template, context, tera};
use sqlx::SqlitePool;
use crate::model::{
activity::ActivityBuilder,
log::Log,
user::{LoginError, User},
};
@@ -83,12 +82,13 @@ async fn login(
cookies.add_private(Cookie::new("loggedin_user", format!("{}", user.id)));
ActivityBuilder::new(&format!(
"{user} hat sich eingeloggt (User-Agent: {})",
agent.0
))
.relevant_for_user(&user)
.save(db)
Log::create(
db,
format!(
"Succ login of {} with this useragent: {}",
login.name, agent.0
),
)
.await;
// Check for redirect_url cookie and redirect accordingly

View File

@@ -1,7 +1,6 @@
use std::net::IpAddr;
use rocket::{
Request, Route, State,
form::Form,
get,
http::{Cookie, CookieJar},
@@ -10,8 +9,9 @@ use rocket::{
response::{Flash, Redirect},
routes,
time::{Duration, OffsetDateTime},
Request, Route, State,
};
use rocket_dyn_templates::{Template, context};
use rocket_dyn_templates::{context, Template};
use sqlx::SqlitePool;
use tera::Context;
@@ -585,7 +585,7 @@ mod test {
use sqlx::SqlitePool;
use crate::model::logbook::Logbook;
use crate::tera::{User, log::Boat};
use crate::tera::{log::Boat, User};
use crate::testdb;
#[sqlx::test]

View File

@@ -8,16 +8,19 @@
<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"
@@ -64,6 +67,7 @@
</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()">
@@ -95,6 +99,7 @@
</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()">
@@ -117,6 +122,7 @@
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 ">

View File

@@ -4,9 +4,7 @@
{% 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">&larr; Userverwaltung</a>
</div>
{% endif %}
<h1 class="h1">{{ user.name }}</h1>
<div class="grid sm:grid-cols-2 gap-8 my-8">
@@ -121,12 +119,12 @@
</div>
{% if allowed_to_edit %}
<div class="py-3">
<div class="text-right">
<div class="mt-3 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 mt-3"
class="btn btn-alert"
onclick="return confirm('Ist {{ user.name }} wirklich aus dem Verein ausgetreten?');">
{% include "includes/delete-icon" %}
Mitglied ist ausgetreten
@@ -387,11 +385,9 @@
{% 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 %}
@@ -406,13 +402,11 @@
{% 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 max-h-60 overflow-y-scroll">
<div class="mx-3 divide-y divide-gray-200 dark:divide-primary-600">
<div class="py-3">
<ul class="list-disc ms-4">
{% for activity in activities %}
<li>
<strong>{{ activity.created_at | date(format="%d. %m. %Y") }}:</strong> <small>{{ activity.text }}</small>
</li>
<li>{{ activity.created_at | date(format="%d. %m. %Y") }}: {{ activity.text }}</li>
{% else %}
<li>Noch keine Aktivität... Stay tuned 😆</li>
{% endfor %}

View File

@@ -202,7 +202,9 @@
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 %}
@@ -274,24 +276,31 @@
</svg>
</button>
<div class="mt-8">
<h2 class="h3">Eintrag '{{ log.boat.name }}' ändern</h2>
<p class="text-center mb-3">{{ log.id }}</p>
<h2 class="h3">Eintrag '{{ log.boat.name }}' ändern </h2>
<p class="text-center mb-3">ID: {{ log.id }}</p>
<form action="/log/update" method="post" class="grid gap-3">
<input type="hidden" name="id" value="{{ log.id }}" />
<input type="hidden" name="boat_id" value="{{ log.boat_id }}" />
<input type="hidden" name="shipmaster" value="{{ log.shipmaster }}" />
<input type="hidden"
name="steering_person"
value="{{ log.steering_person }}" />
{{ macros::select(label="Boot", data=boats, name="boat_id", id="boat_id{{ log.id }}", selected_id=log.boat.id ,display=["name", " (","amount_seats", " x)"]) }}
{{ macros::select(label="Schiffsführer", data=log.rowers, name="shipmaster", id="shipmaster{{ log.id }}", selected_id=log.shipmaster_user.id) }}
{{ 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 }}" />
<div>
<label for="departure" class=" text-sm text-gray-600 dark:text-white ">
Abfahrt
</label>
<input type="datetime-local" class="input rounded-md" name="departure" value="{{ log.departure }}" />
</div>
<div>
<label for="arrival" class=" text-sm text-gray-600 dark:text-white ">
Ankunft
</label>
<input type="datetime-local" class="input rounded-md" name="arrival" value="{{ log.arrival }}" />
</div>
<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 }}" />

View File

@@ -26,7 +26,7 @@
{% for log in logs %}
{% set_global allowed_to_edit = false %}
{% if loggedin_user %}
{% if "Vorstand" in loggedin_user.roles or "admin" in loggedin_user.roles %}
{% if "Vorstand" in loggedin_user.roles %}
{% set_global allowed_to_edit = true %}
{% endif %}
{% endif %}