forked from Ruderverein-Donau-Linz/rowt
		
	start working on cal
This commit is contained in:
		
							
								
								
									
										2
									
								
								TODO.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								TODO.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
- create new field in user table -> user\_token
 | 
			
		||||
- change in misc.rs personal calendar function on not require User, but user\_token
 | 
			
		||||
@@ -183,6 +183,17 @@ INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id",
 | 
			
		||||
        .unwrap() //TODO: fixme
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn all_with_user(db: &SqlitePool, user: &User) -> Vec<Event> {
 | 
			
		||||
        let mut ret = Vec::new();
 | 
			
		||||
        let events = Self::all(db).await;
 | 
			
		||||
        for event in events {
 | 
			
		||||
            if event.is_rower_registered(db, user).await {
 | 
			
		||||
                ret.push(event);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ret
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //TODO: add tests
 | 
			
		||||
    pub async fn is_rower_registered(&self, db: &SqlitePool, user: &User) -> bool {
 | 
			
		||||
        let is_rower = sqlx::query!(
 | 
			
		||||
@@ -394,38 +405,41 @@ WHERE trip_details.id=?
 | 
			
		||||
 | 
			
		||||
        let events = Event::all(db).await;
 | 
			
		||||
        for event in events {
 | 
			
		||||
            let mut vevent =
 | 
			
		||||
                ics::Event::new(format!("{}@rudernlinz.at", event.id), "19900101T180000");
 | 
			
		||||
            vevent.push(DtStart::new(format!(
 | 
			
		||||
                "{}T{}00",
 | 
			
		||||
                event.day.replace('-', ""),
 | 
			
		||||
                event.planned_starting_time.replace(':', "")
 | 
			
		||||
            )));
 | 
			
		||||
            let tripdetails = event.trip_details(db).await;
 | 
			
		||||
            let mut name = String::new();
 | 
			
		||||
            if event.is_cancelled() {
 | 
			
		||||
                name.push_str("ABGESAGT");
 | 
			
		||||
                if let Some(notes) = &tripdetails.notes {
 | 
			
		||||
                    if !notes.is_empty() {
 | 
			
		||||
                        name.push_str(&format!(" (Grund: {notes})"))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                name.push_str("! :-( ");
 | 
			
		||||
            }
 | 
			
		||||
            name.push_str(&format!("{} ", event.name));
 | 
			
		||||
 | 
			
		||||
            if let Some(triptype) = tripdetails.triptype(db).await {
 | 
			
		||||
                name.push_str(&format!("• {} ", triptype.name))
 | 
			
		||||
            }
 | 
			
		||||
            vevent.push(Summary::new(name));
 | 
			
		||||
            calendar.add_event(vevent);
 | 
			
		||||
            calendar.add_event(event.get_vevent(db).await);
 | 
			
		||||
        }
 | 
			
		||||
        let mut buf = Vec::new();
 | 
			
		||||
        write!(&mut buf, "{}", calendar).unwrap();
 | 
			
		||||
        String::from_utf8(buf).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) async fn get_vevent(self, db: &SqlitePool) -> ics::Event {
 | 
			
		||||
        let mut vevent = ics::Event::new(format!("{}@rudernlinz.at", self.id), "19900101T180000");
 | 
			
		||||
        vevent.push(DtStart::new(format!(
 | 
			
		||||
            "{}T{}00",
 | 
			
		||||
            self.day.replace('-', ""),
 | 
			
		||||
            self.planned_starting_time.replace(':', "")
 | 
			
		||||
        )));
 | 
			
		||||
        let tripdetails = self.trip_details(db).await;
 | 
			
		||||
        let mut name = String::new();
 | 
			
		||||
        if self.is_cancelled() {
 | 
			
		||||
            name.push_str("ABGESAGT");
 | 
			
		||||
            if let Some(notes) = &tripdetails.notes {
 | 
			
		||||
                if !notes.is_empty() {
 | 
			
		||||
                    name.push_str(&format!(" (Grund: {notes})"))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            name.push_str("! :-( ");
 | 
			
		||||
        }
 | 
			
		||||
        name.push_str(&format!("{} ", self.name));
 | 
			
		||||
 | 
			
		||||
        if let Some(triptype) = tripdetails.triptype(db).await {
 | 
			
		||||
            name.push_str(&format!("• {} ", triptype.name))
 | 
			
		||||
        }
 | 
			
		||||
        vevent.push(Summary::new(name));
 | 
			
		||||
        vevent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn trip_details(&self, db: &SqlitePool) -> TripDetails {
 | 
			
		||||
        TripDetails::find_by_id(db, self.trip_details_id)
 | 
			
		||||
            .await
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								src/model/personal/cal.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/model/personal/cal.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
use std::io::Write;
 | 
			
		||||
 | 
			
		||||
use ics::ICalendar;
 | 
			
		||||
use sqlx::SqlitePool;
 | 
			
		||||
 | 
			
		||||
use crate::model::{event::Event, trip::Trip, user::User};
 | 
			
		||||
 | 
			
		||||
pub(crate) async fn get_personal_cal(db: &SqlitePool, user: &User) -> String {
 | 
			
		||||
    let mut calendar = ICalendar::new("2.0", "ics-rs");
 | 
			
		||||
 | 
			
		||||
    let events = Event::all_with_user(db, user).await;
 | 
			
		||||
    for event in events {
 | 
			
		||||
        calendar.add_event(event.get_vevent(db).await);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let trips = Trip::all_with_user(db, user).await;
 | 
			
		||||
    for trip in trips {
 | 
			
		||||
        calendar.add_event(trip.get_vevent(db).await);
 | 
			
		||||
    }
 | 
			
		||||
    let mut buf = Vec::new();
 | 
			
		||||
    write!(&mut buf, "{}", calendar).unwrap();
 | 
			
		||||
    String::from_utf8(buf).unwrap()
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ use sqlx::SqlitePool;
 | 
			
		||||
 | 
			
		||||
use super::{logbook::Logbook, stat::Stat, user::User};
 | 
			
		||||
 | 
			
		||||
pub(crate) mod cal;
 | 
			
		||||
pub(crate) mod equatorprice;
 | 
			
		||||
pub(crate) mod rowingbadge;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
use chrono::{Local, NaiveDate};
 | 
			
		||||
use ics::properties::{DtStart, Summary};
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
use sqlx::SqlitePool;
 | 
			
		||||
 | 
			
		||||
@@ -9,6 +10,7 @@ use super::{
 | 
			
		||||
    tripdetails::TripDetails,
 | 
			
		||||
    triptype::TripType,
 | 
			
		||||
    user::{CoxUser, User},
 | 
			
		||||
    usertrip::UserTrip,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Clone, Debug)]
 | 
			
		||||
@@ -123,6 +125,61 @@ WHERE trip_details.id=?
 | 
			
		||||
        .ok()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) async fn get_vevent(self, db: &SqlitePool) -> ics::Event {
 | 
			
		||||
        let mut vevent = ics::Event::new(format!("{}@rudernlinz.at", self.id), "19900101T180000");
 | 
			
		||||
        vevent.push(DtStart::new(format!(
 | 
			
		||||
            "{}T{}00",
 | 
			
		||||
            self.day.replace('-', ""),
 | 
			
		||||
            self.planned_starting_time.replace(':', "")
 | 
			
		||||
        )));
 | 
			
		||||
        let mut name = String::new();
 | 
			
		||||
        if self.is_cancelled() {
 | 
			
		||||
            name.push_str("ABGESAGT");
 | 
			
		||||
            if let Some(notes) = &self.notes {
 | 
			
		||||
                if !notes.is_empty() {
 | 
			
		||||
                    name.push_str(&format!(" (Grund: {notes})"))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            name.push_str("! :-( ");
 | 
			
		||||
        }
 | 
			
		||||
        name.push_str(&format!("Ruderausfahrt mit {} ", self.cox_name));
 | 
			
		||||
 | 
			
		||||
        vevent.push(Summary::new(name));
 | 
			
		||||
        vevent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn all(db: &SqlitePool) -> Vec<Self> {
 | 
			
		||||
        sqlx::query_as!(
 | 
			
		||||
            Self,
 | 
			
		||||
            "
 | 
			
		||||
SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, trip_details.notes, allow_guests, trip_type_id, always_show, is_locked
 | 
			
		||||
FROM trip 
 | 
			
		||||
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
 | 
			
		||||
INNER JOIN user ON trip.cox_id = user.id
 | 
			
		||||
",
 | 
			
		||||
        )
 | 
			
		||||
        .fetch_all(db)
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap() //TODO: fixme
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn all_with_user(db: &SqlitePool, user: &User) -> Vec<Self> {
 | 
			
		||||
        let mut ret = Vec::new();
 | 
			
		||||
        let trips = Self::all(db).await;
 | 
			
		||||
        for trip in trips {
 | 
			
		||||
            if let Some(trip_details_id) = trip.trip_details_id {
 | 
			
		||||
                if UserTrip::find_by_userid_and_trip_detail_id(db, user.id, trip_details_id)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .is_some()
 | 
			
		||||
                {
 | 
			
		||||
                    ret.push(trip);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ret
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
 | 
			
		||||
        sqlx::query_as!(
 | 
			
		||||
            Self,
 | 
			
		||||
@@ -370,6 +427,10 @@ WHERE day=?
 | 
			
		||||
        trips.retain(|e| e.trip.always_show);
 | 
			
		||||
        trips
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_cancelled(&self) -> bool {
 | 
			
		||||
        self.max_people == 0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
use rocket::{get, http::ContentType, routes, Route, State};
 | 
			
		||||
use sqlx::SqlitePool;
 | 
			
		||||
 | 
			
		||||
use crate::model::event::Event;
 | 
			
		||||
use crate::model::{event::Event, personal::cal::get_personal_cal, user::User};
 | 
			
		||||
 | 
			
		||||
#[get("/cal")]
 | 
			
		||||
async fn cal(db: &State<SqlitePool>) -> (ContentType, String) {
 | 
			
		||||
@@ -9,8 +9,14 @@ async fn cal(db: &State<SqlitePool>) -> (ContentType, String) {
 | 
			
		||||
    (ContentType::Calendar, Event::get_ics_feed(db).await)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[get("/cal/registered")]
 | 
			
		||||
async fn cal_registered(db: &State<SqlitePool>, user: User) -> (ContentType, String) {
 | 
			
		||||
    //TODO: add unit test once proper functionality is there
 | 
			
		||||
    (ContentType::Calendar, get_personal_cal(db, &user).await)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn routes() -> Vec<Route> {
 | 
			
		||||
    routes![cal]
 | 
			
		||||
    routes![cal, cal_registered]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -103,7 +103,7 @@
 | 
			
		||||
                <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
 | 
			
		||||
                     role="alert">
 | 
			
		||||
                    <h2 class="h2">
 | 
			
		||||
                        Deine Ruderkarriere
 | 
			
		||||
                        Dein Ruderleben
 | 
			
		||||
                        <span class="text-xl"
 | 
			
		||||
                              onclick="document.getElementById('call-for-action').showModal()">💡</span>
 | 
			
		||||
                    </h2>
 | 
			
		||||
@@ -213,6 +213,21 @@
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </details>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="py-3">
 | 
			
		||||
                            <p>
 | 
			
		||||
                                <details>
 | 
			
		||||
                                    <summary><span class="text-xl"> 📅 </span> Kalender</summary>
 | 
			
		||||
				    <p class="mt-3">
 | 
			
		||||
				    Du möchtest immer up-to-date mit den Events und Ausfahrten bleiben? Wir bieten 3 verschiedene Arten von Kalender an:</p>
 | 
			
		||||
				    <ol class="list-decimal ml-5 my-3">
 | 
			
		||||
					<li><strong>Alle Events und Ausfahrten</strong>, zu denen du dich angemeldet hast: <a class="underline" href="https://app.rudernlinz.at/cal/personal?my-secrect-key">https://app.rudernlinz.at/cal/personal?my-secrect-key</a></li>
 | 
			
		||||
					<li><strong>Allgemeiner Kalender</strong>, zB save-the-dates (Wanderfahrten, ...): <a href="https://rudernlinz.at/cal" class="underline">https://rudernlinz.at/cal</a></li>
 | 
			
		||||
					<li><strong>Alle Events</strong>: <a class="underline" href="https://app.rudernlinz.at/cal">https://app.rudernlinz.at/cal</a></li>
 | 
			
		||||
				    </ol>
 | 
			
		||||
				    Du kannst die Kalender einfach in deinen Kalender als "externen Kalender" synchronisieren. Die genauen Schritte hängen von deiner verwendeten Software ab.
 | 
			
		||||
                                </details>
 | 
			
		||||
                            </p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user