2023-04-04 15:16:21 +02:00
use rocket ::{
2023-04-05 19:24:02 +02:00
catch , catchers ,
2023-05-30 14:12:08 +02:00
fairing ::AdHoc ,
2023-10-24 12:36:14 +02:00
form ::Form ,
2023-04-05 19:24:02 +02:00
fs ::FileServer ,
2024-01-22 22:08:05 +01:00
get ,
http ::Cookie ,
post ,
2023-04-04 15:16:21 +02:00
request ::FlashMessage ,
response ::{ Flash , Redirect } ,
2024-01-22 22:08:05 +01:00
routes ,
time ::{ Duration , OffsetDateTime } ,
Build , FromForm , Request , Rocket , State ,
2023-04-04 15:16:21 +02:00
} ;
2024-01-10 14:08:15 +01:00
use rocket_dyn_templates ::Template ;
2023-05-30 14:12:08 +02:00
use serde ::Deserialize ;
2023-04-03 16:11:26 +02:00
use sqlx ::SqlitePool ;
2024-01-10 14:08:15 +01:00
use tera ::Context ;
2023-04-03 16:11:26 +02:00
2024-01-10 14:08:15 +01:00
use crate ::model ::user ::{ User , UserWithRoles } ;
2023-04-03 22:03:45 +02:00
2023-11-02 12:15:10 +01:00
pub ( crate ) mod admin ;
2023-04-03 16:11:26 +02:00
mod auth ;
2023-08-02 14:29:19 +02:00
mod boatdamage ;
2023-04-04 15:16:21 +02:00
mod cox ;
2023-11-02 12:15:10 +01:00
mod ergo ;
2023-07-23 12:17:57 +02:00
mod log ;
2023-05-24 15:36:38 +02:00
mod misc ;
2024-01-10 14:08:15 +01:00
mod planned ;
2023-07-24 20:56:46 +02:00
mod stat ;
2023-03-26 14:40:56 +02:00
2023-10-24 13:14:26 +02:00
#[ derive(FromForm, Debug) ]
2023-10-24 12:36:14 +02:00
struct LoginForm < ' r > {
name : & ' r str ,
password : & ' r str ,
}
2023-04-04 15:42:26 +02:00
#[ get( " / " ) ]
async fn index ( db : & State < SqlitePool > , user : User , flash : Option < FlashMessage < '_ > > ) -> Template {
2023-04-28 21:19:51 +02:00
let mut context = Context ::new ( ) ;
2023-04-04 15:16:21 +02:00
if let Some ( msg ) = flash {
context . insert ( " flash " , & msg . into_inner ( ) ) ;
}
2024-01-19 10:10:23 +01:00
2023-12-23 21:27:52 +01:00
context . insert ( " loggedin_user " , & UserWithRoles ::from_user ( user , db ) . await ) ;
2023-04-04 15:16:21 +02:00
Template ::render ( " index " , context . into_json ( ) )
}
2024-01-10 14:08:15 +01:00
#[ post( " / " , data = " <login> " ) ]
async fn wikiauth ( db : & State < SqlitePool > , login : Form < LoginForm < '_ > > ) -> String {
match User ::login ( db , login . name , login . password ) . await {
Ok ( _ ) = > " SUCC " . into ( ) ,
Err ( _ ) = > " FAIL " . into ( ) ,
2023-08-09 11:54:18 +02:00
}
2023-03-26 14:40:56 +02:00
}
2024-01-10 14:08:15 +01:00
#[ catch(401) ] //Unauthorized
2024-01-22 22:08:05 +01:00
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 ) ;
2023-04-03 22:03:45 +02:00
Redirect ::to ( " /auth " )
}
2024-01-10 14:08:15 +01:00
#[ catch(403) ] //forbidden
fn forbidden_error ( ) -> Flash < Redirect > {
Flash ::error ( Redirect ::to ( " / " ) , " Keine Berechtigung für diese Aktion. Wenn du der Meinung bist, dass du das machen darfst, melde dich bitte bei it@rudernlinz.at. " )
}
2023-05-30 14:12:08 +02:00
#[ derive(Deserialize) ]
#[ serde(crate = " rocket::serde " ) ]
pub struct Config {
rss_key : String ,
2024-01-01 15:50:06 +01:00
smtp_pw : String ,
2023-05-30 14:12:08 +02:00
}
2023-07-16 18:33:17 +02:00
pub fn config ( rocket : Rocket < Build > ) -> Rocket < Build > {
rocket
2024-01-10 14:08:15 +01:00
. mount ( " / " , routes! [ index ] )
2023-04-03 16:11:26 +02:00
. mount ( " /auth " , auth ::routes ( ) )
2023-10-24 12:36:14 +02:00
. mount ( " /wikiauth " , routes! [ wikiauth ] )
2023-07-23 12:17:57 +02:00
. mount ( " /log " , log ::routes ( ) )
2024-01-10 14:08:15 +01:00
. mount ( " /planned " , planned ::routes ( ) )
2023-11-02 12:15:10 +01:00
. mount ( " /ergo " , ergo ::routes ( ) )
2023-07-24 20:56:46 +02:00
. mount ( " /stat " , stat ::routes ( ) )
2023-08-02 14:29:19 +02:00
. mount ( " /boatdamage " , boatdamage ::routes ( ) )
2023-04-04 15:16:21 +02:00
. mount ( " /cox " , cox ::routes ( ) )
2023-04-04 10:44:14 +02:00
. mount ( " /admin " , admin ::routes ( ) )
2023-05-24 15:36:38 +02:00
. mount ( " / " , misc ::routes ( ) )
2023-04-10 15:15:16 +02:00
. mount ( " /public " , FileServer ::from ( " static/ " ) )
2024-01-10 14:08:15 +01:00
. register ( " / " , catchers! [ unauthorized_error , forbidden_error ] )
2023-03-26 16:58:45 +02:00
. attach ( Template ::fairing ( ) )
2023-05-30 14:12:08 +02:00
. attach ( AdHoc ::config ::< Config > ( ) )
2023-03-26 14:40:56 +02:00
}
2023-07-22 12:24:29 +02:00
#[ cfg(test) ]
mod test {
use rocket ::{
http ::{ ContentType , Status } ,
local ::asynchronous ::Client ,
} ;
use sqlx ::SqlitePool ;
use crate ::testdb ;
#[ sqlx::test ]
fn test_index ( ) {
let db = testdb! ( ) ;
let rocket = rocket ::build ( ) . manage ( db . clone ( ) ) ;
let rocket = crate ::tera ::config ( rocket ) ;
let client = Client ::tracked ( rocket ) . await . unwrap ( ) ;
let login = client
. post ( " /auth " )
. header ( ContentType ::Form ) // Set the content type to form
. body ( " name=cox&password=cox " ) ; // Add the form data to the request body;
login . dispatch ( ) . await ;
let req = client . get ( " / " ) ;
let response = req . dispatch ( ) . await ;
assert_eq! ( response . status ( ) , Status ::Ok ) ;
2024-01-10 14:08:15 +01:00
assert! ( response
. into_string ( )
. await
. unwrap ( )
. contains ( " Ruderassistent " ) ) ;
2023-07-22 12:24:29 +02:00
}
#[ sqlx::test ]
fn test_without_login ( ) {
let db = testdb! ( ) ;
let rocket = rocket ::build ( ) . manage ( db . clone ( ) ) ;
let rocket = crate ::tera ::config ( rocket ) ;
let client = Client ::tracked ( rocket ) . await . unwrap ( ) ;
let req = client . get ( " / " ) ;
let response = req . dispatch ( ) . await ;
assert_eq! ( response . status ( ) , Status ::SeeOther ) ;
assert_eq! ( response . headers ( ) . get ( " Location " ) . next ( ) , Some ( " /auth " ) ) ;
}
2023-07-31 21:07:01 +02:00
#[ sqlx::test ]
fn test_public ( ) {
let db = testdb! ( ) ;
let rocket = rocket ::build ( ) . manage ( db . clone ( ) ) ;
let rocket = crate ::tera ::config ( rocket ) ;
let client = Client ::tracked ( rocket ) . await . unwrap ( ) ;
let req = client . get ( " /public/main.css " ) ;
let response = req . dispatch ( ) . await ;
assert_eq! ( response . status ( ) , Status ::Ok ) ;
let req = client . get ( " /public/main.js " ) ;
let response = req . dispatch ( ) . await ;
assert_eq! ( response . status ( ) , Status ::Ok ) ;
}
2023-07-22 12:24:29 +02:00
}