Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e65c34688f | |||
| 60a6a99380 | |||
| dc822585cd | |||
| 987feacbbe | |||
| ad0da68628 | |||
| 629c107277 | |||
| c1fc75b187 | |||
| fbd9115eb2 | |||
| 910c51d01f | |||
| c2d8427e1a | |||
| 79687807f2 | |||
| 09defdc1f4 | |||
| 45f595e147 | |||
| 1beb6ebfe9 | |||
| 55666a6eff |
@@ -31,6 +31,7 @@ jobs:
|
||||
run: cd frontend && npx playwright install && npx playwright test --workers 1 --reporter html,line
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: playwright-report
|
||||
path: frontend/playwright-report/
|
||||
|
||||
Generated
+772
-801
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -23,11 +23,11 @@ tera = { version = "1.20", features = ["date-locale"], optional = true}
|
||||
ics = "0.5"
|
||||
futures = "0.3"
|
||||
lettre = "0.11"
|
||||
csv = "1.4"
|
||||
csv = "1.3"
|
||||
itertools = "0.14"
|
||||
job_scheduler_ng = "2.4"
|
||||
ureq = { version = "3.2", features = ["json"] }
|
||||
regex = "1.12"
|
||||
job_scheduler_ng = "2.2"
|
||||
ureq = { version = "3.0", features = ["json"] }
|
||||
regex = "1.11"
|
||||
urlencoding = "2.1"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
|
||||
@@ -11,6 +11,7 @@ import { defineConfig, devices } from '@playwright/test';
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
timeout: process.env.CI ? 120000 : 30000,
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
|
||||
@@ -9,21 +9,10 @@ export async function resetDatabase(): Promise<void> {
|
||||
}
|
||||
|
||||
export async function login(page: Page, username: string, password: string): Promise<void> {
|
||||
// Clear cookies to ensure clean state
|
||||
await page.context().clearCookies();
|
||||
|
||||
// Navigate to auth page and wait for it to fully load
|
||||
await page.goto("/auth", { waitUntil: 'load' });
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await page.getByPlaceholder("Name").click();
|
||||
await page.getByPlaceholder("Name").fill(username);
|
||||
await page.getByPlaceholder("Passwort").click();
|
||||
await page.getByPlaceholder("Passwort").fill(password);
|
||||
|
||||
// Wait for navigation after form submission
|
||||
await Promise.all([
|
||||
page.waitForURL(/\/(planned|log|$)/, { timeout: 10000 }),
|
||||
page.getByPlaceholder("Passwort").press("Enter")
|
||||
]);
|
||||
await page.getByPlaceholder("Passwort").press("Enter");
|
||||
await page.waitForURL(/\/(planned|log|$)/);
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ use rot::rest;
|
||||
use rot::tera;
|
||||
use rot::{scheduled, tera::Config};
|
||||
|
||||
use sqlx::{ConnectOptions, pool::PoolOptions, sqlite::SqliteConnectOptions};
|
||||
use sqlx::{pool::PoolOptions, sqlite::SqliteConnectOptions, ConnectOptions};
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
@@ -95,13 +95,13 @@ WHERE end_date >= ? AND start_date <= ?
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn all_future(db: &SqlitePool) -> Vec<BoatReservationWithDetails> {
|
||||
pub async fn next_future(db: &SqlitePool) -> Vec<BoatReservationWithDetails> {
|
||||
let boatreservations = sqlx::query_as!(
|
||||
Self,
|
||||
"
|
||||
SELECT id, boat_id, start_date, end_date, time_desc, usage, user_id_applicant, user_id_confirmation, created_at
|
||||
FROM boat_reservation
|
||||
WHERE end_date >= CURRENT_DATE ORDER BY end_date
|
||||
WHERE end_date >= CURRENT_DATE AND end_date <= date(CURRENT_DATE, '+3 days') ORDER BY end_date
|
||||
"
|
||||
)
|
||||
.fetch_all(db)
|
||||
@@ -158,10 +158,10 @@ WHERE end_date >= CURRENT_DATE ORDER BY end_date
|
||||
|
||||
grouped_reservations
|
||||
}
|
||||
pub async fn all_future_with_groups(
|
||||
pub async fn next_future_with_groups(
|
||||
db: &SqlitePool,
|
||||
) -> HashMap<String, Vec<BoatReservationWithDetails>> {
|
||||
let reservations = Self::all_future(db).await;
|
||||
let reservations = Self::next_future(db).await;
|
||||
Self::with_groups(reservations)
|
||||
}
|
||||
|
||||
|
||||
+15
-2
@@ -93,11 +93,24 @@ GROUP BY family.id;"
|
||||
}
|
||||
|
||||
pub async fn clean_families_without_members(db: &SqlitePool) {
|
||||
sqlx::query(
|
||||
"UPDATE user SET family_id = NULL
|
||||
WHERE family_id IN (
|
||||
SELECT family_id FROM user
|
||||
WHERE family_id IS NOT NULL
|
||||
GROUP BY family_id
|
||||
HAVING COUNT(*) = 1
|
||||
);",
|
||||
)
|
||||
.execute(db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
sqlx::query(
|
||||
"DELETE FROM family
|
||||
WHERE id NOT IN (
|
||||
SELECT DISTINCT family_id
|
||||
FROM user
|
||||
SELECT DISTINCT family_id
|
||||
FROM user
|
||||
WHERE family_id IS NOT NULL
|
||||
);",
|
||||
)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use chrono::NaiveDate;
|
||||
use rocket::{
|
||||
FromForm, Route, State,
|
||||
form::Form,
|
||||
get, post,
|
||||
request::FlashMessage,
|
||||
response::{Flash, Redirect},
|
||||
routes,
|
||||
routes, FromForm, Route, State,
|
||||
};
|
||||
use rocket_dyn_templates::Template;
|
||||
use sqlx::SqlitePool;
|
||||
@@ -27,7 +26,7 @@ async fn index_kiosk(
|
||||
flash: Option<FlashMessage<'_>>,
|
||||
_kiosk: KioskCookie,
|
||||
) -> Template {
|
||||
let boatreservations = BoatReservation::all_future(db).await;
|
||||
let boatreservations = BoatReservation::next_future(db).await;
|
||||
|
||||
let mut context = Context::new();
|
||||
if let Some(msg) = flash {
|
||||
@@ -56,7 +55,7 @@ async fn index(
|
||||
flash: Option<FlashMessage<'_>>,
|
||||
user: DonauLinzUser,
|
||||
) -> Template {
|
||||
let boatreservations = BoatReservation::all_future(db).await;
|
||||
let boatreservations = BoatReservation::next_future(db).await;
|
||||
|
||||
let mut context = Context::new();
|
||||
if let Some(msg) = flash {
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ async fn index(db: &SqlitePool, flash: Option<FlashMessage<'_>>, mut context: Co
|
||||
context.insert("planned_trips", &Trip::get_for_today(db).await);
|
||||
context.insert(
|
||||
"reservations",
|
||||
&BoatReservation::all_future_with_groups(db).await,
|
||||
&BoatReservation::next_future_with_groups(db).await,
|
||||
);
|
||||
context.insert("coxes", &coxes);
|
||||
context.insert("users", &users);
|
||||
|
||||
@@ -230,6 +230,17 @@
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% elif "NoMembership" in member %}
|
||||
{% if allowed_to_edit %}
|
||||
<div class="grid pt-3">
|
||||
<a href="/admin/user/{{ user.id }}/delete"
|
||||
class="btn btn-alert"
|
||||
onclick="return confirm('Willst du die Daten von {{ user.name }} wirklich löschen?');">
|
||||
{% include "includes/delete-icon" %}
|
||||
Daten löschen
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if "Scheckbuch" in member or "Schnupperant" in member or "NoMembership" in member %}
|
||||
{% if allowed_to_edit %}
|
||||
|
||||
@@ -40,7 +40,7 @@ function setChoiceByLabel(choicesInstance, label) {
|
||||
{% endmacro plannedtrips %}
|
||||
{% macro boatreservation() %}
|
||||
<div class="bg-white dark:bg-primary-900 rounded-md shadow pb-2 mt-3">
|
||||
<h2 class="h2">Reservierungen ({{ reservations | length }})</h2>
|
||||
<h2 class="h2">Reservierungen<br /><small>in den nächsten 3 Tagen</small></h2>
|
||||
<div class="grid grid-cols-1 gap-3 mb-3 w-full">
|
||||
{% for _, reservations_for_event in reservations %}
|
||||
{% set reservation = reservations_for_event[0] %}
|
||||
|
||||
Reference in New Issue
Block a user