Compare commits
	
		
			21 Commits
		
	
	
		
			6f491e20e5
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1add5c2a2a | |||
| 567f31dd3d | |||
| eec485dced | |||
| b48b689aeb | |||
| 9f57cbaa71 | |||
| 
						 | 
					284a853344 | ||
| 
						 | 
					ebce600356 | ||
| 6e418b6f2f | |||
| 328a8e3e35 | |||
| bfb95610f6 | |||
| 68674dd1c5 | |||
| 9a16ce0c21 | |||
| 16689318eb | |||
| b12ea81bbf | |||
| 49a638d595 | |||
| 452d257c7a | |||
| 599eec0e43 | |||
| 433c914c4a | |||
| 0338351eef | |||
| e1803aea3e | |||
| 72c19d7a75 | 
@@ -17,6 +17,9 @@ jobs:
 | 
			
		||||
    - name: Run Test DB Script
 | 
			
		||||
      run: ./test_db.sh
 | 
			
		||||
 | 
			
		||||
    - name: Test
 | 
			
		||||
      run: npm --version
 | 
			
		||||
 | 
			
		||||
    - name: Cache Cargo dependencies
 | 
			
		||||
      uses: Swatinem/rust-cache@v2
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -425,10 +425,8 @@ function initNewChoice(select: HTMLInputElement) {
 | 
			
		||||
    maxItemText: (maxItemCount) => {
 | 
			
		||||
      return `Nur ${maxItemCount} Ruderer können hinzugefügt werden`;
 | 
			
		||||
    },
 | 
			
		||||
    callbackOnInit: function (this: Choices) {
 | 
			
		||||
      const items = this.getValue(); // Get all selected items
 | 
			
		||||
      const itemsArray = Array.isArray(items) ? items : [items];
 | 
			
		||||
      itemsArray.forEach((obj: any) => {
 | 
			
		||||
    callbackOnInit: function () {
 | 
			
		||||
      this._currentState.items.forEach(function (obj) {
 | 
			
		||||
        if (boat_in_ottensheim && obj.customProperties) {
 | 
			
		||||
          if (obj.customProperties.is_racing) {
 | 
			
		||||
            const coxSelect = <HTMLSelectElement>(
 | 
			
		||||
 
 | 
			
		||||
@@ -9,20 +9,20 @@
 | 
			
		||||
    "preview": "vite preview"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@playwright/test": "^1.55.1",
 | 
			
		||||
    "@types/d3": "^7.4.3",
 | 
			
		||||
    "@types/node": "^24.6.1",
 | 
			
		||||
    "autoprefixer": "^10.4.21",
 | 
			
		||||
    "postcss": "^8.5.6",
 | 
			
		||||
    "sass": "^1.93.2",
 | 
			
		||||
    "tailwindcss": "^3.4.18",
 | 
			
		||||
    "@playwright/test": "^1.40.1",
 | 
			
		||||
    "@types/d3": "^7.4.1",
 | 
			
		||||
    "@types/node": "^20.11.4",
 | 
			
		||||
    "autoprefixer": "^10.4.14",
 | 
			
		||||
    "postcss": "^8.4.21",
 | 
			
		||||
    "sass": "^1.60.0",
 | 
			
		||||
    "tailwindcss": "^3.3.1",
 | 
			
		||||
    "typescript": "^5.9.3",
 | 
			
		||||
    "vite": "^7.1.7",
 | 
			
		||||
    "vite-plugin-static-copy": "^3.1.3"
 | 
			
		||||
    "vite": "^4.2.0",
 | 
			
		||||
    "vite-plugin-static-copy": "^0.13.1"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "choices.js": "^11.1.0",
 | 
			
		||||
    "d3": "^7.9.0",
 | 
			
		||||
    "terser": "^5.44.0"
 | 
			
		||||
    "choices.js": "^10.2.0",
 | 
			
		||||
    "d3": "^7.8.5",
 | 
			
		||||
    "terser": "^5.21.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -860,6 +860,7 @@ special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch", +"Förde
 | 
			
		||||
special_user!(DonauLinzUser, +"Donau Linz", +"Förderndes Mitglied", -"Unterstützend"); // TODO:
 | 
			
		||||
                                                                                       // remove ->
 | 
			
		||||
                                                                                       // RegularUser
 | 
			
		||||
special_user!(ErgoAdminUser, +"ergo-admin", +"admin");
 | 
			
		||||
special_user!(SchnupperBetreuerUser, +"schnupper-betreuer");
 | 
			
		||||
special_user!(VorstandUser, +"admin", +"Vorstand");
 | 
			
		||||
special_user!(EventUser, +"manage_events");
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								src/tera/ergo.rs
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								src/tera/ergo.rs
									
									
									
									
									
								
							@@ -1,8 +1,7 @@
 | 
			
		||||
use std::env;
 | 
			
		||||
 | 
			
		||||
use chrono::Utc;
 | 
			
		||||
use chrono::{Datelike, Utc};
 | 
			
		||||
use rocket::{
 | 
			
		||||
    FromForm, Route, State,
 | 
			
		||||
    form::Form,
 | 
			
		||||
    fs::TempFile,
 | 
			
		||||
    get,
 | 
			
		||||
@@ -10,18 +9,19 @@ use rocket::{
 | 
			
		||||
    post,
 | 
			
		||||
    request::FlashMessage,
 | 
			
		||||
    response::{Flash, Redirect},
 | 
			
		||||
    routes,
 | 
			
		||||
    routes, FromForm, Route, State,
 | 
			
		||||
};
 | 
			
		||||
use rocket_dyn_templates::{Template, context};
 | 
			
		||||
use rocket_dyn_templates::{context, Template};
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
use sqlx::SqlitePool;
 | 
			
		||||
use tera::Context;
 | 
			
		||||
 | 
			
		||||
use crate::model::{
 | 
			
		||||
    activity::ActivityBuilder,
 | 
			
		||||
    log::Log,
 | 
			
		||||
    notification::Notification,
 | 
			
		||||
    role::Role,
 | 
			
		||||
    user::{AdminUser, User, UserWithDetails},
 | 
			
		||||
    user::{AdminUser, ErgoAdminUser, User, UserWithDetails},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
@@ -59,7 +59,7 @@ async fn send(db: &State<SqlitePool>, _user: AdminUser) -> Template {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[get("/reset")]
 | 
			
		||||
async fn reset(db: &State<SqlitePool>, _user: AdminUser) -> Flash<Redirect> {
 | 
			
		||||
async fn reset(db: &State<SqlitePool>, _user: ErgoAdminUser) -> Flash<Redirect> {
 | 
			
		||||
    sqlx::query!("UPDATE user SET dirty_thirty = NULL, dirty_dozen = NULL;")
 | 
			
		||||
        .execute(db.inner())
 | 
			
		||||
        .await
 | 
			
		||||
@@ -74,7 +74,7 @@ async fn reset(db: &State<SqlitePool>, _user: AdminUser) -> Flash<Redirect> {
 | 
			
		||||
#[get("/<challenge>/user/<user_id>/new?<new>")]
 | 
			
		||||
async fn update(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    _admin: AdminUser,
 | 
			
		||||
    _admin: ErgoAdminUser,
 | 
			
		||||
    challenge: &str,
 | 
			
		||||
    user_id: i64,
 | 
			
		||||
    new: &str,
 | 
			
		||||
@@ -146,47 +146,61 @@ pub struct UserAdd {
 | 
			
		||||
    sex: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//#[post("/set-data", data = "<data>")]
 | 
			
		||||
//async fn new_user(db: &State<SqlitePool>, data: Form<UserAdd>, user: User) -> Flash<Redirect> {
 | 
			
		||||
//    if user.has_role(db, "ergo").await {
 | 
			
		||||
//        return Flash::error(Redirect::to("/ergo"), "Du hast deine Daten schon eingegeben. Wenn du sie updaten willst, melde dich bitte bei it@rudernlinz.at");
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    // check data
 | 
			
		||||
//    if data.birthyear < 1900 || data.birthyear > chrono::Utc::now().year() - 5 {
 | 
			
		||||
//        return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geburtsjahr...");
 | 
			
		||||
//    }
 | 
			
		||||
//    if data.weight < 20 || data.weight > 200 {
 | 
			
		||||
//        return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Gewicht...");
 | 
			
		||||
//    }
 | 
			
		||||
//    if &data.sex != "f" && &data.sex != "m" {
 | 
			
		||||
//        return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geschlecht...");
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    // set data
 | 
			
		||||
//    user.update_ergo(db, data.birthyear, data.weight, &data.sex)
 | 
			
		||||
//        .await;
 | 
			
		||||
//
 | 
			
		||||
//    // inform all other `ergo` users
 | 
			
		||||
//    let ergo = Role::find_by_name(db, "ergo").await.unwrap();
 | 
			
		||||
//    Notification::create_for_role(
 | 
			
		||||
//        db,
 | 
			
		||||
//        &ergo,
 | 
			
		||||
//        &format!("{} nimmt heuer an der Ergochallenge teil 💪", user.name),
 | 
			
		||||
//        "Ergo Challenge",
 | 
			
		||||
//        None,
 | 
			
		||||
//        None,
 | 
			
		||||
//    )
 | 
			
		||||
//    .await;
 | 
			
		||||
//
 | 
			
		||||
//    // add to `ergo`  group
 | 
			
		||||
//    user.add_role(db, &ergo).await.unwrap();
 | 
			
		||||
//
 | 
			
		||||
//    Flash::success(
 | 
			
		||||
//        Redirect::to("/ergo"),
 | 
			
		||||
//        "Du hast deine Daten erfolgreich eingegeben. Viel Spaß beim Schwitzen :-)",
 | 
			
		||||
//    )
 | 
			
		||||
//}
 | 
			
		||||
#[post("/set-data", data = "<data>")]
 | 
			
		||||
async fn new_user(db: &State<SqlitePool>, data: Form<UserAdd>, user: User) -> Flash<Redirect> {
 | 
			
		||||
    if user.has_role(db, "ergo").await {
 | 
			
		||||
        return Flash::error(Redirect::to("/ergo"), "Du hast deine Daten schon eingegeben. Wenn du sie updaten willst, melde dich bitte bei info@rudernlinz.at");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // check data
 | 
			
		||||
    if data.birthyear < 1900 || data.birthyear > chrono::Utc::now().year() - 5 {
 | 
			
		||||
        return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geburtsjahr...");
 | 
			
		||||
    }
 | 
			
		||||
    if data.weight < 20 || data.weight > 200 {
 | 
			
		||||
        return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Gewicht...");
 | 
			
		||||
    }
 | 
			
		||||
    if &data.sex != "f" && &data.sex != "m" {
 | 
			
		||||
        return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geschlecht...");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set data
 | 
			
		||||
    user.update_ergo(db, data.birthyear, data.weight, &data.sex)
 | 
			
		||||
        .await;
 | 
			
		||||
 | 
			
		||||
    // inform all other `ergo` users
 | 
			
		||||
    let ergo = Role::find_by_name(db, "ergo").await.unwrap();
 | 
			
		||||
    Notification::create_for_role(
 | 
			
		||||
        db,
 | 
			
		||||
        &ergo,
 | 
			
		||||
        &format!("{} nimmt heuer an der Ergochallenge teil 💪", user.name),
 | 
			
		||||
        "Ergo Challenge",
 | 
			
		||||
        None,
 | 
			
		||||
        None,
 | 
			
		||||
    )
 | 
			
		||||
    .await;
 | 
			
		||||
 | 
			
		||||
    // add to `ergo`  group
 | 
			
		||||
    sqlx::query!(
 | 
			
		||||
        "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)",
 | 
			
		||||
        user.id,
 | 
			
		||||
        ergo.id
 | 
			
		||||
    )
 | 
			
		||||
    .execute(db.inner())
 | 
			
		||||
    .await
 | 
			
		||||
    .unwrap();
 | 
			
		||||
 | 
			
		||||
    ActivityBuilder::new(&format!(
 | 
			
		||||
        "{user} nimmt an der Ergo-Challenge teil und hat gerade die Daten eingegeben."
 | 
			
		||||
    ))
 | 
			
		||||
    .user(&user)
 | 
			
		||||
    .save(db)
 | 
			
		||||
    .await;
 | 
			
		||||
 | 
			
		||||
    Flash::success(
 | 
			
		||||
        Redirect::to("/ergo"),
 | 
			
		||||
        "Du hast deine Daten erfolgreich eingegeben. Viel Spaß beim Schwitzen :-)",
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(FromForm, Debug)]
 | 
			
		||||
pub struct ErgoToAdd<'a> {
 | 
			
		||||
@@ -359,10 +373,7 @@ async fn new_dozen(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn routes() -> Vec<Route> {
 | 
			
		||||
    routes![
 | 
			
		||||
        index, new_thirty, new_dozen, send, reset, update,
 | 
			
		||||
        // new_user
 | 
			
		||||
    ]
 | 
			
		||||
    routes![index, new_thirty, new_dozen, send, reset, update, new_user]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_
 | 
			
		||||
 | 
			
		||||
    let date = chrono::Utc::now();
 | 
			
		||||
    if date.month() <= 3 || date.month() >= 10 {
 | 
			
		||||
        //context.insert("show_quick_ergo_button", "yes");
 | 
			
		||||
        context.insert("show_quick_ergo_button", "yes");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    context.insert("achievements", &Achievements::for_user(db, &user).await);
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,7 @@
 | 
			
		||||
                               class="link-primary">Überblick der Challenges</a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li class="py-1">
 | 
			
		||||
                            Eintragung ist jederzeit möglich, alle Daten die bis Sonntag 23:59 hier hochgeladen wurden, werden gesammelt an die Ister Ergo Challenge geschickt
 | 
			
		||||
                            <li class="py-1">
 | 
			
		||||
                                Montag → gemeinsames Training; bitte um <a href="/planned" class="link-primary">Anmeldung</a>, damit jeder einen Ergo hat
 | 
			
		||||
                            </li>
 | 
			
		||||
                            Eintragung ist jederzeit möglich, wenn du sie auch an die offizielle Liste schicken willst, kannst du das <a href="https://data.ergochallenge.at/" target="_blank" style="text-decoration: underline">hier</a> machen
 | 
			
		||||
                            <li class="py-1">
 | 
			
		||||
                                <a href="https://data.ergochallenge.at"
 | 
			
		||||
                                   target="_blank"
 | 
			
		||||
@@ -194,7 +191,7 @@
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </details>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% if "admin" in loggedin_user.roles %}
 | 
			
		||||
                    {% if "admin" in loggedin_user.roles or "ergo-admin" in loggedin_user.roles %}
 | 
			
		||||
                        <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow grid gap-3">
 | 
			
		||||
                            <h2 class="h2">Update</h2>
 | 
			
		||||
                            <details class="p-2">
 | 
			
		||||
@@ -233,6 +230,14 @@
 | 
			
		||||
                                    </ol>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </details>
 | 
			
		||||
                              <div class="mt-3 text-right">
 | 
			
		||||
                                <a href="/ergo/reset"
 | 
			
		||||
                                   class="w-28 btn btn-alert"
 | 
			
		||||
                                   onclick="return confirm('Willst du wirklich alle Ergo-Eingaben löschen?');">
 | 
			
		||||
                                    {% include "includes/delete-icon" %}
 | 
			
		||||
                                    Einträge löschen
 | 
			
		||||
                                </a>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user