forked from Ruderverein-Donau-Linz/rowt
		
	Merge pull request 'kassier-role' (#685) from kassier-role into main
Reviewed-on: Ruderverein-Donau-Linz/rowt#685
This commit is contained in:
		@@ -9,6 +9,7 @@ INSERT INTO "role" (name) VALUES ('paid');
 | 
			
		||||
INSERT INTO "role" (name) VALUES ('Vorstand');
 | 
			
		||||
INSERT INTO "role" (name) VALUES ('Bootsführer');
 | 
			
		||||
INSERT INTO "role" (name) VALUES ('schnupperant');
 | 
			
		||||
INSERT INTO "role" (name) VALUES ('kassier');
 | 
			
		||||
INSERT INTO "user" (name, pw) VALUES('admin', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$4P4NCw4Ukhv80/eQYTsarHhnw61JuL1KMx/L9dm82YM');
 | 
			
		||||
INSERT INTO "user_role" (user_id, role_id) VALUES(1,1);
 | 
			
		||||
INSERT INTO "user_role" (user_id, role_id) VALUES(1,2);
 | 
			
		||||
 
 | 
			
		||||
@@ -918,266 +918,82 @@ impl<'r> FromRequest<'r> for User {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TechUser {
 | 
			
		||||
    pub(crate) user: User,
 | 
			
		||||
}
 | 
			
		||||
/// Creates a struct named $name. Allows to be created from a user, if one of the specified $roles are active for the user.
 | 
			
		||||
macro_rules! special_user {
 | 
			
		||||
    ($name:ident, $($role:tt)*) => {
 | 
			
		||||
        #[derive(Debug)]
 | 
			
		||||
        pub struct $name {
 | 
			
		||||
            pub(crate) user: User,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
impl Deref for TechUser {
 | 
			
		||||
    type Target = User;
 | 
			
		||||
        impl Deref for $name {
 | 
			
		||||
            type Target = User;
 | 
			
		||||
            fn deref(&self) -> &Self::Target {
 | 
			
		||||
                &self.user
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.user
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
        impl $name {
 | 
			
		||||
            pub fn into_inner(self) -> User {
 | 
			
		||||
                self.user
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for TechUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "tech").await {
 | 
			
		||||
                    Outcome::Success(TechUser { user })
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Error((Status::Forbidden, LoginError::NotACox))
 | 
			
		||||
        #[async_trait]
 | 
			
		||||
        impl<'r> FromRequest<'r> for $name {
 | 
			
		||||
            type Error = LoginError;
 | 
			
		||||
            async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
                let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
                match User::from_request(req).await {
 | 
			
		||||
                    Outcome::Success(user) => {
 | 
			
		||||
                        if special_user!(@check_roles user, db, $($role)*) {
 | 
			
		||||
                            Outcome::Success($name { user })
 | 
			
		||||
                        } else {
 | 
			
		||||
                            Outcome::Forward(Status::Forbidden)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
                    Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct CoxUser {
 | 
			
		||||
    pub(crate) user: User,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for CoxUser {
 | 
			
		||||
    type Target = User;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.user
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CoxUser {
 | 
			
		||||
    pub async fn new(db: &SqlitePool, user: User) -> Option<Self> {
 | 
			
		||||
        if user.has_role(db, "cox").await {
 | 
			
		||||
            Some(CoxUser { user })
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for CoxUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "cox").await {
 | 
			
		||||
                    Outcome::Success(CoxUser { user })
 | 
			
		||||
        impl $name {
 | 
			
		||||
            pub async fn new(db: &SqlitePool, user: User) -> Option<Self> {
 | 
			
		||||
                if special_user!(@check_roles user, db, $($role)*) {
 | 
			
		||||
                    Some($name { user })
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Error((Status::Forbidden, LoginError::NotACox))
 | 
			
		||||
                    None
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct AdminUser {
 | 
			
		||||
    pub(crate) user: User,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for AdminUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "admin").await {
 | 
			
		||||
                    Outcome::Success(AdminUser { user })
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Forward(Status::Forbidden)
 | 
			
		||||
    };
 | 
			
		||||
    (@check_roles $user:ident, $db:ident, $(+$role:expr),* $(,-$neg_role:expr)*) => {
 | 
			
		||||
        {
 | 
			
		||||
            let mut has_positive_role = false;
 | 
			
		||||
            $(
 | 
			
		||||
                if $user.has_role($db, $role).await {
 | 
			
		||||
                    has_positive_role = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
            )*
 | 
			
		||||
            has_positive_role
 | 
			
		||||
            $(
 | 
			
		||||
                && !$user.has_role($db, $neg_role).await
 | 
			
		||||
            )*
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct AllowedForPlannedTripsUser(pub(crate) User);
 | 
			
		||||
special_user!(TechUser, +"tech");
 | 
			
		||||
special_user!(CoxUser, +"cox");
 | 
			
		||||
special_user!(AdminUser, +"admin");
 | 
			
		||||
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch");
 | 
			
		||||
special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied");
 | 
			
		||||
special_user!(SchnupperBetreuerUser, +"schnupper-betreuer");
 | 
			
		||||
special_user!(VorstandUser, +"Vorstand");
 | 
			
		||||
special_user!(EventUser, +"manage_events");
 | 
			
		||||
special_user!(AllowedToEditPaymentStatusUser, +"kassier", +"admin");
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for AllowedForPlannedTripsUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "Donau Linz").await | user.has_role(db, "scheckbuch").await {
 | 
			
		||||
                    Outcome::Success(AllowedForPlannedTripsUser(user))
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Error((Status::Forbidden, LoginError::NotACox))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<AllowedForPlannedTripsUser> for User {
 | 
			
		||||
    fn from(val: AllowedForPlannedTripsUser) -> Self {
 | 
			
		||||
        val.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct DonauLinzUser(pub(crate) User);
 | 
			
		||||
 | 
			
		||||
impl From<DonauLinzUser> for User {
 | 
			
		||||
    fn from(val: DonauLinzUser) -> Self {
 | 
			
		||||
        val.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for DonauLinzUser {
 | 
			
		||||
    type Target = User;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for DonauLinzUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "Donau Linz").await
 | 
			
		||||
                    && !user.has_role(db, "Unterstützend").await
 | 
			
		||||
                    && !user.has_role(db, "Förderndes Mitglied").await
 | 
			
		||||
                {
 | 
			
		||||
                    Outcome::Success(DonauLinzUser(user))
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Error((Status::Forbidden, LoginError::NotACox))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct SchnupperBetreuerUser(pub(crate) User);
 | 
			
		||||
 | 
			
		||||
impl From<SchnupperBetreuerUser> for User {
 | 
			
		||||
    fn from(val: SchnupperBetreuerUser) -> Self {
 | 
			
		||||
        val.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for SchnupperBetreuerUser {
 | 
			
		||||
    type Target = User;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for SchnupperBetreuerUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "schnupper-betreuer").await {
 | 
			
		||||
                    Outcome::Success(SchnupperBetreuerUser(user))
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Forward(Status::Forbidden)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct VorstandUser(pub(crate) User);
 | 
			
		||||
 | 
			
		||||
impl From<VorstandUser> for User {
 | 
			
		||||
    fn from(val: VorstandUser) -> Self {
 | 
			
		||||
        val.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for VorstandUser {
 | 
			
		||||
    type Target = User;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for VorstandUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "Vorstand").await {
 | 
			
		||||
                    Outcome::Success(VorstandUser(user))
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Forward(Status::Forbidden)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct EventUser(pub(crate) User);
 | 
			
		||||
 | 
			
		||||
impl From<EventUser> for User {
 | 
			
		||||
    fn from(val: EventUser) -> Self {
 | 
			
		||||
        val.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for EventUser {
 | 
			
		||||
    type Target = User;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.0
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
 | 
			
		||||
pub struct UserWithRolesAndMembershipPdf {
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
@@ -1221,25 +1037,6 @@ impl UserWithMembershipPdf {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for EventUser {
 | 
			
		||||
    type Error = LoginError;
 | 
			
		||||
 | 
			
		||||
    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
 | 
			
		||||
        let db = req.rocket().state::<SqlitePool>().unwrap();
 | 
			
		||||
        match User::from_request(req).await {
 | 
			
		||||
            Outcome::Success(user) => {
 | 
			
		||||
                if user.has_role(db, "manage_events").await {
 | 
			
		||||
                    Outcome::Success(EventUser(user))
 | 
			
		||||
                } else {
 | 
			
		||||
                    Outcome::Error((Status::Forbidden, LoginError::NotACox))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Outcome::Error(f) => Outcome::Error(f),
 | 
			
		||||
            Outcome::Forward(f) => Outcome::Forward(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use std::collections::HashMap;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ async fn index(
 | 
			
		||||
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(admin.0, db).await,
 | 
			
		||||
        &UserWithDetails::from_user(admin.user, db).await,
 | 
			
		||||
    );
 | 
			
		||||
    context.insert("roles", &roles);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ async fn index(
 | 
			
		||||
    }
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.0, db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.user, db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let users: Vec<User> = User::all(db)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ async fn index(
 | 
			
		||||
    context.insert("schnupperanten", &users);
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.user, db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("admin/schnupper/index", context.into_json())
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,8 @@ use crate::{
 | 
			
		||||
        logbook::Logbook,
 | 
			
		||||
        role::Role,
 | 
			
		||||
        user::{
 | 
			
		||||
            AdminUser, User, UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf,
 | 
			
		||||
            VorstandUser,
 | 
			
		||||
            AdminUser, AllowedToEditPaymentStatusUser, User, UserWithDetails,
 | 
			
		||||
            UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    tera::Config,
 | 
			
		||||
@@ -54,7 +54,7 @@ async fn index(
 | 
			
		||||
        .map(|u| async move { UserWithRolesAndMembershipPdf::from_user(db, u).await })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    let user: User = user.into();
 | 
			
		||||
    let user: User = user.into_inner();
 | 
			
		||||
    let allowed_to_edit = user.has_role(db, "admin").await;
 | 
			
		||||
 | 
			
		||||
    let users: Vec<UserWithRolesAndMembershipPdf> = join_all(user_futures).await;
 | 
			
		||||
@@ -110,7 +110,7 @@ async fn index_admin(
 | 
			
		||||
#[get("/user/fees")]
 | 
			
		||||
async fn fees(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    admin: VorstandUser,
 | 
			
		||||
    user: AllowedToEditPaymentStatusUser,
 | 
			
		||||
    flash: Option<FlashMessage<'_>>,
 | 
			
		||||
) -> Template {
 | 
			
		||||
    let mut context = Context::new();
 | 
			
		||||
@@ -130,7 +130,7 @@ async fn fees(
 | 
			
		||||
    }
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(admin.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("admin/user/fees", context.into_json())
 | 
			
		||||
@@ -161,7 +161,7 @@ async fn scheckbuch(
 | 
			
		||||
    }
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("admin/user/scheckbuch", context.into_json())
 | 
			
		||||
@@ -170,7 +170,7 @@ async fn scheckbuch(
 | 
			
		||||
#[get("/user/fees/paid?<user_ids>")]
 | 
			
		||||
async fn fees_paid(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    admin: AdminUser,
 | 
			
		||||
    calling_user: AllowedToEditPaymentStatusUser,
 | 
			
		||||
    user_ids: Vec<i32>,
 | 
			
		||||
    referer: Referer,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
@@ -181,7 +181,10 @@ async fn fees_paid(
 | 
			
		||||
        if user.has_role(db, "paid").await {
 | 
			
		||||
            Log::create(
 | 
			
		||||
                db,
 | 
			
		||||
                format!("{} set fees NOT paid for '{}'", admin.user.name, user.name),
 | 
			
		||||
                format!(
 | 
			
		||||
                    "{} set fees NOT paid for '{}'",
 | 
			
		||||
                    calling_user.user.name, user.name
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
            .await;
 | 
			
		||||
            user.remove_role(db, &Role::find_by_name(db, "paid").await.unwrap())
 | 
			
		||||
@@ -189,7 +192,10 @@ async fn fees_paid(
 | 
			
		||||
        } else {
 | 
			
		||||
            Log::create(
 | 
			
		||||
                db,
 | 
			
		||||
                format!("{} set fees paid for '{}'", admin.user.name, user.name),
 | 
			
		||||
                format!(
 | 
			
		||||
                    "{} set fees paid for '{}'",
 | 
			
		||||
                    calling_user.user.name, user.name
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
            .await;
 | 
			
		||||
            user.add_role(db, &Role::find_by_name(db, "paid").await.unwrap())
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ async fn index(
 | 
			
		||||
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(admin.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(admin.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("board/boathouse", context.into_json())
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ async fn index(
 | 
			
		||||
    context.insert("boats", &boats);
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("boatdamages", context.into_json())
 | 
			
		||||
@@ -78,7 +78,7 @@ async fn create<'r>(
 | 
			
		||||
    data: Form<FormBoatDamageToAdd<'r>>,
 | 
			
		||||
    user: DonauLinzUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let user: User = user.into();
 | 
			
		||||
    let user: User = user.into_inner();
 | 
			
		||||
    let boatdamage_to_add = BoatDamageToAdd {
 | 
			
		||||
        boat_id: data.boat_id,
 | 
			
		||||
        desc: data.desc,
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,7 @@ async fn index(
 | 
			
		||||
    context.insert("user", &User::all(db).await);
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("boatreservations", context.into_json())
 | 
			
		||||
@@ -97,7 +97,7 @@ async fn create<'r>(
 | 
			
		||||
    data: Form<FormBoatReservationToAdd<'r>>,
 | 
			
		||||
    user: DonauLinzUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let user_applicant: User = user.into();
 | 
			
		||||
    let user_applicant: User = user.into_inner();
 | 
			
		||||
    let boat = Boat::find_by_id(db, data.boat_id as i32).await.unwrap();
 | 
			
		||||
    let boatreservation_to_add = BoatReservationToAdd {
 | 
			
		||||
        boat: &boat,
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ async fn index(
 | 
			
		||||
    context.insert("logtypes", &logtypes);
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
    context.insert("on_water", &on_water);
 | 
			
		||||
    context.insert("distances", &distances);
 | 
			
		||||
@@ -110,7 +110,7 @@ async fn show(db: &State<SqlitePool>, user: DonauLinzUser) -> Template {
 | 
			
		||||
 | 
			
		||||
    Template::render(
 | 
			
		||||
        "log.completed",
 | 
			
		||||
        context!(logs, loggedin_user: &UserWithDetails::from_user(user.into(), db).await),
 | 
			
		||||
        context!(logs, loggedin_user: &UserWithDetails::from_user(user.into_inner(), db).await),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -287,7 +287,8 @@ async fn create_kiosk(
 | 
			
		||||
    )
 | 
			
		||||
    .await;
 | 
			
		||||
 | 
			
		||||
    create_logbook(db, data, &DonauLinzUser(creator)).await //TODO: fixme
 | 
			
		||||
    create_logbook(db, data, &DonauLinzUser::new(db, creator).await.unwrap()).await
 | 
			
		||||
    //TODO: fixme
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[post("/update", data = "<data>")]
 | 
			
		||||
@@ -302,7 +303,7 @@ async fn update(
 | 
			
		||||
        return Flash::error(Redirect::to("/log"), &format!("Logbucheintrag kann nicht bearbeitet werden, da es einen Logbuch-Eintrag mit ID={} nicht gibt", data.id));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    match logbook.update(db, data.clone(), &user.0).await {
 | 
			
		||||
    match logbook.update(db, data.clone(), &user.user).await {
 | 
			
		||||
        Ok(()) => {
 | 
			
		||||
            Log::create(
 | 
			
		||||
                db,
 | 
			
		||||
@@ -372,11 +373,14 @@ async fn home_kiosk(
 | 
			
		||||
        db,
 | 
			
		||||
        data,
 | 
			
		||||
        logbook_id,
 | 
			
		||||
        &DonauLinzUser(
 | 
			
		||||
        &DonauLinzUser::new(
 | 
			
		||||
            db,
 | 
			
		||||
            User::find_by_id(db, logbook.shipmaster as i32)
 | 
			
		||||
                .await
 | 
			
		||||
                .unwrap(),
 | 
			
		||||
        ), //TODO: fixme
 | 
			
		||||
        )
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap(),
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ async fn index(
 | 
			
		||||
    user: AllowedForPlannedTripsUser,
 | 
			
		||||
    flash: Option<FlashMessage<'_>>,
 | 
			
		||||
) -> Template {
 | 
			
		||||
    let user: User = user.into();
 | 
			
		||||
    let user: User = user.into_inner();
 | 
			
		||||
 | 
			
		||||
    let mut context = Context::new();
 | 
			
		||||
 | 
			
		||||
@@ -50,7 +50,7 @@ async fn join(
 | 
			
		||||
    user: AllowedForPlannedTripsUser,
 | 
			
		||||
    user_note: Option<String>,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let user: User = user.into();
 | 
			
		||||
    let user: User = user.into_inner();
 | 
			
		||||
 | 
			
		||||
    let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else {
 | 
			
		||||
        return Flash::error(Redirect::to("/"), "Trip_details do not exist.");
 | 
			
		||||
@@ -113,7 +113,7 @@ async fn remove_guest(
 | 
			
		||||
    user: AllowedForPlannedTripsUser,
 | 
			
		||||
    name: String,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let user: User = user.into();
 | 
			
		||||
    let user: User = user.into_inner();
 | 
			
		||||
 | 
			
		||||
    let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else {
 | 
			
		||||
        return Flash::error(Redirect::to("/planned"), "TripDetailsId does not exist");
 | 
			
		||||
@@ -160,7 +160,7 @@ async fn remove(
 | 
			
		||||
    trip_details_id: i64,
 | 
			
		||||
    user: AllowedForPlannedTripsUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let user: User = user.into();
 | 
			
		||||
    let user: User = user.into_inner();
 | 
			
		||||
 | 
			
		||||
    let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else {
 | 
			
		||||
        return Flash::error(Redirect::to("/planned"), "TripDetailsId does not exist");
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ async fn index_boat(db: &State<SqlitePool>, user: DonauLinzUser) -> Template {
 | 
			
		||||
 | 
			
		||||
    Template::render(
 | 
			
		||||
        "stat.boats",
 | 
			
		||||
        context!(loggedin_user: &UserWithDetails::from_user(user.into(), db).await, stat, kiosk),
 | 
			
		||||
        context!(loggedin_user: &UserWithDetails::from_user(user.into_inner(), db).await, stat, kiosk),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -38,7 +38,7 @@ async fn index(db: &State<SqlitePool>, user: DonauLinzUser, year: Option<i32>) -
 | 
			
		||||
 | 
			
		||||
    Template::render(
 | 
			
		||||
        "stat.people",
 | 
			
		||||
        context!(loggedin_user: &UserWithDetails::from_user(user.into(), db).await, stat, personal, kiosk, guest_km, club_km),
 | 
			
		||||
        context!(loggedin_user: &UserWithDetails::from_user(user.into_inner(), db).await, stat, personal, kiosk, guest_km, club_km),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ async fn index(
 | 
			
		||||
    context.insert("user", &User::all(db).await);
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithDetails::from_user(user.into(), db).await,
 | 
			
		||||
        &UserWithDetails::from_user(user.into_inner(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("trailerreservations", context.into_json())
 | 
			
		||||
@@ -81,7 +81,7 @@ async fn create<'r>(
 | 
			
		||||
    data: Form<FormTrailerReservationToAdd<'r>>,
 | 
			
		||||
    user: DonauLinzUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let user_applicant: User = user.into();
 | 
			
		||||
    let user_applicant: User = user.into_inner();
 | 
			
		||||
    let trailer = Trailer::find_by_id(db, data.trailer_id as i32)
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
                                {% if not loop.last %}+{% endif %}
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        {% if "admin" in loggedin_user.roles %}
 | 
			
		||||
                        {% if "admin" in loggedin_user.roles or "kassier" in loggedin_user.roles %}
 | 
			
		||||
                            <a href="/admin/user/fees/paid?{{ fee.user_ids }}">Zahlungsstatus ändern</a>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
                                <li>{{ log::show_old(log=trip, state="completed", only_ones=false, index=loop.index) }}</li>
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        {% if "admin" in loggedin_user.roles %}
 | 
			
		||||
                        {% if "admin" in loggedin_user.roles  or "kassier" in loggedin_user.roles %}
 | 
			
		||||
                            <a href="/admin/user/fees/paid?user_ids[]={{ user.id }}">Zahlungsstatus ändern</a>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user