gourami

[UNMAINTAINED] Activitypub server in Rust
Log | Files | Refs | README | LICENSE

commit bbb531dbd354d0b8099c1093ce5eac2bcf6b13b3
parent cd5095f0f1fc64d9b73aae3974f82a8be23f81f1
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sun, 19 Apr 2020 14:01:24 -0500

Add additional pages

Diffstat:
M.gitignore | 1+
Msrc/db/user.rs | 10+++++-----
Msrc/lib.rs | 121++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/session.rs | 2+-
Atemplates/error.html | 5+++++
Atemplates/note.html | 7+++++++
Atemplates/server_info.html | 4++++
7 files changed, 115 insertions(+), 35 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ /target test_env sample.db +warp-diesel-ructe-sample/ diff --git a/src/db/user.rs b/src/db/user.rs @@ -13,6 +13,7 @@ pub struct User { pub email: String, pub bio: String, pub created_time: String, + pub password: String, // is this OK? hashed } // TODO -- default "anonymous" user @@ -24,19 +25,18 @@ impl User { pass: &str, ) -> Option<Self> { use crate::db::schema::users::dsl::*; - let (user, hash) = match users + let user = match users .filter(username.eq(user)) - .select(((id, username, email, created_time, bio), password)) - .first::<(User, String)>(conn) + .first::<User>(conn) { - Ok((user, hash)) => (user, hash), + Ok(user) => user, Err(e) => { error!("Failed to load hash for {:?}: {:?}", user, e); return None; } }; - match bcrypt::verify(&pass, &hash) { + match bcrypt::verify(&pass, &user.password) { Ok(true) => Some(user), Ok(false) => None, Err(e) => { diff --git a/src/lib.rs b/src/lib.rs @@ -47,16 +47,6 @@ lazy_static! { // return *POOL.get().unwrap(); -#[derive(Template)] -#[template(path = "user.html")] -struct UserTemplate<'a>{ - global: Global<'a>, - page: &'a str, - notes: Vec<Note>, - user: &'a User -} - - // TODO split into separate templates. not sure how #[derive(Template)] #[template(path = "timeline.html")] @@ -249,23 +239,85 @@ fn render_timeline(session: Option<Session>) -> impl Reply { }) } -// fn do_logout(mut session: Session) -> Result<impl Reply, Rejection> { -// session.clear(); -// Response::builder() -// .status(StatusCode::FOUND) -// .header(header::LOCATION, "/") -// .header( -// header::SET_COOKIE, -// "EXAUTH=; Max-Age=0; SameSite=Strict; HttpOpnly", -// ) -// .body(b"".to_vec()) -// .map_err(custom) -// } - -fn logout() { + +#[derive(Template)] +#[template(path = "server_info.html")] +struct ServerInfoTemplate<'a> { + global: Global<'a>, + page: &'a str, +} + +#[derive(Template)] +#[template(path = "error.html")] +struct ErrorTemplate<'a> { + global: Global<'a>, + error_message: &'a str +} + +#[derive(Template)] +#[template(path = "user.html")] +struct UserTemplate<'a>{ + global: Global<'a>, + page: &'a str, + notes: Vec<Note>, + user: User +} + +#[derive(Template)] +#[template(path = "note.html")] +struct NoteTemplate<'a> { + global: Global<'a>, + page: &'a str, + note: Note, + // thread +} + +fn server_info_page(session: Option<Session>) -> impl Reply { + let global = Global::from_session(session); + render_template(&ServerInfoTemplate{global: global, page: "server"}) +} + +fn note_page(session: Option<Session>, note_id: i32) -> impl Reply { + let global = Global::from_session(session); + use db::schema::notes::dsl::*; + let conn = &POOL.get().unwrap(); + let note: Option<Note> = notes + .filter(id.eq(note_id)) + .first::<Note>(conn) + .ok(); + if let Some(n) = note { + render_template(&NoteTemplate{global: global, note: n.clone(), page: &n.id.to_string()}) + } + else { + render_template(&ErrorTemplate{global: global, error_message: "Note not found"}) + } + // TODO -- fetch replies } -// ActivityPub inbox -fn inbox() { + +fn user_page(session: Option<Session>, user_name: String) -> impl Reply { + let global = Global::from_session(session); + use db::schema::notes::dsl::*; + use db::schema::users::dsl::*; + let conn = &POOL.get().unwrap(); + let user: Option<User> = users + .filter(username.eq(user_name)) + .first::<User>(conn) + .ok(); + if let Some(u) = user { + let results = notes + .filter(creator_id.eq(u.id)) + .load::<Note>(conn) + .expect("Error loading posts"); + render_template(&UserTemplate{ + global: global, + page: &u.username, + user: u.clone(), // TODO stop cloning + notes: results + }) + } + else { + render_template(&ErrorTemplate{global: global, error_message: "User not found"}) + } } pub async fn run_server() { @@ -279,6 +331,18 @@ pub async fn run_server() { .and(session_filter()) .map(render_timeline); + let user_page = session_filter() + .and(path!("user" / String)) + .map(user_page); + + let note_page = session_filter() + .and(path!("note" / i32)) + .map(note_page); + + let server_info_page = session_filter() + .and(path("server_info")) + .map(server_info_page); + // auth functions let register_page = path("register") .map(|| register_page()); @@ -301,8 +365,7 @@ pub async fn run_server() { .map(new_note); let delete_note = session_filter() - .and(warp::path::param::<i32>()) - .and(warp::path("delete")) + .and(path!(i32 / "delete")) .map(delete_note); @@ -316,7 +379,7 @@ pub async fn run_server() { // TODO secure against xss // used for api based authentication // let api_filter = session::create_session_filter(&POOL.get()); - let html_renders = home.or(login_page).or(register_page); + let html_renders = home.or(login_page).or(register_page).or(user_page).or(note_page).or(server_info_page); let forms = login_page.or(do_register).or(do_login).or(create_note).or(delete_note); // let api // catch all for any other paths diff --git a/src/session.rs b/src/session.rs @@ -51,7 +51,7 @@ impl Session { use db::schema::users::dsl as u; let result = u::users .inner_join(s::sessions) - .select((s::id, (u::id, u::username, u::email, u::created_time, u::bio))) // TODO figure out how to not select pw + .select((s::id, (u::id, u::username, u::email, u::created_time, u::bio, u::password))) // TODO figure out how to not select pw .filter(s::cookie.eq(sessionkey)) .first::<(i32, User)>(&POOL.get().unwrap()) .ok(); diff --git a/templates/error.html b/templates/error.html @@ -0,0 +1,5 @@ +{% block content %} +<div class="container"> + {{ error_message }} +</div> +{% endblock %} diff --git a/templates/note.html b/templates/note.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} +<div class="container"> + {{ note.id }} +</div> +{% endblock %} diff --git a/templates/server_info.html b/templates/server_info.html @@ -0,0 +1,4 @@ +{% extends "base.html" %} + +{% block content %} +{% endblock %}