From 58de24c424b039ac85b8f50edc948f273de51c8e Mon Sep 17 00:00:00 2001 From: Dessalines Date: Mon, 4 Mar 2019 19:52:09 -0800 Subject: [PATCH] Adding and activitypub output for user. --- API.md | 1 - .../2019-02-26-002946_create_user/up.sql | 6 +- .../2019-02-27-170003_create_community/up.sql | 7 +- .../2019-03-03-163336_create_post/up.sql | 7 +- server/src/actions/community.rs | 21 ++-- server/src/actions/post.rs | 95 ------------------- server/src/actions/user.rs | 22 ++--- server/src/apub.rs | 59 ++++++++++++ server/src/lib.rs | 49 ++++++++-- server/src/models.rs | 19 ---- server/src/schema.rs | 17 ++-- 11 files changed, 141 insertions(+), 162 deletions(-) create mode 100644 server/src/apub.rs delete mode 100644 server/src/models.rs diff --git a/API.md b/API.md index 8438cb9e7..fb2335424 100644 --- a/API.md +++ b/API.md @@ -52,7 +52,6 @@ "inbox": "https://rust-reddit-fediverse/api/v1/user/sally_smith/inbox", "outbox": "https://rust-reddit-fediverse/api/v1/user/sally_smith/outbox", "liked": "https://rust-reddit-fediverse/api/v1/user/sally_smith/liked", - "disliked": "https://rust-reddit-fediverse/api/v1/user/sally_smith/disliked", "following": "https://rust-reddit-fediverse/api/v1/user/sally_smith/following", "name": "sally_smith", "preferredUsername": "Sally", diff --git a/server/migrations/2019-02-26-002946_create_user/up.sql b/server/migrations/2019-02-26-002946_create_user/up.sql index a4ba1e880..577ff136a 100644 --- a/server/migrations/2019-02-26-002946_create_user/up.sql +++ b/server/migrations/2019-02-26-002946_create_user/up.sql @@ -5,6 +5,6 @@ create table user_ ( password_encrypted text not null, email text, icon bytea, - start_time timestamp not null default now() -); - + published timestamp not null default now(), + updated timestamp +) diff --git a/server/migrations/2019-02-27-170003_create_community/up.sql b/server/migrations/2019-02-27-170003_create_community/up.sql index 692a5f06b..30deec5b8 100644 --- a/server/migrations/2019-02-27-170003_create_community/up.sql +++ b/server/migrations/2019-02-27-170003_create_community/up.sql @@ -1,19 +1,20 @@ create table community ( id serial primary key, name varchar(20) not null, - start_time timestamp not null default now() + published timestamp not null default now(), + updated timestamp ); create table community_user ( id serial primary key, community_id int references community on update cascade on delete cascade not null, fedi_user_id text not null, - start_time timestamp not null default now() + published timestamp not null default now() ); create table community_follower ( id serial primary key, community_id int references community on update cascade on delete cascade not null, fedi_user_id text not null, - start_time timestamp not null default now() + published timestamp not null default now() ); diff --git a/server/migrations/2019-03-03-163336_create_post/up.sql b/server/migrations/2019-03-03-163336_create_post/up.sql index 4a811fa2d..16ef545e8 100644 --- a/server/migrations/2019-03-03-163336_create_post/up.sql +++ b/server/migrations/2019-03-03-163336_create_post/up.sql @@ -3,20 +3,21 @@ create table post ( name varchar(100) not null, url text not null, attributed_to text not null, - start_time timestamp not null default now() + published timestamp not null default now(), + updated timestamp ); create table post_like ( id serial primary key, fedi_user_id text not null, post_id int references post on update cascade on delete cascade, - start_time timestamp not null default now() + published timestamp not null default now() ); create table post_dislike ( id serial primary key, fedi_user_id text not null, post_id int references post on update cascade on delete cascade, - start_time timestamp not null default now() + published timestamp not null default now() ); diff --git a/server/src/actions/community.rs b/server/src/actions/community.rs index 6b0bea8d5..03490369c 100644 --- a/server/src/actions/community.rs +++ b/server/src/actions/community.rs @@ -9,13 +9,15 @@ use {Crud, Followable, Joinable}; pub struct Community { pub id: i32, pub name: String, - pub start_time: chrono::NaiveDateTime + pub published: chrono::NaiveDateTime, + pub updated: Option } #[derive(Insertable, AsChangeset, Clone, Copy)] #[table_name="community"] pub struct CommunityForm<'a> { - pub name: &'a str, + pub name: &'a str, + pub updated: Option<&'a chrono::NaiveDateTime> } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] @@ -25,7 +27,7 @@ pub struct CommunityUser { pub id: i32, pub community_id: i32, pub fedi_user_id: String, - pub start_time: chrono::NaiveDateTime + pub published: chrono::NaiveDateTime, } #[derive(Insertable, AsChangeset, Clone, Copy)] @@ -42,7 +44,7 @@ pub struct CommunityFollower { pub id: i32, pub community_id: i32, pub fedi_user_id: String, - pub start_time: chrono::NaiveDateTime + pub published: chrono::NaiveDateTime, } #[derive(Insertable, AsChangeset, Clone, Copy)] @@ -130,6 +132,7 @@ mod tests { let new_community = CommunityForm { name: "TIL".into(), + updated: None }; let inserted_community = Community::create(&conn, new_community).unwrap(); @@ -137,14 +140,16 @@ mod tests { let expected_community = Community { id: inserted_community.id, name: "TIL".into(), - start_time: inserted_community.start_time + published: inserted_community.published, + updated: None }; let new_user = UserForm { name: "thom".into(), preferred_username: None, password_encrypted: "nope".into(), - email: None + email: None, + updated: None }; let inserted_user = User_::create(&conn, new_user).unwrap(); @@ -160,7 +165,7 @@ mod tests { id: inserted_community_follower.id, community_id: inserted_community.id, fedi_user_id: "test".into(), - start_time: inserted_community_follower.start_time + published: inserted_community_follower.published }; let community_user_form = CommunityUserForm { @@ -174,7 +179,7 @@ mod tests { id: inserted_community_user.id, community_id: inserted_community.id, fedi_user_id: "test".into(), - start_time: inserted_community_user.start_time + published: inserted_community_user.published }; let read_community = Community::read(&conn, inserted_community.id); diff --git a/server/src/actions/post.rs b/server/src/actions/post.rs index f939fc7c2..e69de29bb 100644 --- a/server/src/actions/post.rs +++ b/server/src/actions/post.rs @@ -1,95 +0,0 @@ -extern crate diesel; -use schema::user_; -use diesel::*; -use diesel::result::Error; -use schema::user_::dsl::*; - -#[derive(Queryable, PartialEq, Debug)] -pub struct User_ { - pub id: i32, - pub name: String, - pub preferred_username: Option, - pub password_encrypted: String, - pub email: Option, - pub icon: Option>, - pub start_time: chrono::NaiveDateTime -} - -#[derive(Insertable, AsChangeset, Clone, Copy)] -#[table_name="user_"] -pub struct NewUser<'a> { - pub name: &'a str, - pub preferred_username: Option<&'a str>, - pub password_encrypted: &'a str, - pub email: Option<&'a str>, -} - -pub fn read(conn: &PgConnection, user_id: i32) -> User_ { - user_.find(user_id) - .first::(conn) - .expect("Error in query") -} - -pub fn delete(conn: &PgConnection, user_id: i32) -> usize { - diesel::delete(user_.find(user_id)) - .execute(conn) - .expect("Error deleting.") -} - -pub fn create(conn: &PgConnection, new_user: &NewUser) -> Result { - let mut edited_user = new_user.clone(); - // Add the rust crypt - edited_user.password_encrypted = "here"; - // edited_user.password_encrypted; - insert_into(user_) - .values(edited_user) - .get_result::(conn) -} - -pub fn update(conn: &PgConnection, user_id: i32, new_user: &NewUser) -> User_ { - let mut edited_user = new_user.clone(); - edited_user.password_encrypted = "here"; - diesel::update(user_.find(user_id)) - .set(edited_user) - .get_result::(conn) - .expect(&format!("Unable to find user {}", user_id)) -} - -#[cfg(test)] -mod tests { - use establish_connection; - use super::*; - #[test] - fn test_crud() { - let conn = establish_connection(); - - let new_user = NewUser { - name: "thom".into(), - preferred_username: None, - password_encrypted: "nope".into(), - email: None - }; - - let inserted_user = create(&conn, &new_user).unwrap(); - - let expected_user = User_ { - id: inserted_user.id, - name: "thom".into(), - preferred_username: None, - password_encrypted: "here".into(), - email: None, - icon: None, - start_time: inserted_user.start_time - }; - - let read_user = read(&conn, inserted_user.id); - let updated_user = update(&conn, inserted_user.id, &new_user); - let num_deleted = delete(&conn, inserted_user.id); - - assert_eq!(expected_user, read_user); - assert_eq!(expected_user, inserted_user); - assert_eq!(expected_user, updated_user); - assert_eq!(1, num_deleted); - - } -} diff --git a/server/src/actions/user.rs b/server/src/actions/user.rs index 36222f834..8556525f4 100644 --- a/server/src/actions/user.rs +++ b/server/src/actions/user.rs @@ -1,10 +1,8 @@ extern crate diesel; -extern crate activitypub; use schema::user_; use diesel::*; use diesel::result::Error; use schema::user_::dsl::*; -// use self::activitypub::{context, actor::Person}; use Crud; #[derive(Queryable, Identifiable, PartialEq, Debug)] @@ -16,7 +14,8 @@ pub struct User_ { pub password_encrypted: String, pub email: Option, pub icon: Option>, - pub start_time: chrono::NaiveDateTime + pub published: chrono::NaiveDateTime, + pub updated: Option } #[derive(Insertable, AsChangeset, Clone, Copy)] @@ -26,6 +25,7 @@ pub struct UserForm<'a> { pub preferred_username: Option<&'a str>, pub password_encrypted: &'a str, pub email: Option<&'a str>, + pub updated: Option<&'a chrono::NaiveDateTime> } impl<'a> Crud> for User_ { @@ -58,16 +58,6 @@ impl<'a> Crud> for User_ { } } - -// TODO -// pub fn person(user: &User_) -> Person { -// let mut person = Person::default(); -// person.object_props.set_context_object(context()); -// person.ap_actor_props.set_preferred_username_string("set".into()); - -// person -// } - #[cfg(test)] mod tests { use establish_connection; @@ -81,7 +71,8 @@ mod tests { name: "thom".into(), preferred_username: None, password_encrypted: "nope".into(), - email: None + email: None, + updated: None }; let inserted_user = User_::create(&conn, new_user).unwrap(); @@ -93,7 +84,8 @@ mod tests { password_encrypted: "here".into(), email: None, icon: None, - start_time: inserted_user.start_time + published: inserted_user.published, + updated: None }; let read_user = User_::read(&conn, inserted_user.id); diff --git a/server/src/apub.rs b/server/src/apub.rs new file mode 100644 index 000000000..4cfd10882 --- /dev/null +++ b/server/src/apub.rs @@ -0,0 +1,59 @@ +extern crate activitypub; +use self::activitypub::{context, actor::Person}; +use actions::user::User_; + +impl User_ { + pub fn person(&self) -> Person { + use {Settings, to_datetime_utc}; + let base_url = &format!("{}/user/{}", Settings::get().api_endpoint(), self.name); + let mut person = Person::default(); + person.object_props.set_context_object(context()).ok(); + person.object_props.set_id_string(base_url.to_string()).ok(); + person.object_props.set_name_string(self.name.to_owned()).ok(); + person.object_props.set_published_utctime(to_datetime_utc(self.published)).ok(); + if let Some(i) = self.updated { + person.object_props.set_updated_utctime(to_datetime_utc(i)).ok(); + } + // person.object_props.summary = self.summary; + + person.ap_actor_props.set_inbox_string(format!("{}/inbox", &base_url)).ok(); + person.ap_actor_props.set_outbox_string(format!("{}/outbox", &base_url)).ok(); + person.ap_actor_props.set_following_string(format!("{}/following", &base_url)).ok(); + person.ap_actor_props.set_liked_string(format!("{}/liked", &base_url)).ok(); + if let Some(i) = &self.preferred_username { + person.ap_actor_props.set_preferred_username_string(i.to_string()).ok(); + } + + person + } +} + +#[cfg(test)] +mod tests { + use super::activitypub::{context, actor::Person}; + use super::User_; + use naive_now; + + #[test] + fn test_person() { + let expected_user = User_ { + id: 52, + name: "thom".into(), + preferred_username: None, + password_encrypted: "here".into(), + email: None, + icon: None, + published: naive_now(), + updated: None + }; + + let person = expected_user.person(); + + // let expected_person = Person { + // }; + + assert_eq!("http://0.0.0.0/api/v1/user/thom", person.object_props.id_string().unwrap()); + + } +} + diff --git a/server/src/lib.rs b/server/src/lib.rs index e8a67c3de..e78989711 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,6 +1,7 @@ #[macro_use] extern crate diesel; extern crate dotenv; +extern crate chrono; use diesel::*; use diesel::pg::PgConnection; @@ -9,7 +10,7 @@ use dotenv::dotenv; use std::env; pub mod schema; -pub mod models; +pub mod apub; pub mod actions; // pub trait Likeable; @@ -30,13 +31,45 @@ pub trait Joinable { fn leave(conn: &PgConnection, form: T) -> usize; } - pub fn establish_connection() -> PgConnection { - dotenv().ok(); - - let database_url = env::var("DATABASE_URL") - .expect("DATABASE_URL must be set"); - PgConnection::establish(&database_url) - .expect(&format!("Error connecting to {}", database_url)) + let db_url = Settings::get().db_url; + PgConnection::establish(&db_url) + .expect(&format!("Error connecting to {}", db_url)) } +pub struct Settings { + db_url: String, + hostname: String +} + +impl Settings { + fn get() -> Self { + dotenv().ok(); + Settings { + db_url: env::var("DATABASE_URL") + .expect("DATABASE_URL must be set"), + hostname: env::var("HOSTNAME").unwrap_or("http://0.0.0.0".to_string()) + } + } + fn api_endpoint(&self) -> String { + format!("{}/api/v1", self.hostname) + } +} + +use chrono::{DateTime, NaiveDateTime, Utc}; +pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime { + DateTime::::from_utc(ndt, Utc) +} + +pub fn naive_now() -> NaiveDateTime { + chrono::prelude::Utc::now().naive_utc() +} + +#[cfg(test)] +mod tests { + use Settings; + #[test] + fn test_api() { + assert_eq!(Settings::get().api_endpoint(), "http://0.0.0.0/api/v1"); + } +} diff --git a/server/src/models.rs b/server/src/models.rs deleted file mode 100644 index c895f3ea5..000000000 --- a/server/src/models.rs +++ /dev/null @@ -1,19 +0,0 @@ - -// enum CommunityUserType { -// CREATOR = 0, -// MODERATOR = 1, -// USER = 2 -// } - -// impl CommunityUserType { -// fn from_u32(value: u32) -> CommunityUserType { -// match value { -// 0 => CommunityUserType::CREATOR, -// 1 => CommunityUserType::MODERATOR, -// 2 => CommunityUserType::USER, -// _ => panic!("Unknown value: {}", value), -// } -// } -// } - - diff --git a/server/src/schema.rs b/server/src/schema.rs index cf90c0475..75cbad5ba 100644 --- a/server/src/schema.rs +++ b/server/src/schema.rs @@ -2,7 +2,8 @@ table! { community (id) { id -> Int4, name -> Varchar, - start_time -> Timestamp, + published -> Timestamp, + updated -> Nullable, } } @@ -11,7 +12,7 @@ table! { id -> Int4, community_id -> Int4, fedi_user_id -> Text, - start_time -> Timestamp, + published -> Timestamp, } } @@ -20,7 +21,7 @@ table! { id -> Int4, community_id -> Int4, fedi_user_id -> Text, - start_time -> Timestamp, + published -> Timestamp, } } @@ -30,7 +31,8 @@ table! { name -> Varchar, url -> Text, attributed_to -> Text, - start_time -> Timestamp, + published -> Timestamp, + updated -> Nullable, } } @@ -39,7 +41,7 @@ table! { id -> Int4, fedi_user_id -> Text, post_id -> Nullable, - start_time -> Timestamp, + published -> Timestamp, } } @@ -48,7 +50,7 @@ table! { id -> Int4, fedi_user_id -> Text, post_id -> Nullable, - start_time -> Timestamp, + published -> Timestamp, } } @@ -60,7 +62,8 @@ table! { password_encrypted -> Text, email -> Nullable, icon -> Nullable, - start_time -> Timestamp, + published -> Timestamp, + updated -> Nullable, } }