128 Commits

Author SHA1 Message Date
ecf73f72e5 fix minor mistakes during merge
Some checks failed
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
2025-04-03 17:03:11 +02:00
ab7ec637ab Merge remote-tracking branch 'upstream/main' into upd 2025-04-03 16:58:43 +02:00
f0a86a7186 Merge pull request 'fix kiosk error' (#886) from fix-kiosk-error into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#886
2025-03-26 20:58:15 +01:00
18d9f51354 fix kiosk error 2025-03-26 20:56:39 +01:00
dfe39cdd13 Merge pull request 'update deps' (#884) from upd into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#884
2025-03-26 14:52:08 +01:00
3a1ff3189d update deps 2025-03-26 14:51:10 +01:00
a89d78160d Merge pull request 'update id's' (#882) from add-unit-test into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#882
2025-03-09 19:21:41 +01:00
86e5482c6f update id's 2025-03-09 19:20:56 +01:00
08283dd392 Merge pull request 'add unit test for previous bug' (#880) from add-unit-test into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#880
2025-03-09 19:18:44 +01:00
2003ff0e59 add unit test for previous bug 2025-03-09 19:17:34 +01:00
1471ccad2c Merge pull request 'correct-name-in-notification' (#877) from correct-name-in-notification into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#877
2025-03-09 13:34:42 +01:00
d1102a7b04 show proper name in notification 2025-03-09 13:31:12 +01:00
faa8b4e767 Merge branch 'main' of ssh://git.hofer.link:2222/Ruderverein-Donau-Linz/rowt 2025-03-06 10:25:55 +01:00
bed4b4eb44 Merge pull request 'update deps' (#873) from update-deps into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#873
2025-03-06 10:25:03 +01:00
1ca0de1dd3 push 2025-03-06 10:18:34 +01:00
40bc866b3e push 2025-03-06 10:15:49 +01:00
13c9c5a708 push 2025-03-06 10:14:36 +01:00
d4b99f67ac push 2025-03-06 10:11:34 +01:00
b189c4f203 push 2025-03-06 10:10:33 +01:00
4820f8c798 push 2025-03-06 10:09:51 +01:00
7b2c47613c try 2025-03-06 10:07:35 +01:00
0a81489fa3 more updates 2025-03-06 10:06:54 +01:00
31a7643d96 update deps 2025-03-06 10:04:11 +01:00
83796a9824 test 2025-02-21 10:59:54 +01:00
227c751f60 test 2025-02-21 10:55:41 +01:00
ee5a1202fd test 2025-02-21 10:42:39 +01:00
7f824ccd2f test 2025-02-21 10:42:09 +01:00
e3d8a47af0 test 2025-02-21 10:40:46 +01:00
9f35920f3c test 2025-02-21 10:39:03 +01:00
58e3140376 fetch new ci image 2025-02-21 10:33:36 +01:00
b86043bba5 update deps 2025-02-20 18:18:48 +01:00
e141bcfc37 Merge pull request 'name proper mail addresses' (#871) from remove-philipp-mentioning into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#871
2025-02-17 22:59:01 +01:00
eaa35fb46c name proper mail addresses 2025-02-17 22:55:48 +01:00
86470da184 Merge pull request 'update deps' (#869) from update-deps into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#869
2025-02-13 10:07:01 +01:00
82a54bdea1 update deps 2025-02-13 10:06:04 +01:00
2a37bcbec5 Merge pull request 'upd' (#864) from upd into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#864
2025-02-12 07:13:13 +01:00
c96cc4b38f Merge branch 'upd' of ssh://git.hofer.link:2222/Ruderverein-Donau-Linz/rowt into upd 2025-02-11 21:39:28 +01:00
3008264261 fix default sort 2025-02-11 21:39:06 +01:00
Marie Birner
11025738bb [TASK] improve user management ux 2025-02-11 21:29:54 +01:00
Marie Birner
31fc0605d9 [TASK] improve user management ux 2025-02-11 21:28:28 +01:00
Marie Birner
1fdec59f77 [TASK] add sort element user management 2025-02-11 21:12:30 +01:00
da793fec2d allow sorting of user 2025-02-11 20:23:18 +01:00
8917629613 use proper permissions 2025-02-11 19:30:09 +01:00
2a2c2ce9dc Merge pull request 'fix ci' (#863) from allow-secretary-to-edit-boats into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#863
2025-02-11 09:37:24 +01:00
10f6268e56 fix ci 2025-02-11 09:36:44 +01:00
f0ea5823ba Merge pull request 'allow vorstand to edit boats' (#861) from allow-secretary-to-edit-boats into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#861
2025-02-11 09:23:56 +01:00
3406b66f41 allow vorstand to edit boats 2025-02-11 09:22:22 +01:00
2ffddda960 Merge pull request 'staging' (#858) from staging into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#858
2025-02-10 18:48:54 +01:00
c7c92c83fb Merge pull request 'fix ci' (#856) from allow-secretary-to-edit-boats into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#856
2025-02-10 18:48:22 +01:00
5cc77c39ff Merge branch 'staging' into allow-secretary-to-edit-boats 2025-02-10 18:47:59 +01:00
80d8857c6b Merge pull request 'fix ci' (#857) from allow-secretary-to-edit-boats into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#857
2025-02-10 18:47:28 +01:00
78403e4ec5 Merge branch 'main' into allow-secretary-to-edit-boats 2025-02-10 18:46:04 +01:00
4dd656f566 fix ci 2025-02-10 18:44:01 +01:00
23a1a118a3 Merge pull request 'allow 'schriftführer' to edit boats' (#854) from allow-secretary-to-edit-boats into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#854
2025-02-10 18:17:31 +01:00
b281201906 Merge pull request 'allow-secretary-to-edit-boats' (#855) from allow-secretary-to-edit-boats into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#855
2025-02-10 18:17:25 +01:00
4d58bd3cae allow 'schriftführer' to edit boats 2025-02-10 18:16:31 +01:00
67e790a82e Merge pull request 'fix-new-npm' (#853) from fix-new-npm into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#853
2025-01-10 14:35:40 +01:00
63bf1015cc Merge pull request 'Update frontend/tests/cox.spec.ts' (#852) from fix-new-npm into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#852
2025-01-10 14:34:34 +01:00
352dad8e6c Update frontend/tests/cox.spec.ts 2025-01-10 14:16:05 +01:00
4f42e7cb8c Merge pull request 'use new rust in ci' (#851) from update-rust into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#851
2025-01-10 12:47:30 +01:00
c6aa25fe0e Merge pull request 'use new rust in ci' (#850) from update-rust into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#850
2025-01-10 12:47:23 +01:00
9ba848cbab use new rust in ci 2025-01-10 12:46:43 +01:00
9047459d6c Merge pull request 'vorstand-show-old-logs' (#849) from vorstand-show-old-logs into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#849
2025-01-10 10:23:30 +01:00
87de3859a2 Merge pull request 'allow vorstand to see all old logs' (#848) from vorstand-show-old-logs into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#848
2025-01-10 09:52:56 +01:00
b8aaf5ba2e allow vorstand to see all old logs 2025-01-10 09:51:43 +01:00
de9ea9405e Merge pull request 'update-deps' (#847) from update-deps into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#847
2025-01-09 17:23:53 +01:00
3bd229554b Merge pull request 'update-deps' (#846) from update-deps into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#846
2025-01-09 17:04:02 +01:00
f9c9f7c523 update to sqlx 0.8 2025-01-09 16:31:53 +01:00
0dfceec737 update deps 2025-01-09 16:22:08 +01:00
e5fec411f3 Merge pull request 'notfiication-on-new-personal-stat' (#843) from notfiication-on-new-personal-stat into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#843
2025-01-09 16:19:37 +01:00
ac67c6cfdb Merge pull request 'ped clippy' (#845) from notfiication-on-new-personal-stat into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#845
2025-01-09 15:36:34 +01:00
a90c4fc07e ped clippy 2025-01-09 15:35:57 +01:00
52b960cec7 Merge pull request 'cargo clippy' (#844) from notfiication-on-new-personal-stat into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#844
2025-01-09 15:32:26 +01:00
f7d109f1b2 cargo clippy 2025-01-09 15:31:05 +01:00
63505722f9 Merge pull request 'notfiication-on-new-personal-stat' (#842) from notfiication-on-new-personal-stat into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#842
2025-01-09 11:58:10 +01:00
d21272d4bb send notifiation to user + vorstand if user completes 'äquatorpreis' or 'fahrtenabzeichen'; Fixes #746 2025-01-09 11:45:24 +01:00
97dd7794fb split to separate fee file 2025-01-09 10:37:15 +01:00
cfe99c2f2a Merge pull request 'add confirm dialog before creating a new user' (#841) from confirm-user-creation into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#841
2025-01-09 10:22:58 +01:00
2a3f846c5c Merge pull request 'confirm-user-creation' (#840) from confirm-user-creation into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#840
2025-01-09 10:22:56 +01:00
af4163a065 add confirm dialog before creating a new user 2025-01-09 10:21:44 +01:00
8a9047b3c3 Merge pull request 'reservation-styling' (#839) from reservation-styling into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#839
2025-01-08 14:50:27 +01:00
ebc7c32351 Merge pull request 'reservation-styling' (#838) from reservation-styling into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#838
2025-01-08 14:50:20 +01:00
1a850535ed switch from date to time icon + add 'Reservierung' 2025-01-08 14:46:11 +01:00
99bbb2b088 Merge pull request 'stats' (#836) from stats into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#836
2025-01-07 14:51:16 +01:00
b31209a97a Merge pull request '[TASK] make stats more beautiful' (#837) from stats into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#837
2025-01-07 14:27:59 +01:00
Marie Birner
be4f302a4c [TASK] make stats more beautiful 2025-01-07 14:07:52 +01:00
e5c2bec145 Merge pull request 'stats' (#835) from stats into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#835
2025-01-07 12:58:37 +01:00
0ebcd5a284 allow changing the year in stats again 2025-01-07 11:44:56 +01:00
6237340f72 fix ci 2025-01-07 11:39:36 +01:00
Marie Birner
5b013fe389 [TASK] rm unnecessary personal stat 2025-01-07 10:54:15 +01:00
Marie Birner
022ec6bd5b [TASK] make stats more beautiful 2025-01-07 10:52:46 +01:00
09d4c0abe4 Merge pull request 'show amount of trips in stat' (#834) from show-amount-trips into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#834
2025-01-06 13:15:05 +01:00
5448558085 Merge pull request 'show-amount-trips' (#833) from show-amount-trips into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#833
2025-01-06 13:14:55 +01:00
3232a03d75 show amount of trips in stat 2025-01-06 13:14:19 +01:00
dceb57e370 Merge pull request 'fix count in statistic' (#832) from fix-count into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#832
2025-01-04 10:57:34 +01:00
f68928df00 Merge pull request 'fix-count' (#831) from fix-count into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#831
2025-01-04 10:57:05 +01:00
d3bb050534 fix count in statistic 2025-01-04 10:56:32 +01:00
32b4131aae Merge pull request 'nicer mail text' (#830) from nicer-mail-text into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#830
2025-01-03 12:38:28 +01:00
1d34cb5794 Merge pull request 'nicer-mail-text' (#829) from nicer-mail-text into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#829
2025-01-03 12:38:09 +01:00
8a4d98a90f nicer mail text 2025-01-03 12:36:29 +01:00
Marie Birner
213e9faad4 [TASK] idea reservation styling in planned events view 2025-01-02 11:22:41 +01:00
a9a8207813 Merge pull request 'show boatreservations in planned' (#828) from show-boatreservations-in-planned into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#828
2025-01-01 19:30:58 +01:00
b7b2385264 Merge pull request 'Merge pull request 'fix no 'donau linz' group' (#825) from fix-no-group into main' (#826) from show-boatreservations-in-planned into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#826
2025-01-01 19:29:58 +01:00
b560233acf show boatreservations in planned 2025-01-01 19:05:20 +01:00
d7187a7589 Merge pull request 'fix no 'donau linz' group' (#825) from fix-no-group into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#825
2025-01-01 17:46:26 +01:00
e61b16c389 Merge pull request 'fix-no-group' (#824) from fix-no-group into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#824
2025-01-01 17:45:52 +01:00
2ac8a3155c fix no 'donau linz' group 2025-01-01 17:44:48 +01:00
d01e6ea30b Merge pull request 'allow lazy people to mark all notifcations as read' (#822) from mark-all-notifications-read into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#822
2024-12-19 21:16:40 +01:00
f38ca09eb7 Merge pull request 'allow lazy people to mark all notifcations as read' (#823) from mark-all-notifications-read into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#823
2024-12-19 21:16:31 +01:00
1ad4c31979 allow lazy people to mark all notifcations as read 2024-12-19 21:15:27 +01:00
5e413d2d72 Merge pull request 'add-renntrainer' (#820) from add-renntrainer into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#820
2024-12-17 09:14:18 +01:00
0f8e1158b9 Merge pull request 'add renntrainer role' (#821) from add-renntrainer into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#821
2024-12-17 08:57:29 +01:00
af10399797 add renntrainer role 2024-12-17 08:56:48 +01:00
6344ba720d Merge pull request 'fix-mobile-link' (#818) from fix-mobile-link into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#818
2024-12-06 18:28:49 +01:00
4b1dceb08a Merge pull request 'format' (#816) from format into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#816
2024-12-05 23:40:07 +01:00
cb819c16a3 Merge pull request 'links; Fixes #755' (#815) from links into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#815
2024-12-05 11:16:34 +01:00
08a48cb4d2 Merge pull request 'update ci' (#812) from update-ci into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#812
2024-12-05 10:23:43 +01:00
9c36da32bd Merge pull request 'demo' (#810) from demo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#810
2024-11-30 22:33:12 +01:00
77444d25ae Merge pull request 'fix' (#808) from fix into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#808
2024-11-27 08:21:48 +01:00
a683af00d0 Merge pull request 'new-link' (#805) from new-link into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#805
2024-11-27 08:14:00 +01:00
766886d857 Merge pull request 'nicer-label' (#803) from nicer-label into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#803
2024-11-25 21:01:38 +01:00
38703321e8 Merge pull request 'ergo-trips' (#801) from ergo-trips into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#801
2024-11-25 12:31:50 +01:00
ec1c717341 Merge pull request 'allow for smaller m' (#799) from trim-ergo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#799
2024-11-11 23:12:23 +01:00
22bb79bfbd Merge pull request 'allow m in dd' (#797) from trim-ergo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#797
2024-11-11 23:07:28 +01:00
eba4b77983 Merge pull request 'trim-ergo' (#795) from trim-ergo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#795
2024-11-11 23:00:08 +01:00
83d266b3e0 Merge pull request 'update data' (#793) from formating-ergo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#793
2024-11-11 18:03:43 +01:00
980bcff1d9 Merge pull request 'fix tests' (#791) from formating-ergo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#791
2024-11-11 15:27:15 +01:00
c15ed6e9a9 Merge pull request 'formating-ergo' (#789) from formating-ergo into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#789
2024-11-11 13:34:31 +01:00
17 changed files with 1156 additions and 624 deletions

1481
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "rot" name = "rot"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2024"
[features] [features]
default = ["rest", "rowing-tera" ] default = ["rest", "rowing-tera" ]
@@ -13,20 +13,20 @@ rocket = { version = "0.5.0", features = ["secrets"]}
rocket_dyn_templates = {version = "0.2", features = [ "tera" ], optional = true } rocket_dyn_templates = {version = "0.2", features = [ "tera" ], optional = true }
log = "0.4" log = "0.4"
env_logger = "0.11" env_logger = "0.11"
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio-rustls", "macros", "chrono", "time"] } sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "macros", "chrono"] }
argon2 = "0.5" argon2 = "0.5"
serde = { version = "1.0", features = [ "derive" ]} serde = { version = "1.0", features = [ "derive" ]}
serde_json = "1.0" serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"]} chrono = { version = "0.4", features = ["serde"]}
chrono-tz = "0.9" chrono-tz = "0.10"
tera = { version = "1.18", features = ["date-locale"], optional = true} tera = { version = "1.18", features = ["date-locale"], optional = true}
ics = "0.5" ics = "0.5"
futures = "0.3" futures = "0.3"
lettre = "0.11" lettre = "0.11"
csv = "1.3" csv = "1.3"
itertools = "0.13" itertools = "0.14"
job_scheduler_ng = "2.0" job_scheduler_ng = "2.0"
ureq = { version = "2.9", features = ["json"] } ureq = { version = "3.0", features = ["json"] }
regex = "1.10" regex = "1.10"
urlencoding = "2.1" urlencoding = "2.1"

View File

@@ -23,6 +23,7 @@ document.addEventListener("DOMContentLoaded", function () {
addRelationMagic(<HTMLElement>document.querySelector("body")); addRelationMagic(<HTMLElement>document.querySelector("body"));
reloadPage(); reloadPage();
setCurrentdate(<HTMLInputElement>document.querySelector("#departure")); setCurrentdate(<HTMLInputElement>document.querySelector("#departure"));
initDropdown();
}); });
function changeTheme() { function changeTheme() {
@@ -795,3 +796,21 @@ function replaceStrings() {
weekday.innerHTML = weekday.innerHTML.replace("Freitag", "Markttag"); weekday.innerHTML = weekday.innerHTML.replace("Freitag", "Markttag");
}); });
} }
function initDropdown() {
const popoverTriggerList = document.querySelectorAll('[data-dropdown]');
popoverTriggerList.forEach((popoverTriggerEl: Element) => {
const id = popoverTriggerEl.getAttribute('data-dropdown');
if (id) {
const element = document.getElementById(id);
if (element) {
// Toggle visibility of the dropdown when clicked
popoverTriggerEl.addEventListener('click', () => {
element.classList.toggle('hidden');
});
}
}
});
}

View File

@@ -53,6 +53,7 @@ INSERT INTO "planned_event" (name, planned_amount_cox, trip_details_id) VALUES('
INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('11:00', 1, date('now', '+1 day'), 'trip_details for trip from cox'); INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('11:00', 1, date('now', '+1 day'), 'trip_details for trip from cox');
INSERT INTO "trip" (cox_id, trip_details_id) VALUES(4, 2); INSERT INTO "trip" (cox_id, trip_details_id) VALUES(4, 2);
INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('10:00', 2, date('now'), 'same trip_details as id=1');
INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Regatta', 'Regatta!', 'Kein normales Event. Das ist eine Regatta! Willst du wirklich teilnehmen?', '&#127941;'); INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Regatta', 'Regatta!', 'Kein normales Event. Das ist eine Regatta! Willst du wirklich teilnehmen?', '&#127941;');
INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Lange Ausfahrt', 'Lange Ausfahrt!', 'Das ist eine lange Ausfahrt! Willst du wirklich teilnehmen?', '&#128170;'); INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Lange Ausfahrt', 'Lange Ausfahrt!', 'Das ist eine lange Ausfahrt! Willst du wirklich teilnehmen?', '&#128170;');
INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Wanderfahrt', 'Wanderfahrt!', 'Kein normales Event. Das ist eine Wanderfahrt! Bitte überprüfe ob du alle Anforderungen erfüllst. Willst du wirklich teilnehmen?', '&#9969;'); INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Wanderfahrt', 'Wanderfahrt!', 'Kein normales Event. Das ist eine Wanderfahrt! Bitte überprüfe ob du alle Anforderungen erfüllst. Willst du wirklich teilnehmen?', '&#9969;');

View File

@@ -96,8 +96,8 @@ FROM trip WHERE planned_event_id = ?
.unwrap() .unwrap()
.into_iter() .into_iter()
.map(|r| Registration { .map(|r| Registration {
name: r.name, name: r.name.unwrap(),
registered_at: r.registered_at, registered_at: r.registered_at.unwrap(),
is_guest: false, is_guest: false,
is_real_guest: false, is_real_guest: false,
}) })

View File

@@ -208,6 +208,15 @@ ORDER BY read_at DESC, created_at DESC;
} }
} }
} }
pub(crate) async fn mark_all_read(db: &SqlitePool, user: &User) {
let notifications = Self::for_user(db, user).await;
for notification in notifications {
notification.mark_read(db).await;
}
}
pub(crate) async fn delete_by_action(db: &sqlx::Pool<Sqlite>, action: &str) { pub(crate) async fn delete_by_action(db: &sqlx::Pool<Sqlite>, action: &str) {
sqlx::query!( sqlx::query!(
"DELETE FROM notification WHERE action_after_reading=? and read_at is null", "DELETE FROM notification WHERE action_after_reading=? and read_at is null",
@@ -289,7 +298,7 @@ mod test {
assert_eq!(rower_notification.category, "Absage Ausfahrt"); assert_eq!(rower_notification.category, "Absage Ausfahrt");
assert_eq!( assert_eq!(
rower_notification.action_after_reading.as_deref(), rower_notification.action_after_reading.as_deref(),
Some("remove_user_trip_with_trip_details_id:3") Some("remove_user_trip_with_trip_details_id:4")
); );
// Cox received notification // Cox received notification

View File

@@ -81,33 +81,31 @@ impl Trip {
trip_details.planned_starting_time, trip_details.planned_starting_time,
) )
.await; .await;
if same_starting_datetime.len() > 1 { for notify in same_starting_datetime {
for notify in same_starting_datetime { // don't notify oneself
// don't notify oneself if notify.id == trip_details.id {
if notify.id == trip_details.id { continue;
continue; }
}
// don't notify people who have cancelled their trip // don't notify people who have cancelled their trip
if notify.cancelled() { if notify.cancelled() {
continue; continue;
} }
if let Some(trip) = Trip::find_by_trip_details(db, notify.id).await { if let Some(trip) = Trip::find_by_trip_details(db, notify.id).await {
let user = User::find_by_id(db, trip.cox_id as i32).await.unwrap(); let user_earlier_trip = User::find_by_id(db, trip.cox_id as i32).await.unwrap();
Notification::create( Notification::create(
db, db,
&user, &user_earlier_trip,
&format!( &format!(
"{} hat eine Ausfahrt zur selben Zeit ({} um {}) wie du erstellt", "{} hat eine Ausfahrt zur selben Zeit ({} um {}) wie du erstellt",
user.name, trip.day, trip.planned_starting_time user.name, trip.day, trip.planned_starting_time
), ),
"Neue Ausfahrt zur selben Zeit", "Neue Ausfahrt zur selben Zeit",
None, None,
None, None,
) )
.await; .await;
}
} }
} }
} }
@@ -277,10 +275,8 @@ WHERE day=?
return Err(TripUpdateError::NotYourTrip); return Err(TripUpdateError::NotYourTrip);
} }
if update.trip_type != Some(4) { if update.trip_type != Some(4) && !update.cox.allowed_to_steer(db).await {
if !update.cox.allowed_to_steer(db).await { return Err(TripUpdateError::TripTypeNotAllowed);
return Err(TripUpdateError::TripTypeNotAllowed);
}
} }
let Some(trip_details_id) = update.trip.trip_details_id else { let Some(trip_details_id) = update.trip.trip_details_id else {
@@ -478,6 +474,7 @@ mod test {
use crate::{ use crate::{
model::{ model::{
event::Event, event::Event,
notification::Notification,
trip::{self, TripDeleteError}, trip::{self, TripDeleteError},
tripdetails::TripDetails, tripdetails::TripDetails,
user::{SteeringUser, User}, user::{SteeringUser, User},
@@ -509,6 +506,34 @@ mod test {
assert!(Trip::find_by_id(&pool, 1).await.is_some()); assert!(Trip::find_by_id(&pool, 1).await.is_some());
} }
#[sqlx::test]
fn test_notification_cox_if_same_datetime() {
let pool = testdb!();
let cox = SteeringUser::new(
&pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(),
)
.await
.unwrap();
let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
Trip::new_own(&pool, &cox, trip_details).await;
let cox2 = SteeringUser::new(
&pool,
User::find_by_name(&pool, "cox2".into()).await.unwrap(),
)
.await
.unwrap();
let trip_details = TripDetails::find_by_id(&pool, 3).await.unwrap();
Trip::new_own(&pool, &cox2, trip_details).await;
let last_notification = &Notification::for_user(&pool, &cox).await[0];
assert!(last_notification
.message
.starts_with("cox2 hat eine Ausfahrt zur selben Zeit"));
}
#[sqlx::test] #[sqlx::test]
fn test_get_day_cox_trip() { fn test_get_day_cox_trip() {
let pool = testdb!(); let pool = testdb!();

View File

@@ -339,7 +339,7 @@ mod test {
} }
) )
.await, .await,
3, 4,
); );
assert_eq!( assert_eq!(
TripDetails::create( TripDetails::create(
@@ -354,7 +354,7 @@ mod test {
} }
) )
.await, .await,
4, 5,
); );
} }

58
src/model/user/fee.rs Normal file
View File

@@ -0,0 +1,58 @@
use super::User;
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct Fee {
pub sum_in_cents: i64,
pub parts: Vec<(String, i64)>,
pub name: String,
pub user_ids: String,
pub paid: bool,
pub users: Vec<User>,
}
impl Default for Fee {
fn default() -> Self {
Self::new()
}
}
impl Fee {
pub fn new() -> Self {
Self {
sum_in_cents: 0,
name: "".into(),
parts: Vec::new(),
user_ids: "".into(),
users: Vec::new(),
paid: false,
}
}
pub fn add(&mut self, desc: String, price_in_cents: i64) {
self.sum_in_cents += price_in_cents;
self.parts.push((desc, price_in_cents));
}
pub fn add_person(&mut self, user: &User) {
if !self.name.is_empty() {
self.name.push_str(" + ");
self.user_ids.push('&');
}
self.name.push_str(&user.name);
self.user_ids.push_str(&format!("user_ids[]={}", user.id));
self.users.push(user.clone());
}
pub fn paid(&mut self) {
self.paid = true;
}
pub fn merge(&mut self, fee: Fee) {
for (desc, price_in_cents) in fee.parts {
self.add(desc, price_in_cents);
}
}
}

View File

@@ -31,7 +31,7 @@ pub struct User {
pub struct UserWithDetails { pub struct UserWithDetails {
#[serde(flatten)] #[serde(flatten)]
pub user: User, pub user: User,
pub amount_unread_notifications: i32, pub amount_unread_notifications: i64,
pub allowed_to_steer: bool, pub allowed_to_steer: bool,
pub roles: Vec<String>, pub roles: Vec<String>,
} }
@@ -72,7 +72,7 @@ impl User {
self.has_role_tx(db, "cox").await || self.has_role_tx(db, "Bootsführer").await self.has_role_tx(db, "cox").await || self.has_role_tx(db, "Bootsführer").await
} }
pub async fn amount_unread_notifications(&self, db: &SqlitePool) -> i32 { pub async fn amount_unread_notifications(&self, db: &SqlitePool) -> i64 {
sqlx::query!( sqlx::query!(
"SELECT COUNT(*) as count FROM notification WHERE user_id = ? AND read_at IS NULL", "SELECT COUNT(*) as count FROM notification WHERE user_id = ? AND read_at IS NULL",
self.id self.id
@@ -197,18 +197,27 @@ WHERE lower(name)=?
} }
pub async fn all(db: &SqlitePool) -> Vec<Self> { pub async fn all(db: &SqlitePool) -> Vec<Self> {
sqlx::query_as!( Self::all_with_order(db, "last_access", false).await
Self, }
pub async fn all_with_order(db: &SqlitePool, sort: &str, asc: bool) -> Vec<Self> {
let mut query = format!(
" "
SELECT id, name, pw, deleted, last_access, user_token SELECT id, name, pw, deleted, last_access, user_token
FROM user FROM user
WHERE deleted = 0 WHERE deleted = 0
ORDER BY last_access DESC ORDER BY {}
" ",
) sort
.fetch_all(db) );
.await if !asc {
.unwrap() query.push_str(" DESC");
}
sqlx::query_as::<_, User>(&query)
.fetch_all(db)
.await
.unwrap()
} }
pub async fn all_with_role(db: &SqlitePool, role: &Role) -> Vec<Self> { pub async fn all_with_role(db: &SqlitePool, role: &Role) -> Vec<Self> {

View File

@@ -80,8 +80,8 @@ fn fetch() -> Result<Station, String> {
let url = "https://hydro.ooe.gv.at/daten/internet/stations/OG/207068/S/forecast.json"; let url = "https://hydro.ooe.gv.at/daten/internet/stations/OG/207068/S/forecast.json";
match ureq::get(url).call() { match ureq::get(url).call() {
Ok(response) => { Ok(mut response) => {
let forecast: Result<Vec<Station>, _> = response.into_json(); let forecast: Result<Vec<Station>, _> = response.body_mut().read_json();
if let Ok(data) = forecast { if let Ok(data) = forecast {
if data.len() == 1 { if data.len() == 1 {

View File

@@ -99,8 +99,8 @@ fn fetch(api_key: &str) -> Result<Data, String> {
let url = format!("https://api.openweathermap.org/data/3.0/onecall?lat=47.766249&lon=13.367683&units=metric&exclude=current,minutely,hourly,alert&appid={api_key}"); let url = format!("https://api.openweathermap.org/data/3.0/onecall?lat=47.766249&lon=13.367683&units=metric&exclude=current,minutely,hourly,alert&appid={api_key}");
match ureq::get(&url).call() { match ureq::get(&url).call() {
Ok(response) => { Ok(mut response) => {
let data: Result<Data, _> = response.into_json(); let data: Result<Data, _> = response.body_mut().read_json();
if let Ok(data) = data { if let Ok(data) = data {
Ok(data) Ok(data)

View File

@@ -33,13 +33,17 @@ impl<'r> FromRequest<'r> for Referer {
} }
} }
#[get("/user")] #[get("/user?<sort>&<asc>")]
async fn index( async fn index(
db: &State<SqlitePool>, db: &State<SqlitePool>,
user: ManageUserUser, user: ManageUserUser,
flash: Option<FlashMessage<'_>>, flash: Option<FlashMessage<'_>>,
sort: Option<String>,
asc: bool,
) -> Template { ) -> Template {
let user_futures: Vec<_> = User::all(db) let sort_column = sort.unwrap_or_else(|| "last_access".to_string());
let user_futures: Vec<_> = User::all_with_order(db, &sort_column, asc)
.await .await
.into_iter() .into_iter()
.map(|u| async move { UserWithDetails::from_user(u, db).await }) .map(|u| async move { UserWithDetails::from_user(u, db).await })

View File

@@ -38,7 +38,7 @@ async fn cal_registered(
return Err("Invalid".into()); return Err("Invalid".into());
}; };
if &user.user_token != uuid { if user.user_token != uuid {
return Err("Invalid".into()); return Err("Invalid".into());
} }

View File

@@ -30,6 +30,12 @@ async fn mark_read(db: &State<SqlitePool>, user: User, notification_id: i64) ->
} }
} }
pub fn routes() -> Vec<Route> { #[get("/read/all")]
routes![mark_read] async fn mark_all_read(db: &State<SqlitePool>, user: User) -> Flash<Redirect> {
Notification::mark_all_read(db, &user).await;
Flash::success(Redirect::to("/"), "Alle Nachrichten als gelesen markiert")
}
pub fn routes() -> Vec<Route> {
routes![mark_read, mark_all_read]
} }

View File

@@ -4,11 +4,13 @@
<div class="max-w-screen-lg w-full"> <div class="max-w-screen-lg w-full">
<h1 class="h1">Mitglieder</h1> <h1 class="h1">Mitglieder</h1>
{% if allowed_to_edit %} {% if allowed_to_edit %}
<form action="/admin/user/new" <details class="mt-5 bg-gray-200 dark:bg-primary-600 p-3 rounded-md">
<summary class="px-3 cursor-pointer text-md font-bold text-primary-950 dark:text-white">Neue Person hinzufügen</summary>
<form action="/admin/user/new"
onsubmit="return confirm('Willst du wirklich einen neuen Benutzer anlegen?');"
method="post" method="post"
class="mt-4 bg-primary-900 rounded-md text-white px-3 pb-3 pt-2 sm:flex items-end justify-between"> class="flex mt-4 rounded-md sm:flex items-end justify-between">
<div class="w-full"> <div class="w-full">
<h2 class="text-md font-bold mb-2 uppercase tracking-wide">Neues Mitglied hinzufügen</h2>
<div class="grid md:grid-cols-3"> <div class="grid md:grid-cols-3">
<div> <div>
<label for="name" class="sr-only">Name</label> <label for="name" class="sr-only">Name</label>
@@ -19,21 +21,44 @@
</div> </div>
</div> </div>
</div> </div>
<div class="text-right"> <div class="text-right ml-3">
<input value="Hinzufügen" <input value="Hinzufügen"
type="submit" type="submit"
class="w-28 mt-2 sm:mt-0 rounded-md bg-primary-500 px-3 py-2 text-sm font-semibold text-white hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 cursor-pointer" /> class="w-28 mt-2 sm:mt-0 rounded-md bg-primary-500 px-3 py-2 text-sm font-semibold text-white hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 cursor-pointer" />
</div> </div>
</form> </form>
</details>
{% endif %} {% endif %}
<!-- START filterBar --> <!-- START filterBar -->
<div class="search-wrapper"> <div class="search-wrapper flex">
<label for="name" class="sr-only">Suche</label> <label for="name" class="sr-only">Suche</label>
<input type="search" <input type="search"
name="name" name="name"
id="filter-js" id="filter-js"
class="search-bar" class="search-bar"
placeholder="Suchen nach (Name, [yes|no]-role:<name>" /> placeholder="Suchen nach (Name, [yes|no]-role:<name>, has-[no-]membership-pdf)" />
<div class="relative">
<button id="dropdownbtn" data-dropdown="dropdown" class="btn btn-dark ml-3" type="button">
Sortieren
</button>
<!-- Dropdown menu -->
<div id="dropdown" class="z-10 hidden bg-white divide-y divide-gray-100 text-secondary-900 rounded-lg shadow-sm w-44 absolute right-0">
<ul class="py-2 text-sm" aria-labelledby="dropdownbtn">
<li>
<a href="./user" class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Zuletzt eingeloggt</a>
</li>
<li>
<a href="?sort=name&asc" class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Name A-Z</a>
</li>
<li>
<a href="?sort=name" class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Name Z-A</a>
</li>
</ul>
</div>
</div>
</div> </div>
<!-- END filterBar --> <!-- END filterBar -->
<div id="filter-result-js" class="search-result"></div> <div id="filter-result-js" class="search-result"></div>
@@ -46,7 +71,7 @@
<span class="text-black dark:text-white cursor-pointer"> <span class="text-black dark:text-white cursor-pointer">
<span class="font-bold"> <span class="font-bold">
{{ user.name }} {{ user.name }}
{% if not user.last_access and "admin" in loggedin_user.roles %} {% if not user.last_access and allowed_to_edit and user.mail %}
<form action="/admin/user" <form action="/admin/user"
method="post" method="post"
enctype="multipart/form-data" enctype="multipart/form-data"

View File

@@ -4,13 +4,12 @@
{% extends "base" %} {% extends "base" %}
{% macro show_place(aisle_name, side_name, level) %} {% macro show_place(aisle_name, side_name, level) %}
<li class="truncate p-2 flex relative w-full"> <li class="truncate p-2 flex relative w-full">
{% set aisle = aisle_name ~ "-aisle" %} {% set place = boathouse[aisle_name][side_name].boats %}
{% set place = boathouse[aisle][side_name] %}
{% if place[level] %} {% if place[level] %}
{{ place[level].1.name }} {{ place[level].boat.name }}
{% if "admin" in loggedin_user.roles %} {% if "admin" in loggedin_user.roles %}
<a class="btn btn-primary absolute end-0" <a class="btn btn-primary absolute end-0"
href="/board/boathouse/{{ place[level].0 }}/delete">X</a> href="/board/boathouse/{{ place[level].boathouse_id }}/delete">X</a>
{% endif %} {% endif %}
{% elif boats | length > 0 %} {% elif boats | length > 0 %}
{% if "admin" in loggedin_user.roles %} {% if "admin" in loggedin_user.roles %}