gourami

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

commit cbbe0c4c1e2414ff3a59e127902b51f4cad15702
parent 829bb64acc465268ab45bdab90f5e857d7881c0d
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Fri, 17 Apr 2020 12:49:46 -0500

Simple post to timeline

Diffstat:
MCargo.lock | 3+++
MCargo.toml | 4++++
Mmigrations/2020-04-13-014917_initialize/up.sql | 7++++---
Msrc/db/status.rs | 8+++++---
Msrc/main.rs | 38+++++++++++++++++++++++++++++++-------
Mtemplates/timeline.html | 2+-
6 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -481,8 +481,11 @@ dependencies = [ "chrono", "diesel", "env_logger", + "lazy_static", "log 0.4.8", "reqwest", + "serde", + "serde_json", "tokio", "warp", ] diff --git a/Cargo.toml b/Cargo.toml @@ -14,5 +14,9 @@ warp = "0.2" reqwest = "0.10" activitystreams = "0.4.0" chrono = "*" +lazy_static = "1.4.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + [dev-dependencies] diff --git a/migrations/2020-04-13-014917_initialize/up.sql b/migrations/2020-04-13-014917_initialize/up.sql @@ -1,7 +1,7 @@ -- Your SQL goes here CREATE TABLE user ( -id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, username VARCHAR(255), email VARCHAR(255), created_at TEXT, @@ -9,8 +9,9 @@ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, public_key TEXT ); -CREATE TABLE notification ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT +CREATE TABLE activity ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + json_text TEXT ); -- media_attachments diff --git a/src/db/status.rs b/src/db/status.rs @@ -5,10 +5,11 @@ use diesel::deserialize::{Queryable}; use super::schema::note; use super::schema::note::dsl::*; use diesel::prelude::*; +use serde::{Deserialize, Serialize}; // Statuses are note activitystream object -#[derive(Queryable, Clone)] +#[derive(Queryable, Clone, Deserialize, Serialize)] pub struct Note { pub id: i32, pub creator_id: i32, @@ -30,9 +31,10 @@ impl Note { #[derive(Insertable, Clone)] #[table_name = "note"] pub struct NoteInput { - pub id: i32, //unsigned? + //pub id: i32, //unsigned? pub creator_id: i32, pub parent_id: Option<i32>, - pub content: String, + pub content: String, // can we make this a slice? + pub published: String, // pub published: chrono::NaiveDateTime, } diff --git a/src/main.rs b/src/main.rs @@ -6,14 +6,21 @@ use warp::Filter; use askama::Template; use warp::http::{self, header, StatusCode}; use warp::hyper::Body; -use warp::reply::Response; +use warp::reply::{Response, Reply}; use env_logger; -use db::status::Note; +use db::status::{NoteInput, Note}; use diesel::prelude::*; use diesel::sqlite::SqliteConnection; +use diesel::insert_into; +use serde::{Deserialize, Serialize}; mod db; +fn establish_connection() -> SqliteConnection { + let url = ::std::env::var("DATABASE_URL").unwrap(); + let conn = SqliteConnection::establish(&url).unwrap(); + conn +} // TODO split into separate templates. not sure how #[derive(Template)] #[template(path = "timeline.html")] @@ -46,15 +53,32 @@ pub fn render_template<T: askama::Template>(t: &T) -> Response { .unwrap() } -fn new_note() { +#[derive(Deserialize)] +struct NewNoteRequest { + note_input: String, // has to be String +} + +fn new_note(req: &NewNoteRequest) -> impl Reply { + use db::schema::note::dsl::*; // create activitypub activity object // TODO -- micropub? + let conn = establish_connection(); + let new_note = NoteInput{ + creator_id: 1, + parent_id: None, + published: String::from("now"), + content: req.note_input.clone(), // how to avoid clone here? + }; + insert_into(note).values(new_note).execute(&conn).unwrap(); + // generate activitypub object from post request // send to outbox + // if request made from web form + warp::redirect::redirect(warp::http::Uri::from_static("/")) } // ActivityPub outbox -fn outbox() { +fn send_to_outbox(activity: bool) { // activitystreams object // fetch/store from db. // db objects need to serialize/deserialize this object // if get -> fetch from db @@ -72,8 +96,6 @@ async fn main() { let notifications = warp::path("notifications"); // How does this interact with tokio? who knows! - // let url = ::std::env::var("DATABASE_URL").unwrap(); - // let conn = SqliteConnection::establish(&url).unwrap(); let test = warp::path("test").map(|| "Hello world"); // post @@ -90,11 +112,13 @@ async fn main() { let static_files = warp::path("static") .and(warp::fs::dir("./static")); + // https://github.com/seanmonstar/warp/issues/42 -- how to set up diesel // TODO set content length limit // TODO redirect via redirect in request // TODO secure against xss let create_note = warp::path("create_note") - .map(|| warp::redirect(warp::http::Uri::from_static("/"))); + .and(warp::body::form()) + .map(|note_req: NewNoteRequest| new_note(&note_req)); // catch all for any other paths let not_found = warp::any().map(|| "404 not found"); diff --git a/templates/timeline.html b/templates/timeline.html @@ -3,7 +3,7 @@ {% block content %} <div class="container"> <form action="/create_note" method="POST"> -<textarea id="note-input" rows=3 placeholder="note"></textarea> +<textarea name="note_input" rows=3 placeholder="note"></textarea> <br> <button id="post">create note</button> </form>