210 Commits

Author SHA1 Message Date
9890a4ac09 remove normannen + move to new server
All checks were successful
CI/CD Pipeline / test (push) Successful in 27m37s
CI/CD Pipeline / deploy-main (push) Successful in 26m57s
2025-07-18 17:53:54 +02:00
b60834ca18 remove ister :-(
All checks were successful
CI/CD Pipeline / test (push) Successful in 19m25s
CI/CD Pipeline / deploy-main (push) Successful in 21m58s
2025-04-28 22:41:54 +02:00
f8b16b2a95 Merge pull request 'rebase to rowt' (#12) from upd into main
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
Reviewed-on: #12
2025-04-28 22:41:32 +02:00
39e1c4432a remove compiler warnings, Fixes #1
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-04-28 22:40:48 +02:00
c548bf211b fix ci
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-04-28 22:39:45 +02:00
bdf92f40f0 Merge remote-tracking branch 'upstream/main'
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-04-28 22:37:31 +02:00
f1423b8713 Merge pull request 'format dtstart according to ics standard -> leading zero' (#945) from format-cal-according-to-standard into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#945
2025-04-28 22:21:42 +02:00
47b46cf41d format dtstart according to ics standard -> leading zero 2025-04-28 22:20:06 +02:00
8ba763e54e bye-bye kufstein (for now!)
All checks were successful
CI/CD Pipeline / test (push) Successful in 10m48s
CI/CD Pipeline / deploy-main (push) Successful in 6m34s
2025-04-21 15:15:43 +02:00
4134b2a65b Merge pull request 'no need to show rower box, if no rower can particiapte' (#936) from hide-box into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#936
2025-04-19 21:30:27 +02:00
f289c7b6d7 no need to show rower box, if no rower can particiapte 2025-04-19 21:29:17 +02:00
0f1bc39b4b Merge pull request 'document nextcloud integration, for future nextcloud setups' (#934) from doc-nextcloud-integration into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#934
2025-04-19 09:20:10 +02:00
3eb84ce46b document nextcloud integration, for future nextcloud setups 2025-04-19 09:19:11 +02:00
c8b01bcd03 Merge pull request 'zero-rower-events' (#932) from zero-rower-events into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#932
2025-04-19 00:22:35 +02:00
9b31ea981a hack in frontend test not working, as we can' hack a cancellation with setting rowers=0 2025-04-19 00:21:51 +02:00
b4a22820e7 tests are not using magic values as well... 2025-04-18 23:48:08 +02:00
af0aad2a99 Merge pull request 'also be able to cancel trips (not only events)' (#930) from zero-rower-events into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#930
2025-04-18 23:32:40 +02:00
fe6db2cdd5 one more check 2025-04-18 23:32:00 +02:00
5cd75ed8c8 also be able to cancel trips (not only events) 2025-04-18 23:24:03 +02:00
1ed0d8fd32 Merge pull request 'reduce amount of magic values, goal is to have specific states -> e.g. cancelled' (#928) from zero-rower-events into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#928
2025-04-18 23:14:04 +02:00
10740f988d reduce amount of magic values, goal is to have specific states -> e.g. cancelled 2025-04-18 23:01:17 +02:00
f98963a28a Merge pull request 'simple-nx-auth' (#924) from simple-nx-auth into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#924
2025-04-18 17:44:51 +02:00
37b6ea6057 remove unused dep; cargo clippy 2025-04-18 17:44:21 +02:00
06c5e5a9d1 Merge branch 'staging' into simple-nx-auth 2025-04-18 17:10:10 +02:00
0059dfe96f simple nx auth 2025-04-18 17:04:10 +02:00
e01afa7d74 Merge pull request 'use maries' magic css skills to unbreak signal links on mobile; Fixes #891' (#922) from signal-breaking-mobile into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#922
2025-04-17 22:01:46 +02:00
2458b0a100 Merge pull request 'signal-breaking-mobile' (#921) from signal-breaking-mobile into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#921
2025-04-17 22:01:40 +02:00
36245fd0f7 use maries' magic css skills to unbreak signal links on mobile; Fixes #891 2025-04-17 22:00:15 +02:00
85bec7f591 Merge pull request 'better description of the button' (#920) from send-fee-reminder into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#920
2025-04-17 21:54:25 +02:00
7e0b30f058 Merge pull request 'better description of the button' (#919) from send-fee-reminder into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#919
2025-04-17 21:53:56 +02:00
b0a2d3d539 better description of the button 2025-04-17 21:52:24 +02:00
ac5f9d253d Merge pull request 'allow others to send fee reminder thus reducing my bus factor' (#916) from send-fee-reminder into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#916
2025-04-17 20:44:51 +02:00
8340e8b33f Merge pull request 'allow others to send fee reminder thus reducing my bus factor' (#915) from send-fee-reminder into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#915
2025-04-17 20:44:45 +02:00
db429b6fe3 high security application... 2025-04-17 20:42:36 +02:00
cf90ab6e1a allow others to send fee reminder thus reducing my bus factor 2025-04-17 20:38:41 +02:00
3b25143a08 Merge pull request '400 instead of 303' (#907) from nx-auth into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#907
2025-04-16 11:32:07 +02:00
4ce9a573fe 400 instead of 303 2025-04-16 11:31:46 +02:00
78aafe4d41 Merge pull request 'nx-auth' (#906) from nx-auth into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#906
2025-04-16 10:57:35 +02:00
dc2ee38aa0 no funny business w/ get params 2025-04-16 10:56:57 +02:00
2b79df8e42 no funny business w/ get params 2025-04-16 10:46:19 +02:00
43c0b9ffc1 Merge pull request 'nx-auth' (#905) from nx-auth into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#905
2025-04-16 10:19:13 +02:00
588520914c add nextcloud auth route 2025-04-16 10:18:27 +02:00
f1d4b6d008 Merge pull request 'upd' (#9) from upd into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 9m27s
CI/CD Pipeline / deploy-main (push) Successful in 22m23s
Reviewed-on: #9
2025-04-15 23:20:03 +02:00
da3949cca1 Merge remote-tracking branch 'upstream/main' into upd
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-04-15 23:19:12 +02:00
819c4bb31b Merge pull request 'fix tests' (#903) from fix-cal-uid into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#903
2025-04-15 23:18:32 +02:00
0c425f7a8e Merge pull request 'fix tests' (#902) from fix-cal-uid into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#902
2025-04-15 23:18:26 +02:00
5da4b592ea fix tests 2025-04-15 23:17:57 +02:00
654674ce53 fix tests
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
2025-04-15 23:17:22 +02:00
7e9acbb5ac Merge remote-tracking branch 'upstream/main' 2025-04-15 23:15:47 +02:00
9a30ce0afb Merge pull request 'make default duration 3 hrs (to have a larger block in the cal)' (#901) from fix-cal-uid into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#901
2025-04-15 23:13:19 +02:00
21b33566bc Merge pull request 'make default duration 3 hrs (to have a larger block in the cal)' (#900) from fix-cal-uid into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#900
2025-04-15 23:13:13 +02:00
eb9dd3f864 make default duration 3 hrs (to have a larger block in the cal) 2025-04-15 23:12:30 +02:00
29f2cadb99 Merge pull request 'fix ci' (#899) from fix-cal-uid into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#899
2025-04-15 22:12:32 +02:00
ca3de1123b Merge pull request 'fix ci' (#898) from fix-cal-uid into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#898
2025-04-15 22:12:09 +02:00
f42bf5ea3a fix ci 2025-04-15 22:11:29 +02:00
dfb53291b7 Merge pull request 'have unique uid's, fixes error in some clients (e.g. sogo)' (#896) from fix-cal-uid into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#896
2025-04-15 20:56:00 +02:00
1c628f40ed Merge pull request 'also show cox_helps_at_event in cal' (#897) from fix-cal-uid into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#897
2025-04-15 20:53:40 +02:00
9fcd5a1a8f also show cox_helps_at_event in cal 2025-04-15 20:52:06 +02:00
2f4874321f Merge pull request 'have unique uid's, fixes error in some clients (e.g. sogo)' (#895) from fix-cal-uid into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#895
2025-04-15 20:33:46 +02:00
6c83d00c2c have unique uid's, fixes error in some clients (e.g. sogo) 2025-04-15 20:33:13 +02:00
0568e1fd4d Merge pull request 'update deps' (#8) from update into main
Some checks failed
CI/CD Pipeline / test (push) Successful in 9m17s
CI/CD Pipeline / deploy-main (push) Has been cancelled
Reviewed-on: #8
2025-04-15 14:27:00 +02:00
298f384875 Merge remote-tracking branch 'upstream/main'
All checks were successful
CI/CD Pipeline / test (push) Successful in 20m7s
CI/CD Pipeline / deploy-main (push) Has been skipped
2025-04-15 14:25:20 +02:00
418bcc3143 Merge pull request 'update deps' (#893) from upd into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#893
2025-04-15 14:20:28 +02:00
35dffdd8f0 Merge pull request 'upd' (#892) from upd into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#892
2025-04-15 14:20:20 +02:00
b9368e6c64 update deps 2025-04-15 14:19:35 +02:00
2853340a39 Merge pull request 'nicer text' (#7) from upd into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 11m29s
CI/CD Pipeline / deploy-main (push) Successful in 8m27s
Reviewed-on: #7
2025-04-03 21:01:19 +02:00
2ec4ec49a1 no nbsp
Some checks failed
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
2025-04-03 21:00:46 +02:00
cc1ebb8ff6 nicer text
Some checks failed
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
2025-04-03 20:58:59 +02:00
2520108fba Merge pull request 'Rebase from rowt' (#6) from upd into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 21m39s
CI/CD Pipeline / deploy-main (push) Successful in 23m24s
Reviewed-on: #6
2025-04-03 17:11:46 +02:00
1e70e798af have new 'read all notifications' button
Some checks failed
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
2025-04-03 17:06:18 +02:00
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
b419004949 Merge pull request 'fix-kiosk-error' (#885) from fix-kiosk-error into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#885
2025-03-26 20:58:10 +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
94938fb4ea Merge pull request 'update deps' (#883) from upd into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#883
2025-03-26 14:52:02 +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
2368f03761 Merge pull request 'update id's' (#881) from add-unit-test into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#881
2025-03-09 19:21:35 +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
a7d33548d4 Merge pull request 'add-unit-test' (#879) from add-unit-test into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#879
2025-03-09 19:18:24 +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
0f345862ee Merge pull request 'correct-name-in-notification' (#878) from correct-name-in-notification into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#878
2025-03-09 13:34:36 +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
856e3b2cff Merge pull request 'update deps' (#872) from update-deps into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#872
2025-03-06 10:24:35 +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
9b9cf98473 Merge pull request 'remove-philipp-mentioning' (#870) from remove-philipp-mentioning into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#870
2025-02-17 22:58:45 +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
ae61564ad4 Merge pull request 'update-deps' (#868) from update-deps into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#868
2025-02-13 10:06:50 +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
a2a39103e0 Merge pull request 'upd' (#865) from upd into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#865
2025-02-11 21:54:14 +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
d82bd3ebeb Merge pull request 'fix ci' (#862) from allow-secretary-to-edit-boats into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#862
2025-02-11 09:37:20 +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
32800b1897 Merge pull request 'allow vorstand to edit boats' (#860) from allow-secretary-to-edit-boats into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#860
2025-02-11 09:23:28 +01:00
3406b66f41 allow vorstand to edit boats 2025-02-11 09:22:22 +01:00
cfd8b12556 Merge pull request 'main' (#859) from main into staging
Reviewed-on: Ruderverein-Donau-Linz/rowt#859
2025-02-10 18:49:20 +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
27 changed files with 1513 additions and 792 deletions

View File

@@ -63,73 +63,14 @@ jobs:
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
scp -C target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/wolfgangsee/rot-updating
scp -C -r static $SSH_USER@$SSH_HOST:/home/wolfgangsee/
scp -C -r templates $SSH_USER@$SSH_HOST:/home/wolfgangsee/
scp -C -r svelte $SSH_USER@$SSH_HOST:/home/wolfgangsee/
ssh $SSH_USER@$SSH_HOST 'mkdir -p /home/wolfgangsee/svelte/build'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop wolfgangsee'
ssh $SSH_USER@$SSH_HOST 'mv /home/wolfgangsee/rot-updating /home/wolfgangsee/rot'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl start wolfgangsee'
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
- name: Deploy Normannen
run: |
mkdir -p ~/.ssh
ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
scp -C target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/normannen/rot-updating
scp -C -r static $SSH_USER@$SSH_HOST:/home/normannen/
scp -C -r templates $SSH_USER@$SSH_HOST:/home/normannen/
scp -C -r svelte $SSH_USER@$SSH_HOST:/home/normannen/
ssh $SSH_USER@$SSH_HOST 'mkdir -p /home/normannen/svelte/build'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop normannen'
ssh $SSH_USER@$SSH_HOST 'mv /home/normannen/rot-updating /home/normannen/rot'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl start normannen'
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
- name: Deploy Ister
run: |
mkdir -p ~/.ssh
ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
scp -C target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/ister/rot-updating
scp -C -r static $SSH_USER@$SSH_HOST:/home/ister/
scp -C -r templates $SSH_USER@$SSH_HOST:/home/ister/
scp -C -r svelte $SSH_USER@$SSH_HOST:/home/ister/
ssh $SSH_USER@$SSH_HOST 'mkdir -p /home/ister/svelte/build'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop ister'
ssh $SSH_USER@$SSH_HOST 'mv /home/ister/rot-updating /home/ister/rot'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl start ister'
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
- name: Deploy Kufstein
run: |
mkdir -p ~/.ssh
ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
scp -C target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/kufstein/rot-updating
scp -C -r static $SSH_USER@$SSH_HOST:/home/kufstein/
scp -C -r templates $SSH_USER@$SSH_HOST:/home/kufstein/
scp -C -r svelte $SSH_USER@$SSH_HOST:/home/kufstein/
ssh $SSH_USER@$SSH_HOST 'mkdir -p /home/kufstein/svelte/build'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop kufstein'
ssh $SSH_USER@$SSH_HOST 'mv /home/kufstein/rot-updating /home/kufstein/rot'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl start kufstein'
scp -C target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/root/rowing-wolfgangsee/rot-updating
scp -C -r static $SSH_USER@$SSH_HOST:/root/rowing-wolfgangsee/
scp -C -r templates $SSH_USER@$SSH_HOST:/root/rowing-wolfgangsee/
scp -C -r svelte $SSH_USER@$SSH_HOST:/root/rowing-wolfgangsee/
ssh $SSH_USER@$SSH_HOST 'mkdir -p /root/rowing-wolfgangsee/svelte/build'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop rowing-wolfgangsee'
ssh $SSH_USER@$SSH_HOST 'mv /root/rowing-wolfgangsee/rot-updating /root/rowing-wolfgangsee/rot'
ssh $SSH_USER@$SSH_HOST 'sudo systemctl start rowing-wolfgangsee'
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_HOST: ${{ secrets.SSH_HOST }}

1563
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
[package]
name = "rot"
version = "0.1.0"
edition = "2021"
edition = "2024"
[features]
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 }
log = "0.4"
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"
serde = { version = "1.0", features = [ "derive" ]}
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"]}
chrono-tz = "0.9"
chrono-tz = "0.10"
tera = { version = "1.18", features = ["date-locale"], optional = true}
ics = "0.5"
futures = "0.3"
lettre = "0.11"
csv = "1.3"
itertools = "0.13"
itertools = "0.14"
job_scheduler_ng = "2.0"
ureq = { version = "2.9", features = ["json"] }
ureq = { version = "3.0", features = ["json"] }
regex = "1.10"
urlencoding = "2.1"

View File

@@ -2,7 +2,7 @@
secret_key = "/NtVGizglEoyoxBLzsRDWTy4oAG1qDw4J4O+CWJSv+fypD7W9sam8hUY4j90EZsbZk8wEradS5zBoWtWKi3k8w=="
rss_key = "rss-key-for-ci"
limits = { file = "10 MiB", data-form = "10 MiB"}
smtp_pw = "8kIjlLH79Ky6D3j"
smtp_pw = "my-smtp-password"
usage_log_path = "./usage.txt"
openweathermap_key = "c8dab8f91b5b815d76e9879cbaecd8d5"
openweathermap_key = "openweather-key"
wordpress_key = "pw-to-allow-sending-notifications"

94
doc/nextcloud-notes.md Normal file
View File

@@ -0,0 +1,94 @@
# Nextcloud integration
- Based on [this plugin](https://github.com/nextcloud/user_external)
- Install that plugin via web
- Connect to server, enter nextcloud-docker-image: `docker exec -it nextcloud-aio-nextcloud bash`
- Adapt `/var/www/html/custom_apps/user_external/lib/BasicAuth.php` to switch from BasicAuth to RowtAuth:
```php
<?php
/**
* Copyright (c) 2019 Lutz Freitag <lutz.freitag@gottliebtfreitag.de>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\UserExternal;
class BasicAuth extends Base {
private $authUrl;
public function __construct($authUrl) {
parent::__construct($authUrl);
$this->authUrl = $authUrl;
}
/**
* Check if the password is correct without logging in the user
*
* @param string $uid The username
* @param string $password The password
*
* @return true/false
*/
public function checkPassword($uid, $password) {
// Prepare POST data with credentials
$postData = http_build_query([
'name' => $uid,
'password' => $password
]);
// Create context with POST method
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $postData,
'follow_location' => 0
]
]);
// Get the content of the response
$content = @file_get_contents($this->authUrl, false, $context);
if ($content === false) {
\OC::$server->getLogger()->error(
'ERROR: Failed to get content from Auth Url: '.$this->authUrl,
['app' => 'user_external']
);
return false;
}
// Check if the content is "SUCC"
if (trim($content) === "SUCC") {
$this->storeUser($uid);
return $uid;
}
return false;
}
}
```
- In `/var/www/html/config/config.php` add this:
```
'user_backends' =>
array (
0 =>
array (
'class' => '\\OCA\\UserExternal\\BasicAuth',
'arguments' =>
array (
0 => 'https://app.rudernlinz.at/nxauth',
),
),
),
```
- In `/var/www/html/config/config.php` add this `'skeletondirectory' => '',` to disable default folders for new users
- To automatically add users to a group (e.g. `vorstand`), use the `Auto Groups` plugin
- Shared folders are not shared with new members due to [this bug](https://github.com/nextcloud/server/issues/25062#issuecomment-766445043)
- Find DB config: `docker exec nextcloud-aio-database env | grep POSTGRES`
- Workaround: Connect to docker-db: `docker exec -it nextcloud-aio-database bash`
- Connect to db: `psql -U nextcloud -d nextcloud_database`
- (with `\l` you see all dbs)
- Connect to nextcloud db: `\c nextcloud_database`
- Do query from issue: `UPDATE oc_share SET accepted = 1 WHERE share_type = 1;`

View File

@@ -23,6 +23,7 @@ document.addEventListener("DOMContentLoaded", function () {
addRelationMagic(<HTMLElement>document.querySelector("body"));
reloadPage();
setCurrentdate(<HTMLInputElement>document.querySelector("#departure"));
initDropdown();
});
function changeTheme() {
@@ -795,3 +796,21 @@ function replaceStrings() {
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

@@ -120,18 +120,69 @@ test.describe("cox can edit trips", () => {
});
test("call off trip", async () => {
// Someone registers...
await sharedPage.goto("/auth/logout");
await sharedPage.goto("/auth");
await sharedPage.getByPlaceholder("Name").click();
await sharedPage.getByPlaceholder("Name").fill("rower");
await sharedPage.getByPlaceholder("Name").press("Tab");
await sharedPage.getByPlaceholder("Passwort").fill("rower");
await sharedPage.getByPlaceholder("Passwort").press("Enter");
await sharedPage.goto("/");
await sharedPage.getByRole('link', { name: 'Mitrudern' }).nth(1).click();
// Login as cox again
await sharedPage.goto("/auth/logout");
await sharedPage.goto("/auth");
await sharedPage.getByPlaceholder("Name").click();
await sharedPage.getByPlaceholder("Name").fill("cox");
await sharedPage.getByPlaceholder("Name").press("Tab");
await sharedPage.getByPlaceholder("Passwort").fill("cox");
await sharedPage.getByPlaceholder("Passwort").press("Enter");
await sharedPage.goto("/");
// ... now I can cancel trip
await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
await expect(sharedPage.locator("#sidebar")).toContainText(
"Freie Plätze: 3",
);
await sharedPage.getByRole("spinbutton").click();
await sharedPage.getByRole("spinbutton").fill("0");
await sharedPage.getByRole("button", { name: "Speichern" }).click();
await sharedPage.getByRole("button", { name: "Ausfahrt absagen" }).click();
await expect(sharedPage.locator("body")).toContainText(
"Ausfahrt erfolgreich aktualisiert.",
);
await expect(sharedPage.locator("body")).toContainText("(Absage cox)");
// Done with the test -> cancel the cancellation of the trip, otherwise the afterAll function below fails
await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
await sharedPage.getByRole("spinbutton").click();
await sharedPage.getByRole("spinbutton").fill("3");
await sharedPage.getByRole("button", { name: "Speichern" }).click();
// deregistering
await sharedPage.goto("/auth/logout");
await sharedPage.goto("/auth");
await sharedPage.getByPlaceholder("Name").click();
await sharedPage.getByPlaceholder("Name").fill("rower");
await sharedPage.getByPlaceholder("Name").press("Tab");
await sharedPage.getByPlaceholder("Passwort").fill("rower");
await sharedPage.getByPlaceholder("Passwort").press("Enter");
await sharedPage.goto("/");
await sharedPage.getByRole('link', { name: 'Abmelden' }).click();
// now cox can delete trip again in afterAll
await sharedPage.goto("/auth/logout");
await sharedPage.goto("/auth");
await sharedPage.getByPlaceholder("Name").click();
await sharedPage.getByPlaceholder("Name").fill("cox");
await sharedPage.getByPlaceholder("Name").press("Tab");
await sharedPage.getByPlaceholder("Passwort").fill("cox");
await sharedPage.getByPlaceholder("Passwort").press("Enter");
});
test.afterAll(async () => {

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" (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 ('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;');

View File

@@ -1,8 +1,8 @@
use std::io::Write;
use chrono::NaiveDate;
use chrono::{Duration, NaiveDate, NaiveTime};
use ics::{
properties::{DtStart, Summary},
properties::{DtEnd, DtStart, Summary},
ICalendar,
};
use serde::Serialize;
@@ -11,7 +11,6 @@ use sqlx::{FromRow, Row, SqlitePool};
use super::{
log::Log,
notification::Notification,
role::Role,
tripdetails::TripDetails,
triptype::TripType,
user::{EventUser, User},
@@ -34,11 +33,13 @@ pub struct Event {
}
#[derive(Serialize, Debug)]
pub struct EventWithUserAndTriptype {
pub struct EventWithDetails {
#[serde(flatten)]
pub event: Event,
trip_type: Option<TripType>,
tripdetails: TripDetails,
cox_needed: bool,
cancelled: bool,
cox: Vec<Registration>,
rower: Vec<Registration>,
}
@@ -96,8 +97,8 @@ FROM trip WHERE planned_event_id = ?
.unwrap()
.into_iter()
.map(|r| Registration {
name: r.name,
registered_at: r.registered_at,
name: r.name.unwrap(),
registered_at: r.registered_at.unwrap(),
is_guest: false,
is_real_guest: false,
})
@@ -116,6 +117,12 @@ pub struct EventUpdate<'a> {
pub trip_type_id: Option<i64>,
}
impl EventUpdate<'_> {
fn cancelled(&self) -> bool {
self.max_people == -1
}
}
impl Event {
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
sqlx::query_as!(
@@ -134,16 +141,13 @@ WHERE planned_event.id like ?
.ok()
}
pub async fn get_pinned_for_day(
db: &SqlitePool,
day: NaiveDate,
) -> Vec<EventWithUserAndTriptype> {
pub async fn get_pinned_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<EventWithDetails> {
let mut events = Self::get_for_day(db, day).await;
events.retain(|e| e.event.always_show);
events
}
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<EventWithUserAndTriptype> {
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<EventWithDetails> {
let day = format!("{day}");
let events = sqlx::query_as!(
Event,
@@ -164,10 +168,15 @@ WHERE day=?",
if let Some(trip_type_id) = event.trip_type_id {
trip_type = TripType::find_by_id(db, trip_type_id).await;
}
ret.push(EventWithUserAndTriptype {
let tripdetails = TripDetails::find_by_id(db, event.trip_details_id)
.await
.expect("db constraints");
ret.push(EventWithDetails {
cox_needed: event.planned_amount_cox > cox.len() as i64,
cox,
rower: Registration::all_rower(db, event.trip_details_id).await,
cancelled: tripdetails.cancelled(),
tripdetails,
event,
trip_type,
});
@@ -191,7 +200,8 @@ INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id",
let mut ret = Vec::new();
let events = Self::all(db).await;
for event in events {
if event.is_rower_registered(db, user).await {
if event.is_rower_registered(db, user).await || event.is_cox_registered(db, user).await
{
ret.push(event);
}
}
@@ -215,6 +225,21 @@ INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id",
is_rower.amount > 0
}
pub async fn is_cox_registered(&self, db: &SqlitePool, user: &User) -> bool {
let is_rower = sqlx::query!(
"SELECT count(*) as amount
FROM trip
WHERE planned_event_id = ?
AND cox_id = ?",
self.id,
user.id
)
.fetch_one(db)
.await
.unwrap(); //Okay, bc planned_event can only be created with proper DB backing
is_rower.amount > 0
}
pub async fn find_by_trip_details(db: &SqlitePool, tripdetails_id: i64) -> Option<Self> {
sqlx::query_as!(
Self,
@@ -297,7 +322,7 @@ WHERE trip_details.id=?
.unwrap(); //Okay, as planned_event can only be created with proper DB backing
let tripdetails = self.trip_details(db).await;
let was_already_cancelled = tripdetails.max_people == 0;
let was_already_cancelled = tripdetails.cancelled();
sqlx::query!(
"UPDATE trip_details SET max_people = ?, notes = ?, always_show = ?, is_locked = ?, trip_type_id = ? WHERE id = ?",
@@ -322,7 +347,7 @@ WHERE trip_details.id=?
.await;
}
if update.max_people == 0 && !was_already_cancelled {
if update.cancelled() && !was_already_cancelled {
let coxes = Registration::all_cox(db, self.id).await;
for user in coxes {
if let Some(user) = User::find_by_name(db, &user.name).await {
@@ -371,7 +396,7 @@ WHERE trip_details.id=?
}
}
}
if update.max_people > 0 && was_already_cancelled {
if !update.cancelled() && was_already_cancelled {
Notification::delete_by_action(
db,
&format!("remove_user_trip_with_trip_details_id:{}", tripdetails.id),
@@ -409,7 +434,7 @@ WHERE trip_details.id=?
}
pub fn is_cancelled(&self) -> bool {
self.max_people == 0
self.max_people == -1
}
pub async fn get_ics_feed(db: &SqlitePool) -> String {
@@ -425,12 +450,32 @@ WHERE trip_details.id=?
}
pub(crate) async fn get_vevent(self, db: &SqlitePool) -> ics::Event {
let mut vevent = ics::Event::new(format!("{}@ruad.at", self.id), "19900101T180000");
let mut vevent = ics::Event::new(format!("event-{}@ruad.at", self.id), "19900101T180000");
let time_str = self.planned_starting_time.replace(':', "");
let formatted_time = if time_str.len() == 3 {
format!("0{}", time_str)
} else {
time_str.clone() // TODO: remove again
};
vevent.push(DtStart::new(format!(
"{}T{}00",
self.day.replace('-', ""),
self.planned_starting_time.replace(':', "")
formatted_time
)));
let original_time = NaiveTime::parse_from_str(&self.planned_starting_time, "%H:%M")
.expect("Failed to parse time");
let later_time = original_time + Duration::hours(3);
if later_time > original_time {
// Check if no day-overflow
let time_three_hours_later = later_time.format("%H%M").to_string();
vevent.push(DtEnd::new(format!(
"{}T{}00",
self.day.replace('-', ""),
time_three_hours_later
)));
}
let tripdetails = self.trip_details(db).await;
let mut name = String::new();
if self.is_cancelled() {
@@ -513,6 +558,6 @@ mod test {
let today = Local::now().date_naive().format("%Y%m%d").to_string();
let actual = Event::get_ics_feed(&pool).await;
assert_eq!(format!("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:ics-rs\r\nBEGIN:VEVENT\r\nUID:1@ruad.at\r\nDTSTAMP:19900101T180000\r\nDTSTART:{today}T100000\r\nSUMMARY:test-planned-event \r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"), actual);
assert_eq!(format!("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:ics-rs\r\nBEGIN:VEVENT\r\nUID:event-1@ruad.at\r\nDTSTAMP:19900101T180000\r\nDTSTART:{today}T100000\r\nDTEND:{today}T130000\r\nSUMMARY:test-planned-event \r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"), actual);
}
}

View File

@@ -6,8 +6,8 @@ use waterlevel::WaterlevelDay;
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
use self::{
event::{Event, EventWithUserAndTriptype},
trip::{Trip, TripWithUserAndType},
event::{Event, EventWithDetails},
trip::{Trip, TripWithDetails},
waterlevel::Waterlevel,
weather::Weather,
};
@@ -28,8 +28,8 @@ pub mod weather;
#[derive(Serialize, Debug)]
pub struct Day {
day: NaiveDate,
events: Vec<EventWithUserAndTriptype>,
trips: Vec<TripWithUserAndType>,
events: Vec<EventWithDetails>,
trips: Vec<TripWithDetails>,
is_pinned: bool,
regular_sees_this_day: bool,
max_waterlevel: Option<WaterlevelDay>,

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) {
sqlx::query!(
"DELETE FROM notification WHERE action_after_reading=? and read_at is null",
@@ -275,7 +284,7 @@ mod test {
let cancel_update = EventUpdate {
name: &event.name,
planned_amount_cox: event.planned_amount_cox as i32,
max_people: 0,
max_people: -1,
notes: event.notes.as_deref(),
always_show: event.always_show,
is_locked: event.is_locked,
@@ -289,7 +298,7 @@ mod test {
assert_eq!(rower_notification.category, "Absage Ausfahrt");
assert_eq!(
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

View File

@@ -1,5 +1,5 @@
use chrono::{Local, NaiveDate};
use ics::properties::{DtStart, Summary};
use chrono::{Duration, Local, NaiveDate, NaiveTime};
use ics::properties::{DtEnd, DtStart, Summary};
use serde::Serialize;
use sqlx::SqlitePool;
@@ -30,11 +30,12 @@ pub struct Trip {
}
#[derive(Serialize, Debug)]
pub struct TripWithUserAndType {
pub struct TripWithDetails {
#[serde(flatten)]
pub trip: Trip,
pub rower: Vec<Registration>,
trip_type: Option<TripType>,
cancelled: bool,
}
pub struct TripUpdate<'a> {
@@ -46,7 +47,13 @@ pub struct TripUpdate<'a> {
pub is_locked: bool,
}
impl TripWithUserAndType {
impl<'a> TripUpdate<'a> {
fn cancelled(&self) -> bool {
self.max_people == -1
}
}
impl TripWithDetails {
pub async fn from(db: &SqlitePool, trip: Trip) -> Self {
let mut trip_type = None;
if let Some(trip_type_id) = trip.trip_type_id {
@@ -54,8 +61,9 @@ impl TripWithUserAndType {
}
Self {
rower: Registration::all_rower(db, trip.trip_details_id.unwrap()).await,
trip,
trip_type,
cancelled: trip.is_cancelled(),
trip,
}
}
}
@@ -81,33 +89,31 @@ impl Trip {
trip_details.planned_starting_time,
)
.await;
if same_starting_datetime.len() > 1 {
for notify in same_starting_datetime {
// don't notify oneself
if notify.id == trip_details.id {
continue;
}
for notify in same_starting_datetime {
// don't notify oneself
if notify.id == trip_details.id {
continue;
}
// don't notify people who have cancelled their trip
if notify.cancelled() {
continue;
}
// don't notify people who have cancelled their trip
if notify.cancelled() {
continue;
}
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();
Notification::create(
db,
&user,
&format!(
"{} hat eine Ausfahrt zur selben Zeit ({} um {}) wie du erstellt",
user.name, trip.day, trip.planned_starting_time
),
"Neue Ausfahrt zur selben Zeit",
None,
None,
)
.await;
}
if let Some(trip) = Trip::find_by_trip_details(db, notify.id).await {
let user_earlier_trip = User::find_by_id(db, trip.cox_id as i32).await.unwrap();
Notification::create(
db,
&user_earlier_trip,
&format!(
"{} hat eine Ausfahrt zur selben Zeit ({} um {}) wie du erstellt",
user.name, trip.day, trip.planned_starting_time
),
"Neue Ausfahrt zur selben Zeit",
None,
None,
)
.await;
}
}
}
@@ -130,12 +136,33 @@ WHERE trip_details.id=?
}
pub(crate) async fn get_vevent(self, user: &User) -> ics::Event {
let mut vevent = ics::Event::new(format!("{}@ruad.at", self.id), "19900101T180000");
let mut vevent = ics::Event::new(format!("trip-{}@ruad.at", self.id), "19900101T180000");
let time_str = self.planned_starting_time.replace(':', "");
let formatted_time = if time_str.len() == 3 {
format!("0{}", time_str)
} else {
time_str
};
vevent.push(DtStart::new(format!(
"{}T{}00",
self.day.replace('-', ""),
self.planned_starting_time.replace(':', "")
formatted_time
)));
let original_time = NaiveTime::parse_from_str(&self.planned_starting_time, "%H:%M")
.expect("Failed to parse time");
let later_time = original_time + Duration::hours(3);
if later_time > original_time {
// Check if no day-overflow
let time_three_hours_later = later_time.format("%H%M").to_string();
vevent.push(DtEnd::new(format!(
"{}T{}00",
self.day.replace('-', ""),
time_three_hours_later
)));
}
let mut name = String::new();
if self.is_cancelled() {
name.push_str("ABGESAGT");
@@ -222,7 +249,7 @@ WHERE trip.id=?
return Err(CoxHelpError::DetailsLocked);
}
if event.max_people == 0 {
if event.is_cancelled() {
return Err(CoxHelpError::CanceledEvent);
}
@@ -239,12 +266,12 @@ WHERE trip.id=?
}
}
pub async fn get_for_today(db: &SqlitePool) -> Vec<TripWithUserAndType> {
pub async fn get_for_today(db: &SqlitePool) -> Vec<TripWithDetails> {
let today = Local::now().date_naive();
Self::get_for_day(db, today).await
}
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<TripWithUserAndType> {
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<TripWithDetails> {
let day = format!("{day}");
let trips = sqlx::query_as!(
Trip,
@@ -263,7 +290,7 @@ WHERE day=?
let mut ret = Vec::new();
for trip in trips {
ret.push(TripWithUserAndType::from(db, trip).await);
ret.push(TripWithDetails::from(db, trip).await);
}
ret
}
@@ -277,10 +304,8 @@ WHERE day=?
return Err(TripUpdateError::NotYourTrip);
}
if update.trip_type != Some(4) {
if !update.cox.allowed_to_steer(db).await {
return Err(TripUpdateError::TripTypeNotAllowed);
}
if update.trip_type != Some(4) && !update.cox.allowed_to_steer(db).await {
return Err(TripUpdateError::TripTypeNotAllowed);
}
let Some(trip_details_id) = update.trip.trip_details_id else {
@@ -288,9 +313,9 @@ WHERE day=?
};
let tripdetails = TripDetails::find_by_id(db, trip_details_id).await.unwrap();
let was_already_cancelled = tripdetails.max_people == 0;
let was_already_cancelled = tripdetails.cancelled();
let is_locked = if update.max_people == 0 {
let is_locked = if update.cancelled() {
false
} else {
update.is_locked
@@ -308,10 +333,8 @@ WHERE day=?
.await
.unwrap(); //Okay, as trip_details can only be created with proper DB backing
if update.max_people == 0 && !was_already_cancelled {
let rowers = TripWithUserAndType::from(db, update.trip.clone())
.await
.rower;
if update.cancelled() && !was_already_cancelled {
let rowers = TripWithDetails::from(db, update.trip.clone()).await.rower;
for user in rowers {
if let Some(user) = User::find_by_name(db, &user.name).await {
let notes = match update.notes {
@@ -347,7 +370,7 @@ WHERE day=?
.await;
}
if update.max_people > 0 && was_already_cancelled {
if !update.cancelled() && was_already_cancelled {
Notification::delete_by_action(
db,
&format!("remove_user_trip_with_trip_details_id:{}", trip_details_id),
@@ -435,14 +458,14 @@ WHERE day=?
pub(crate) async fn get_pinned_for_day(
db: &sqlx::Pool<sqlx::Sqlite>,
day: NaiveDate,
) -> Vec<TripWithUserAndType> {
) -> Vec<TripWithDetails> {
let mut trips = Self::get_for_day(db, day).await;
trips.retain(|e| e.trip.always_show);
trips
}
fn is_cancelled(&self) -> bool {
self.max_people == 0
self.max_people == -1
}
}
@@ -478,6 +501,7 @@ mod test {
use crate::{
model::{
event::Event,
notification::Notification,
trip::{self, TripDeleteError},
tripdetails::TripDetails,
user::{SteeringUser, User},
@@ -509,6 +533,34 @@ mod test {
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]
fn test_get_day_cox_trip() {
let pool = testdb!();

View File

@@ -6,7 +6,7 @@ use sqlx::{FromRow, SqlitePool};
use super::{
notification::Notification,
trip::{Trip, TripWithUserAndType},
trip::{Trip, TripWithDetails},
triptype::TripType,
};
@@ -95,7 +95,7 @@ WHERE day = ? AND planned_starting_time = ?
}
pub fn cancelled(&self) -> bool {
self.max_people == 0
self.max_people == -1
}
/// This function is called when a person registers to a trip or when the cox changes the
@@ -138,7 +138,7 @@ WHERE day = ? AND planned_starting_time = ?
// This trip_details belongs to a planned_event, no need to do anything
continue;
};
let pot_coxes = TripWithUserAndType::from(db, trip.clone()).await;
let pot_coxes = TripWithDetails::from(db, trip.clone()).await;
let pot_coxes = pot_coxes.rower;
for user in pot_coxes {
let cox = User::find_by_id(db, trip.cox_id as i32).await.unwrap();
@@ -196,7 +196,7 @@ WHERE day = ? AND planned_starting_time = ?
.fetch_one(db)
.await
.unwrap(); //TODO: fixme
let amount_currently_registered = i64::from(amount_currently_registered.count);
let amount_currently_registered = amount_currently_registered.count;
amount_currently_registered >= self.max_people
}
@@ -339,7 +339,7 @@ mod test {
}
)
.await,
3,
4,
);
assert_eq!(
TripDetails::create(
@@ -354,7 +354,7 @@ mod test {
}
)
.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 {
#[serde(flatten)]
pub user: User,
pub amount_unread_notifications: i32,
pub amount_unread_notifications: i64,
pub allowed_to_steer: bool,
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
}
pub async fn amount_unread_notifications(&self, db: &SqlitePool) -> i32 {
pub async fn amount_unread_notifications(&self, db: &SqlitePool) -> i64 {
sqlx::query!(
"SELECT COUNT(*) as count FROM notification WHERE user_id = ? AND read_at IS NULL",
self.id
@@ -197,18 +197,27 @@ WHERE lower(name)=?
}
pub async fn all(db: &SqlitePool) -> Vec<Self> {
sqlx::query_as!(
Self,
Self::all_with_order(db, "last_access", false).await
}
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
FROM user
WHERE deleted = 0
ORDER BY last_access DESC
"
)
.fetch_all(db)
.await
.unwrap()
SELECT id, name, pw, deleted, last_access, user_token
FROM user
WHERE deleted = 0
ORDER BY {}
",
sort
);
if !asc {
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> {

View File

@@ -3,7 +3,7 @@ use sqlx::{FromRow, SqlitePool};
use super::{
notification::Notification,
trip::{Trip, TripWithUserAndType},
trip::{Trip, TripWithDetails},
tripdetails::TripDetails,
user::{SteeringUser, User},
};
@@ -158,7 +158,7 @@ impl UserTrip {
.unwrap()
.cancelled()
{
let trip = TripWithUserAndType::from(db, trip.clone()).await;
let trip = TripWithDetails::from(db, trip.clone()).await;
if trip.rower.len() == 1 {
trip_to_delete = Some(trip.trip);
}

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";
match ureq::get(url).call() {
Ok(response) => {
let forecast: Result<Vec<Station>, _> = response.into_json();
Ok(mut response) => {
let forecast: Result<Vec<Station>, _> = response.body_mut().read_json();
if let Ok(data) = forecast {
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}");
match ureq::get(&url).call() {
Ok(response) => {
let data: Result<Data, _> = response.into_json();
Ok(mut response) => {
let data: Result<Data, _> = response.body_mut().read_json();
if let Ok(data) = data {
Ok(data)

View File

@@ -33,13 +33,17 @@ impl<'r> FromRequest<'r> for Referer {
}
}
#[get("/user")]
#[get("/user?<sort>&<asc>")]
async fn index(
db: &State<SqlitePool>,
user: ManageUserUser,
flash: Option<FlashMessage<'_>>,
sort: Option<String>,
asc: bool,
) -> 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
.into_iter()
.map(|u| async move { UserWithDetails::from_user(u, db).await })

View File

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

View File

@@ -71,7 +71,6 @@ async fn steering(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage
fn unauthorized_error(req: &Request) -> Redirect {
// Save the URL the user tried to access, to be able to go there once logged in
let mut redirect_cookie = Cookie::new("redirect_url", format!("{}", req.uri()));
println!("{}", req.uri());
redirect_cookie.set_expires(OffsetDateTime::now_utc() + Duration::hours(1));
req.cookies().add_private(redirect_cookie);

View File

@@ -30,6 +30,12 @@ async fn mark_read(db: &State<SqlitePool>, user: User, notification_id: i64) ->
}
}
pub fn routes() -> Vec<Route> {
routes![mark_read]
#[get("/read/all")]
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">
<h1 class="h1">Mitglieder</h1>
{% 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"
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">
<h2 class="text-md font-bold mb-2 uppercase tracking-wide">Neues Mitglied hinzufügen</h2>
<div class="grid md:grid-cols-3">
<div>
<label for="name" class="sr-only">Name</label>
@@ -19,21 +21,44 @@
</div>
</div>
</div>
<div class="text-right">
<div class="text-right ml-3">
<input value="Hinzufügen"
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" />
</div>
</form>
</details>
{% endif %}
<!-- START filterBar -->
<div class="search-wrapper">
<div class="search-wrapper flex">
<label for="name" class="sr-only">Suche</label>
<input type="search"
name="name"
id="filter-js"
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>
<!-- END filterBar -->
<div id="filter-result-js" class="search-result"></div>
@@ -46,7 +71,7 @@
<span class="text-black dark:text-white cursor-pointer">
<span class="font-bold">
{{ 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"
method="post"
enctype="multipart/form-data"

View File

@@ -4,13 +4,12 @@
{% extends "base" %}
{% macro show_place(aisle_name, side_name, level) %}
<li class="truncate p-2 flex relative w-full">
{% set aisle = aisle_name ~ "-aisle" %}
{% set place = boathouse[aisle][side_name] %}
{% set place = boathouse[aisle_name][side_name].boats %}
{% if place[level] %}
{{ place[level].1.name }}
{{ place[level].boat.name }}
{% if "admin" in loggedin_user.roles %}
<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 %}
{% elif boats | length > 0 %}
{% if "admin" in loggedin_user.roles %}

View File

@@ -20,10 +20,10 @@
<li>
<a class="break-all underline" href="/cal"><strong>Alle Events</strong></a>
<br />
<small>Beachte, dass dieser Kalender keine Ausfahrten enthält, die von einzelnen Steuerpersonen augeschrieben werden. Dieser Kalender auf der Vereinswebsite verwendet werden, wo zB keine persönlichen Daten (Namen etc.) veröffentlicht werden soll.</small>
<small>Beachte, dass dieser Kalender keine Ausfahrten enthält, die von einzelnen Steuerpersonen augeschrieben werden. Dieser Kalender kann zB auf der Vereinswebsite verwendet werden, wo keine persönlichen Daten (Namen etc.) veröffentlicht werden sollen.</small>
</li>
</ol>
Du kannst die Kalender einfach in deinen Kalender als "externen Kalender" synchronisieren. Die genauen Schritte hängen von deiner verwendeten Software ab.
Du kannst die Kalender einfach in deinen Kalender als <q>externen Kalender</q> synchronisieren. Die genauen Schritte hängen von deiner verwendeten Software ab.
</div>
</div>

View File

@@ -51,7 +51,7 @@
{% if event.always_show and not day.regular_sees_this_day %}
<span title="Du siehst diese Ausfahrt schon, obwohl sie mehr als {{ amount_days_to_show_trips_ahead }} Tage in der Zukunft liegt. Du Magier!">🔮</span>
{% endif -%}
{%- if event.max_people == 0 %}
{%- if event.cancelled %}
<strong class="text-[#f43f5e]">&#9888; Absage
{{ event.planned_starting_time }}
Uhr
@@ -129,7 +129,7 @@
<div id="event{{ event.trip_details_id }}">
{# --- START List Coxes --- #}
{% if event.planned_amount_cox > 0 %}
{% if event.max_people == 0 %}
{% if event.cancelled %}
{{ macros::box(participants=event.cox, empty_seats="", header='Absage', bg='[#f43f5e]') }}
{% else %}
{% if amount_cox_missing > 0 %}
@@ -142,9 +142,9 @@
{# --- END List Coxes --- #}
{# --- START List Rowers --- #}
{% set amount_cur_rower = event.rower | length %}
{% if event.max_people == 0 %}
{% if event.cancelled %}
{{ macros::box(header='Absage', bg='[#f43f5e]', participants=event.rower, trip_details_id=event.trip_details_id, allow_removing="manage_events" in loggedin_user.roles) }}
{% else %}
{% elif event.max_people > 0 %}
{{ macros::box(participants=event.rower, empty_seats=event.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=event.trip_details_id, allow_removing="manage_events" in loggedin_user.roles) }}
{% endif %}
{# --- END List Rowers --- #}
@@ -167,7 +167,11 @@
<input type="hidden" name="_method" value="put" />
<input type="hidden" name="id" value="{{ event.id }}" />
{{ macros::input(label='Titel', name='name', type='input', value=event.name) }}
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=event.max_people, min='1') }}
{% if event.cancelled %}
<input type="hidden" name="max_people" value="-1" />
{% else %}
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=event.max_people, min='1') }}
{% endif %}
{{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', value=event.planned_amount_cox, required=true, min='0') }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show', id=event.id,checked=event.always_show, help="Grundsätzlich sehen Rudernde Ausfahrten 10 Tage im vorhinein. Wenn du diese Option aktivierst, ist diese Ausfahrt sofort allen ersichtlich.") }}
{{ macros::checkbox(label='Gesperrt', name='is_locked', id=event.id,checked=event.is_locked, help="Wenn diese Option aktiviert ist, kann sich keiner mehr an- und abmelden. Sinnvoll, wenn zB bereits die Bootseinteilung vorgenommen wurde") }}
@@ -187,7 +191,7 @@
</a>
</div>
{% else %}
{% if event.max_people == 0 %}
{% if event.cancelled %}
Wenn du deine Absage absagen (:^)) willst, einfach entsprechende Anzahl an Ruderer oben eintragen.
{% else %}
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
@@ -196,9 +200,8 @@
<input type="hidden" name="_method" value="put" />
<input type="hidden" name="id" value="{{ event.id }}" />
{{ macros::input(label='Grund der Absage', name='notes', type='input', value='') }}
{{ macros::input(label='', name='max_people', type='hidden', value=0) }}
{{ macros::input(label='', name='max_people', type='hidden', value=-1) }}
{{ macros::input(label='', name='name', type='hidden', value=event.name) }}
{{ macros::input(label='', name='max_people', type='hidden', value=event.max_people) }}
{{ macros::input(label='', name='planned_amount_cox', type='hidden', value=event.planned_amount_cox) }}
{{ macros::input(label='', name='always_show', type='hidden', value=event.always_show) }}
{{ macros::input(label='', name='is_locked', type='hidden', value=event.is_locked) }}
@@ -228,7 +231,7 @@
{% if trip.always_show and not day.regular_sees_this_day %}
<span title="Du siehst diese Ausfahrt schon, obwohl sie mehr als {{ amount_days_to_show_trips_ahead }} Tage in der Zukunft liegt. Du Magier!">🔮</span>
{% endif -%}
{% if trip.max_people == 0 %}
{% if trip.cancelled %}
<strong class="text-[#f43f5e]">&#9888;
{{ trip.planned_starting_time }}
Uhr</strong>
@@ -250,7 +253,7 @@
{% endif %}
<br />
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>
{% if trip.max_people == 0 %}&#9888;{% endif %}
{% if trip.cancelled %}&#9888;{% endif %}
{{ trip.planned_starting_time }} Uhr</strong> ({{ trip.cox_name }})
{% if trip.trip_type %}<small class='block'>{{ trip.trip_type.desc }}</small>{% endif %}
{% if trip.notes %}<small class='block'>{{ trip.notes }}</small>{% endif %}
@@ -279,7 +282,7 @@
{# --- START Sidebar Content --- #}
<div class="hidden">
<div id="trip{{ trip.trip_details_id }}">
{% if trip.max_people == 0 %}
{% if trip.cancelled %}
{# --- border-[#f43f5e] bg-[#f43f5e] --- #}
{{ macros::box(participants=trip.rower,bg='[#f43f5e]',header='Absage', trip_details_id=trip.trip_details_id, allow_removing=loggedin_user.id == trip.cox_id) }}
{% else %}
@@ -319,13 +322,13 @@
</a>
</div>
{% else %}
{% if trip.max_people == 0 %}
{% if trip.cancelled %}
Wenn du deine Absage absagen (:^)) willst, einfach entsprechende Anzahl an Ruderer oben eintragen.
{% else %}
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
<h3 class="text-primary-950 dark:text-white font-bold uppercase tracking-wide mb-2">Ausfahrt absagen</h3>
<form action="/cox/trip/{{ trip.id }}" method="post" class="grid">
{{ macros::input(label='', name='max_people', type='hidden', value=0) }}
{{ macros::input(label='', name='max_people', type='hidden', value=-1) }}
{{ macros::input(label='Grund der Absage', name='notes', type='input', value='') }}
{{ macros::input(label='', name='is_locked', type='hidden', value=trip.is_locked) }}
{{ macros::input(label='', name='trip_type', type='hidden', value=trip.trip_type_id) }}

View File

@@ -9,7 +9,8 @@
{% if notifications %}
{% if loggedin_user.amount_unread_notifications > 10 %}
<div class="text-primary-950 dark:text-white bg-gray-200 dark:bg-primary-950 bg-opacity-80 text-center pb-3 px-3">
Du hast viele ungelesene Benachrichtigungen. Um deine Oberfläche übersichtlich zu halten und wichtige Updates nicht zu verpassen, nimm dir bitte einen Moment Zeit sie zu überprüfen und als gelesen zu markieren (&#10003;).
Du hast viele ungelesene Benachrichtigungen. Um deine Oberfläche übersichtlich zu halten und wichtige Updates nicht zu verpassen, nimm dir bitte in Zukunft einen kurzen Moment Zeit sie zu überprüfen und als gelesen zu markieren (&#10003;).<br /><a href="/notification/read/all" class="underline">Du kannst hier ausnahmsweise alle als gelesen markieren.</a>
</div>
{% endif %}
<div class="divide-y">