Big repository reorganization

The code is divided in three crates:
- plume-common, for the ActivityPub module, and some common utils
- plume-models, for the models and database-related code
- plume, the app itself

This new organization will allow to test it more easily, but also to create other tools that only reuse a little part of
the code (for instance a Wordpress import tool, that would just use the plume-models crate)
This commit is contained in:
Bat 2018-06-23 17:36:11 +01:00
parent 0a1edba4b0
commit 68c7aad179
40 changed files with 411 additions and 259 deletions

57
Cargo.lock generated
View File

@ -949,35 +949,66 @@ name = "plume"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"activitypub 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "activitypub 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plume-common 0.1.0",
"plume-models 0.1.0",
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=5b4225d5bed5769482dc926a7e6d6b79f1217be6)",
"rpassword 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"webfinger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "plume-common"
version = "0.1.0"
dependencies = [
"activitypub 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", "rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=5b4225d5bed5769482dc926a7e6d6b79f1217be6)",
"rpassword 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", ]
[[package]]
name = "plume-models"
version = "0.1.0"
dependencies = [
"activitypub 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)",
"plume-common 0.1.0",
"reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"webfinger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "webfinger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -4,42 +4,24 @@ name = "plume"
version = "0.1.0" version = "0.1.0"
[dependencies] [dependencies]
activitypub = "0.1.1" activitypub = "0.1.1"
activitystreams-derive = "0.1.0"
activitystreams-traits = "0.1.0"
ammonia = "1.1.0"
array_tool = "1.0"
base64 = "0.9"
bcrypt = "0.2"
colored = "1.6" colored = "1.6"
dotenv = "*" dotenv = "*"
failure = "0.1" failure = "0.1"
failure_derive = "0.1"
gettext-rs = "0.4" gettext-rs = "0.4"
heck = "0.3.0" heck = "0.3.0"
hex = "0.3"
hyper = "*"
lazy_static = "*"
openssl = "0.10.6"
reqwest = "0.8"
rpassword = "2.0" rpassword = "2.0"
serde = "*"
serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"
tera = "0.11"
url = "1.7"
webfinger = "0.1" webfinger = "0.1"
[dependencies.chrono]
features = ["serde"]
version = "0.4"
[dependencies.diesel] [dependencies.diesel]
features = ["postgres", "r2d2", "chrono"] features = ["postgres", "r2d2", "chrono"]
version = "*" version = "*"
[dependencies.pulldown-cmark] [dependencies.plume-models]
default-features = false path = "plume-models"
version = "0.1.2"
[dependencies.plume-common]
path = "plume-common"
[dependencies.rocket] [dependencies.rocket]
git = "https://github.com/SergioBenitez/Rocket" git = "https://github.com/SergioBenitez/Rocket"
@ -57,3 +39,6 @@ rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
[dependencies.rocket_i18n] [dependencies.rocket_i18n]
git = "https://github.com/BaptisteGelez/rocket_i18n" git = "https://github.com/BaptisteGelez/rocket_i18n"
rev = "5b4225d5bed5769482dc926a7e6d6b79f1217be6" rev = "5b4225d5bed5769482dc926a7e6d6b79f1217be6"
[workspace]
members = ['plume-models', 'plume-common']

61
plume-common/Cargo.toml Normal file
View File

@ -0,0 +1,61 @@
[package]
name = "plume-common"
version = "0.1.0"
authors = ["Bat' <baptiste@gelez.xyz>"]
[dependencies]
activitypub = "0.1.1"
activitystreams-derive = "0.1.0"
activitystreams-traits = "0.1.0"
# ammonia = "1.1.0"
array_tool = "1.0"
base64 = "0.9"
# bcrypt = "0.2"
# colored = "1.6"
# dotenv = "*"
failure = "0.1"
failure_derive = "0.1"
gettext-rs = "0.4"
heck = "0.3.0"
hex = "0.3"
hyper = "*"
# lazy_static = "*"
openssl = "0.10.6"
reqwest = "0.8"
# rpassword = "2.0"
serde = "*"
serde_derive = "1.0"
serde_json = "1.0"
# tera = "0.11"
# url = "1.7"
# webfinger = "0.1"
#
[dependencies.chrono]
features = ["serde"]
version = "0.4"
#
# [dependencies.diesel]
# features = ["postgres", "r2d2", "chrono"]
# version = "*"
[dependencies.pulldown-cmark]
default-features = false
version = "0.1.2"
[dependencies.rocket]
git = "https://github.com/SergioBenitez/Rocket"
rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
#
# [dependencies.rocket_codegen]
# git = "https://github.com/SergioBenitez/Rocket"
# rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
#
# [dependencies.rocket_contrib]
# features = ["tera_templates", "json"]
# git = "https://github.com/SergioBenitez/Rocket"
# rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
#
# [dependencies.rocket_i18n]
# git = "https://github.com/BaptisteGelez/rocket_i18n"
# rev = "5b4225d5bed5769482dc926a7e6d6b79f1217be6"
#

View File

@ -0,0 +1,41 @@
use activitypub::{Object, activity::Create};
use activity_pub::Id;
#[derive(Fail, Debug)]
pub enum InboxError {
#[fail(display = "The `type` property is required, but was not present")]
NoType,
#[fail(display = "Invalid activity type")]
InvalidType,
#[fail(display = "Couldn't undo activity")]
CantUndo
}
pub trait FromActivity<T: Object, C>: Sized {
fn from_activity(conn: &C, obj: T, actor: Id) -> Self;
fn try_from_activity(conn: &C, act: Create) -> bool {
if let Ok(obj) = act.create_props.object_object() {
Self::from_activity(conn, obj, act.create_props.actor_link::<Id>().unwrap());
true
} else {
false
}
}
}
pub trait Notify<C> {
fn notify(&self, conn: &C);
}
pub trait Deletable<C> {
/// true if success
fn delete_activity(conn: &C, id: Id) -> bool;
}
pub trait WithInbox {
fn get_inbox_url(&self) -> String;
fn get_shared_inbox_url(&self) -> Option<String>;
}

28
plume-common/src/lib.rs Normal file
View File

@ -0,0 +1,28 @@
#![feature(custom_attribute, iterator_flatten)]
extern crate activitypub;
#[macro_use]
extern crate activitystreams_derive;
extern crate activitystreams_traits;
extern crate array_tool;
extern crate base64;
extern crate chrono;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate gettextrs;
extern crate hex;
extern crate heck;
#[macro_use]
extern crate hyper;
extern crate openssl;
extern crate pulldown_cmark;
extern crate reqwest;
extern crate rocket;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
pub mod activity_pub;
pub mod utils;

64
plume-models/Cargo.toml Normal file
View File

@ -0,0 +1,64 @@
[package]
name = "plume-models"
version = "0.1.0"
authors = ["Baptiste Gelez <baptiste@gelez.xyz>"]
[dependencies]
activitypub = "0.1.1"
# activitystreams-derive = "0.1.0"
# activitystreams-traits = "0.1.0"
ammonia = "1.1.0"
# array_tool = "1.0"
# base64 = "0.9"
bcrypt = "0.2"
# colored = "1.6"
# dotenv = "*"
# failure = "0.1"
# failure_derive = "0.1"
# gettext-rs = "0.4"
heck = "0.3.0"
# hex = "0.3"
# hyper = "*"
lazy_static = "*"
openssl = "0.10.6"
reqwest = "0.8"
# rpassword = "2.0"
serde = "*"
serde_derive = "1.0"
serde_json = "1.0"
# tera = "0.11"
url = "1.7"
webfinger = "0.1"
#
[dependencies.chrono]
features = ["serde"]
version = "0.4"
[dependencies.diesel]
features = ["postgres", "r2d2", "chrono"]
version = "*"
[dependencies.plume-common]
path = "../plume-common"
# [dependencies.pulldown-cmark]
# default-features = false
# version = "0.1.2"
#
[dependencies.rocket]
git = "https://github.com/SergioBenitez/Rocket"
rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
#
# [dependencies.rocket_codegen]
# git = "https://github.com/SergioBenitez/Rocket"
# rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
#
# [dependencies.rocket_contrib]
# features = ["tera_templates", "json"]
# git = "https://github.com/SergioBenitez/Rocket"
# rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
#
# [dependencies.rocket_i18n]
# git = "https://github.com/BaptisteGelez/rocket_i18n"
# rev = "5b4225d5bed5769482dc926a7e6d6b79f1217be6"
#

View File

@ -17,12 +17,12 @@ use openssl::{
use webfinger::*; use webfinger::*;
use BASE_URL; use BASE_URL;
use activity_pub::{ use plume_common::activity_pub::{
ApSignature, ActivityStream, Id, IntoId, PublicKey, ApSignature, ActivityStream, Id, IntoId, PublicKey,
inbox::WithInbox, inbox::WithInbox,
sign sign
}; };
use models::instance::*; use instance::*;
use schema::blogs; use schema::blogs;
pub type CustomGroup = CustomObject<ApSignature, Group>; pub type CustomGroup = CustomObject<ApSignature, Group>;

View File

@ -7,21 +7,19 @@ use chrono;
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, dsl::any}; use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, dsl::any};
use serde_json; use serde_json;
use activity_pub::{ use plume_common::activity_pub::{
ap_url, Id, IntoId, PUBLIC_VISIBILTY, ap_url, Id, IntoId, PUBLIC_VISIBILTY,
inbox::{FromActivity, Notify} inbox::{FromActivity, Notify}
}; };
use models::{ use plume_common::utils;
get_next_id, use get_next_id;
instance::Instance, use instance::Instance;
mentions::Mention, use mentions::Mention;
notifications::*, use notifications::*;
posts::Post, use posts::Post;
users::User use users::User;
};
use schema::comments; use schema::comments;
use safe_string::SafeString; use safe_string::SafeString;
use utils;
#[derive(Queryable, Identifiable, Serialize, Clone)] #[derive(Queryable, Identifiable, Serialize, Clone)]
pub struct Comment { pub struct Comment {
@ -87,7 +85,7 @@ impl Comment {
} }
} }
impl FromActivity<Note> for Comment { impl FromActivity<Note, PgConnection> for Comment {
fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment { fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment {
let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string(); let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string();
let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone()); let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone());
@ -118,7 +116,7 @@ impl FromActivity<Note> for Comment {
} }
} }
impl Notify for Comment { impl Notify<PgConnection> for Comment {
fn notify(&self, conn: &PgConnection) { fn notify(&self, conn: &PgConnection) {
for author in self.get_post(conn).get_authors(conn) { for author in self.get_post(conn).get_authors(conn) {
Notification::insert(conn, NewNotification { Notification::insert(conn, NewNotification {

View File

@ -1,11 +1,11 @@
use diesel::{ use diesel::{
pg::PgConnection, pg::PgConnection,
r2d2::{ConnectionManager, PooledConnection} r2d2::{ConnectionManager, Pool, PooledConnection}
}; };
use rocket::{Request, State, Outcome, http::Status, request::{self, FromRequest}}; use rocket::{Request, State, Outcome, http::Status, request::{self, FromRequest}};
use std::ops::Deref; use std::ops::Deref;
use setup::PgPool; pub type PgPool = Pool<ConnectionManager<PgConnection>>;
// From rocket documentation // From rocket documentation

View File

@ -1,12 +1,10 @@
use activitypub::{Actor, activity::{Accept, Follow as FollowAct}}; use activitypub::{Actor, activity::{Accept, Follow as FollowAct}};
use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl}; use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl};
use activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox}, sign::Signer}; use plume_common::activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox}, sign::Signer};
use models::{ use blogs::Blog;
blogs::Blog, use notifications::*;
notifications::*, use users::User;
users::User
};
use schema::follows; use schema::follows;
#[derive(Queryable, Identifiable, Associations)] #[derive(Queryable, Identifiable, Associations)]
@ -55,7 +53,7 @@ impl Follow {
} }
} }
impl FromActivity<FollowAct> for Follow { impl FromActivity<FollowAct, PgConnection> for Follow {
fn from_activity(conn: &PgConnection, follow: FollowAct, _actor: Id) -> Follow { fn from_activity(conn: &PgConnection, follow: FollowAct, _actor: Id) -> Follow {
let from = User::from_url(conn, follow.follow_props.actor.as_str().unwrap().to_string()).unwrap(); let from = User::from_url(conn, follow.follow_props.actor.as_str().unwrap().to_string()).unwrap();
match User::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()) { match User::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()) {
@ -68,7 +66,7 @@ impl FromActivity<FollowAct> for Follow {
} }
} }
impl Notify for Follow { impl Notify<PgConnection> for Follow {
fn notify(&self, conn: &PgConnection) { fn notify(&self, conn: &PgConnection) {
let follower = User::get(conn, self.follower_id).unwrap(); let follower = User::get(conn, self.follower_id).unwrap();
Notification::insert(conn, NewNotification { Notification::insert(conn, NewNotification {

View File

@ -2,8 +2,8 @@ use chrono::NaiveDateTime;
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, PgConnection}; use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, PgConnection};
use std::iter::Iterator; use std::iter::Iterator;
use activity_pub::{ap_url, inbox::Inbox}; use plume_common::activity_pub::ap_url;
use models::users::User; use users::User;
use schema::{instances, users}; use schema::{instances, users};
#[derive(Identifiable, Queryable, Serialize)] #[derive(Identifiable, Queryable, Serialize)]
@ -69,5 +69,3 @@ impl Instance {
)) ))
} }
} }
impl Inbox for Instance {}

View File

@ -1,4 +1,26 @@
extern crate activitypub;
extern crate ammonia;
extern crate bcrypt;
extern crate chrono;
#[macro_use]
extern crate diesel;
extern crate heck;
#[macro_use]
extern crate lazy_static;
extern crate openssl;
extern crate plume_common;
extern crate reqwest;
extern crate rocket;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate url;
extern crate webfinger;
use diesel::{PgConnection, RunQueryDsl, select}; use diesel::{PgConnection, RunQueryDsl, select};
use std::env;
macro_rules! find_by { macro_rules! find_by {
($table:ident, $fn:ident, $($col:ident as $type:ident),+) => { ($table:ident, $fn:ident, $($col:ident as $type:ident),+) => {
@ -59,9 +81,19 @@ fn get_next_id(conn: &PgConnection, seq: &str) -> i32 {
next as i32 next as i32
} }
lazy_static! {
pub static ref BASE_URL: String = env::var("BASE_URL")
.unwrap_or(format!("127.0.0.1:{}", env::var("ROCKET_PORT").unwrap_or(String::from("8000"))));
pub static ref DB_URL: String = env::var("DB_URL")
.unwrap_or(format!("postgres://plume:plume@localhost/{}", env::var("DB_NAME").unwrap_or(String::from("plume"))));
}
pub mod blog_authors; pub mod blog_authors;
pub mod blogs; pub mod blogs;
pub mod comments; pub mod comments;
pub mod db_conn;
pub mod follows; pub mod follows;
pub mod instance; pub mod instance;
pub mod likes; pub mod likes;
@ -70,4 +102,6 @@ pub mod notifications;
pub mod post_authors; pub mod post_authors;
pub mod posts; pub mod posts;
pub mod reshares; pub mod reshares;
pub mod safe_string;
pub mod schema;
pub mod users; pub mod users;

View File

@ -2,17 +2,15 @@ use activitypub::activity;
use chrono; use chrono;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use activity_pub::{ use plume_common::activity_pub::{
PUBLIC_VISIBILTY, PUBLIC_VISIBILTY,
Id, Id,
IntoId, IntoId,
inbox::{FromActivity, Deletable, Notify} inbox::{FromActivity, Deletable, Notify}
}; };
use models::{ use notifications::*;
notifications::*, use posts::Post;
posts::Post, use users::User;
users::User
};
use schema::likes; use schema::likes;
#[derive(Queryable, Identifiable)] #[derive(Queryable, Identifiable)]
@ -75,7 +73,7 @@ impl Like {
} }
} }
impl FromActivity<activity::Like> for Like { impl FromActivity<activity::Like, PgConnection> for Like {
fn from_activity(conn: &PgConnection, like: activity::Like, _actor: Id) -> Like { fn from_activity(conn: &PgConnection, like: activity::Like, _actor: Id) -> Like {
let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string()); let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string());
let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string());
@ -89,7 +87,7 @@ impl FromActivity<activity::Like> for Like {
} }
} }
impl Notify for Like { impl Notify<PgConnection> for Like {
fn notify(&self, conn: &PgConnection) { fn notify(&self, conn: &PgConnection) {
let liker = User::get(conn, self.user_id).unwrap(); let liker = User::get(conn, self.user_id).unwrap();
let post = Post::get(conn, self.post_id).unwrap(); let post = Post::get(conn, self.post_id).unwrap();
@ -106,7 +104,7 @@ impl Notify for Like {
} }
} }
impl Deletable for Like { impl Deletable<PgConnection> for Like {
fn delete_activity(conn: &PgConnection, id: Id) -> bool { fn delete_activity(conn: &PgConnection, id: Id) -> bool {
if let Some(like) = Like::find_by_ap_url(conn, id.into()) { if let Some(like) = Like::find_by_ap_url(conn, id.into()) {
like.delete(conn); like.delete(conn);

View File

@ -1,13 +1,11 @@
use activitypub::link; use activitypub::link;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use activity_pub::inbox::Notify; use plume_common::activity_pub::inbox::Notify;
use models::{ use comments::Comment;
comments::Comment, use notifications::*;
notifications::*, use posts::Post;
posts::Post, use users::User;
users::User
};
use schema::mentions; use schema::mentions;
#[derive(Queryable, Identifiable, Serialize, Deserialize)] #[derive(Queryable, Identifiable, Serialize, Deserialize)]
@ -94,7 +92,7 @@ impl Mention {
} }
} }
impl Notify for Mention { impl Notify<PgConnection> for Mention {
fn notify(&self, conn: &PgConnection) { fn notify(&self, conn: &PgConnection) {
let author = self.get_comment(conn) let author = self.get_comment(conn)
.map(|c| c.get_author(conn).display_name.clone()) .map(|c| c.get_author(conn).display_name.clone())

View File

@ -1,7 +1,7 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods};
use models::users::User; use users::User;
use schema::notifications; use schema::notifications;
#[derive(Queryable, Identifiable, Serialize)] #[derive(Queryable, Identifiable, Serialize)]

View File

@ -1,9 +1,7 @@
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use models::{ use posts::Post;
posts::Post, use users::User;
users::User
};
use schema::post_authors; use schema::post_authors;
#[derive(Queryable, Identifiable, Associations)] #[derive(Queryable, Identifiable, Associations)]

View File

@ -9,19 +9,17 @@ use heck::KebabCase;
use serde_json; use serde_json;
use BASE_URL; use BASE_URL;
use activity_pub::{ use plume_common::activity_pub::{
PUBLIC_VISIBILTY, ap_url, Id, IntoId, PUBLIC_VISIBILTY, ap_url, Id, IntoId,
inbox::FromActivity inbox::FromActivity
}; };
use models::{ use blogs::Blog;
blogs::Blog, use instance::Instance;
instance::Instance, use likes::Like;
likes::Like, use mentions::Mention;
mentions::Mention, use post_authors::*;
post_authors::*, use reshares::Reshare;
reshares::Reshare, use users::User;
users::User
};
use schema::posts; use schema::posts;
use safe_string::SafeString; use safe_string::SafeString;
@ -190,7 +188,7 @@ impl Post {
} }
} }
impl FromActivity<Article> for Post { impl FromActivity<Article, PgConnection> for Post {
fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post { fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post {
let (blog, authors) = article.object_props.attributed_to_link_vec::<Id>() let (blog, authors) = article.object_props.attributed_to_link_vec::<Id>()
.expect("Post::from_activity: attributedTo error") .expect("Post::from_activity: attributedTo error")

View File

@ -2,8 +2,10 @@ use activitypub::activity::{Announce, Undo};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use activity_pub::{Id, IntoId, inbox::{FromActivity, Notify, Deletable}, PUBLIC_VISIBILTY}; use plume_common::activity_pub::{Id, IntoId, inbox::{FromActivity, Notify, Deletable}, PUBLIC_VISIBILTY};
use models::{notifications::*, posts::Post, users::User}; use notifications::*;
use posts::Post;
use users::User;
use schema::reshares; use schema::reshares;
#[derive(Serialize, Deserialize, Queryable, Identifiable)] #[derive(Serialize, Deserialize, Queryable, Identifiable)]
@ -78,7 +80,7 @@ impl Reshare {
} }
} }
impl FromActivity<Announce> for Reshare { impl FromActivity<Announce, PgConnection> for Reshare {
fn from_activity(conn: &PgConnection, announce: Announce, _actor: Id) -> Reshare { fn from_activity(conn: &PgConnection, announce: Announce, _actor: Id) -> Reshare {
let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string()); let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string());
let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string());
@ -92,7 +94,7 @@ impl FromActivity<Announce> for Reshare {
} }
} }
impl Notify for Reshare { impl Notify<PgConnection> for Reshare {
fn notify(&self, conn: &PgConnection) { fn notify(&self, conn: &PgConnection) {
let actor = User::get(conn, self.user_id).unwrap(); let actor = User::get(conn, self.user_id).unwrap();
let post = self.get_post(conn).unwrap(); let post = self.get_post(conn).unwrap();
@ -109,7 +111,7 @@ impl Notify for Reshare {
} }
} }
impl Deletable for Reshare { impl Deletable<PgConnection> for Reshare {
fn delete_activity(conn: &PgConnection, id: Id) -> bool { fn delete_activity(conn: &PgConnection, id: Id) -> bool {
if let Some(reshare) = Reshare::find_by_ap_url(conn, id.into()) { if let Some(reshare) = Reshare::find_by_ap_url(conn, id.into()) {
reshare.delete(conn); reshare.delete(conn);

View File

@ -12,6 +12,11 @@ use openssl::{
rsa::Rsa, rsa::Rsa,
sign sign
}; };
use plume_common::activity_pub::{
ap_url, ActivityStream, Id, IntoId, ApSignature, PublicKey,
inbox::WithInbox,
sign::{Signer, gen_keypair}
};
use reqwest::{ use reqwest::{
Client, Client,
header::{Accept, qitem}, header::{Accept, qitem},
@ -26,22 +31,17 @@ use url::Url;
use webfinger::*; use webfinger::*;
use BASE_URL; use BASE_URL;
use activity_pub::{
ap_url, ActivityStream, Id, IntoId, ApSignature, PublicKey,
inbox::{Inbox, WithInbox},
sign::{Signer, gen_keypair}
};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use blogs::Blog;
blogs::Blog, use blog_authors::BlogAuthor;
blog_authors::BlogAuthor, use follows::Follow;
follows::Follow, use instance::*;
instance::*, use likes::Like;
post_authors::PostAuthor, use post_authors::PostAuthor;
posts::Post use posts::Post;
}; use reshares::Reshare;
use schema::users;
use safe_string::SafeString; use safe_string::SafeString;
use schema::users;
pub const AUTH_COOKIE: &'static str = "user_id"; pub const AUTH_COOKIE: &'static str = "user_id";
@ -286,7 +286,6 @@ impl User {
pub fn has_liked(&self, conn: &PgConnection, post: &Post) -> bool { pub fn has_liked(&self, conn: &PgConnection, post: &Post) -> bool {
use schema::likes; use schema::likes;
use models::likes::Like;
likes::table likes::table
.filter(likes::post_id.eq(post.id)) .filter(likes::post_id.eq(post.id))
.filter(likes::user_id.eq(self.id)) .filter(likes::user_id.eq(self.id))
@ -297,7 +296,6 @@ impl User {
pub fn has_reshared(&self, conn: &PgConnection, post: &Post) -> bool { pub fn has_reshared(&self, conn: &PgConnection, post: &Post) -> bool {
use schema::reshares; use schema::reshares;
use models::reshares::Reshare;
reshares::table reshares::table
.filter(reshares::post_id.eq(post.id)) .filter(reshares::post_id.eq(post.id))
.filter(reshares::user_id.eq(self.id)) .filter(reshares::user_id.eq(self.id))
@ -418,8 +416,6 @@ impl WithInbox for User {
} }
} }
impl Inbox for User {}
impl Signer for User { impl Signer for User {
fn get_key_id(&self) -> String { fn get_key_id(&self) -> String {
format!("{}#main-key", self.ap_url) format!("{}#main-key", self.ap_url)

View File

@ -1,54 +1,19 @@
use activitypub::{ use activitypub::activity::{Announce, Create, Like, Undo};
Object,
activity::{Announce, Create, Like, Undo}
};
use diesel::PgConnection; use diesel::PgConnection;
use failure::Error; use failure::Error;
use serde_json; use serde_json;
use activity_pub::{ use plume_common::activity_pub::{Id, inbox::{Deletable, FromActivity, InboxError}};
Id use plume_models::{
}; comments::Comment,
use models::{
comments::*,
follows::Follow, follows::Follow,
instance::Instance,
likes, likes,
posts::*, reshares::Reshare,
reshares::* posts::Post,
users::User
}; };
#[derive(Fail, Debug)]
enum InboxError {
#[fail(display = "The `type` property is required, but was not present")]
NoType,
#[fail(display = "Invalid activity type")]
InvalidType,
#[fail(display = "Couldn't undo activity")]
CantUndo
}
pub trait FromActivity<T: Object>: Sized {
fn from_activity(conn: &PgConnection, obj: T, actor: Id) -> Self;
fn try_from_activity(conn: &PgConnection, act: Create) -> bool {
if let Ok(obj) = act.create_props.object_object() {
Self::from_activity(conn, obj, act.create_props.actor_link::<Id>().unwrap());
true
} else {
false
}
}
}
pub trait Notify {
fn notify(&self, conn: &PgConnection);
}
pub trait Deletable {
/// true if success
fn delete_activity(conn: &PgConnection, id: Id) -> bool;
}
pub trait Inbox { pub trait Inbox {
fn received(&self, conn: &PgConnection, act: serde_json::Value) -> Result<(), Error> { fn received(&self, conn: &PgConnection, act: serde_json::Value) -> Result<(), Error> {
let actor_id = Id::new(act["actor"].as_str().unwrap()); let actor_id = Id::new(act["actor"].as_str().unwrap());
@ -97,8 +62,5 @@ pub trait Inbox {
} }
} }
pub trait WithInbox { impl Inbox for Instance {}
fn get_inbox_url(&self) -> String; impl Inbox for User {}
fn get_shared_inbox_url(&self) -> Option<String>;
}

View File

@ -1,64 +1,28 @@
#![feature(plugin, custom_derive, decl_macro, iterator_find_map, iterator_flatten)] #![feature(custom_derive, decl_macro, plugin)]
#![plugin(rocket_codegen)] #![plugin(rocket_codegen)]
extern crate activitypub; extern crate activitypub;
#[macro_use]
extern crate activitystreams_derive;
extern crate activitystreams_traits;
extern crate ammonia;
extern crate array_tool;
extern crate base64;
extern crate bcrypt;
extern crate chrono;
extern crate colored; extern crate colored;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate gettextrs;
extern crate heck;
extern crate hex;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate diesel; extern crate diesel;
extern crate dotenv; extern crate dotenv;
#[macro_use] extern crate failure;
extern crate lazy_static; extern crate gettextrs;
extern crate openssl; extern crate heck;
extern crate pulldown_cmark; extern crate plume_common;
extern crate reqwest; extern crate plume_models;
extern crate rocket; extern crate rocket;
extern crate rocket_contrib; extern crate rocket_contrib;
extern crate rocket_i18n; extern crate rocket_i18n;
extern crate rpassword; extern crate rpassword;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use] #[macro_use]
extern crate serde_json; extern crate serde_json;
extern crate tera;
extern crate url;
extern crate webfinger; extern crate webfinger;
use rocket_contrib::Template; use rocket_contrib::Template;
use std::env;
mod activity_pub; mod inbox;
mod db_conn;
mod models;
mod safe_string;
mod schema;
mod setup; mod setup;
mod routes; mod routes;
mod utils;
lazy_static! {
pub static ref BASE_URL: String = env::var("BASE_URL")
.unwrap_or(format!("127.0.0.1:{}", env::var("ROCKET_PORT").unwrap_or(String::from("8000"))));
pub static ref DB_URL: String = env::var("DB_URL")
.unwrap_or(format!("postgres://plume:plume@localhost/{}", env::var("DB_NAME").unwrap_or(String::from("plume"))));
}
fn main() { fn main() {
let pool = setup::check(); let pool = setup::check();

View File

@ -6,16 +6,16 @@ use rocket::{
use rocket_contrib::Template; use rocket_contrib::Template;
use serde_json; use serde_json;
use activity_pub::ActivityStream; use plume_common::activity_pub::ActivityStream;
use db_conn::DbConn; use plume_common::utils;
use models::{ use plume_models::{
blog_authors::*, blog_authors::*,
blogs::*, blogs::*,
db_conn::DbConn,
instance::Instance, instance::Instance,
posts::Post, posts::Post,
users::User users::User
}; };
use utils;
#[get("/~/<name>", rank = 2)] #[get("/~/<name>", rank = 2)]
fn details(name: String, conn: DbConn, user: Option<User>) -> Template { fn details(name: String, conn: DbConn, user: Option<User>) -> Template {

View File

@ -4,15 +4,16 @@ use rocket::{
}; };
use serde_json; use serde_json;
use activity_pub::{broadcast, inbox::Inbox}; use plume_common::activity_pub::broadcast;
use db_conn::DbConn; use plume_models::{
use models::{
blogs::Blog, blogs::Blog,
comments::*, comments::*,
db_conn::DbConn,
instance::Instance, instance::Instance,
posts::Post, posts::Post,
users::User users::User
}; };
use inbox::Inbox;
#[derive(FromForm)] #[derive(FromForm)]
pub struct CommentQuery { pub struct CommentQuery {

View File

@ -1,7 +1,7 @@
use rocket_contrib::Template; use rocket_contrib::Template;
use rocket::Request; use rocket::Request;
use rocket::request::FromRequest; use rocket::request::FromRequest;
use models::users::User; use plume_models::users::User;
#[catch(404)] #[catch(404)]
fn not_found(req: &Request) -> Template { fn not_found(req: &Request) -> Template {

View File

@ -2,14 +2,14 @@ use gettextrs::gettext;
use rocket_contrib::{Json, Template}; use rocket_contrib::{Json, Template};
use serde_json; use serde_json;
use activity_pub::inbox::Inbox; use plume_models::{
use db_conn::DbConn;
use models::{
comments::Comment, comments::Comment,
db_conn::DbConn,
posts::Post, posts::Post,
users::User, users::User,
instance::* instance::*
}; };
use inbox::Inbox;
#[get("/")] #[get("/")]
fn index(conn: DbConn, user: Option<User>) -> Template { fn index(conn: DbConn, user: Option<User>) -> Template {

View File

@ -1,16 +1,15 @@
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, inbox::Notify}; use plume_common::activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn; use plume_common::utils;
use models::{ use plume_models::{
blogs::Blog, blogs::Blog,
db_conn::DbConn,
likes, likes,
posts::Post, posts::Post,
users::User users::User
}; };
use utils;
#[get("/~/<blog>/<slug>/like")] #[get("/~/<blog>/<slug>/like")]
fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap(); let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap();

View File

@ -1,10 +1,8 @@
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use rocket_contrib::Template; use rocket_contrib::Template;
use db_conn::DbConn; use plume_common::utils;
use models::{notifications::Notification, users::User}; use plume_models::{db_conn::DbConn, notifications::Notification, users::User};
use utils;
#[get("/notifications")] #[get("/notifications")]
fn notifications(conn: DbConn, user: User) -> Template { fn notifications(conn: DbConn, user: User) -> Template {

View File

@ -5,19 +5,19 @@ use rocket::response::{Redirect, Flash};
use rocket_contrib::Template; use rocket_contrib::Template;
use serde_json; use serde_json;
use activity_pub::{broadcast, ActivityStream}; use plume_common::activity_pub::{broadcast, ActivityStream};
use db_conn::DbConn; use plume_common::utils;
use models::{ use plume_models::{
blogs::*, blogs::*,
db_conn::DbConn,
comments::Comment, comments::Comment,
mentions::Mention, mentions::Mention,
post_authors::*, post_authors::*,
posts::*, posts::*,
safe_string::SafeString,
users::User users::User
}; };
use routes::comments::CommentQuery; use routes::comments::CommentQuery;
use safe_string::SafeString;
use utils;
// See: https://github.com/SergioBenitez/Rocket/pull/454 // See: https://github.com/SergioBenitez/Rocket/pull/454
#[get("/~/<blog>/<slug>", rank = 4)] #[get("/~/<blog>/<slug>", rank = 4)]

View File

@ -1,16 +1,15 @@
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, inbox::Notify}; use plume_common::activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn; use plume_common::utils;
use models::{ use plume_models::{
blogs::Blog, blogs::Blog,
db_conn::DbConn,
posts::Post, posts::Post,
reshares::*, reshares::*,
users::User users::User
}; };
use utils;
#[get("/~/<blog>/<slug>/reshare")] #[get("/~/<blog>/<slug>/reshare")]
fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap(); let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap();

View File

@ -6,8 +6,10 @@ use rocket::{
}; };
use rocket_contrib::Template; use rocket_contrib::Template;
use db_conn::DbConn; use plume_models::{
use models::users::{User, AUTH_COOKIE}; db_conn::DbConn,
users::{User, AUTH_COOKIE}
};
#[get("/login")] #[get("/login")]
fn new(user: Option<User>) -> Template { fn new(user: Option<User>) -> Template {

View File

@ -8,20 +8,21 @@ use rocket::{request::Form,
use rocket_contrib::Template; use rocket_contrib::Template;
use serde_json; use serde_json;
use activity_pub::{ use plume_common::activity_pub::{
ActivityStream, broadcast, Id, IntoId, ActivityStream, broadcast, Id, IntoId,
inbox::{Inbox, Notify} inbox::{Notify}
}; };
use db_conn::DbConn; use plume_common::utils;
use models::{ use plume_models::{
blogs::Blog, blogs::Blog,
db_conn::DbConn,
follows, follows,
instance::Instance, instance::Instance,
posts::Post, posts::Post,
reshares::Reshare, reshares::Reshare,
users::* users::*
}; };
use utils; use inbox::Inbox;
#[get("/me")] #[get("/me")]
fn me(user: Option<User>) -> Result<Redirect, Flash<Redirect>> { fn me(user: Option<User>) -> Result<Redirect, Flash<Redirect>> {

View File

@ -3,10 +3,8 @@ use rocket::response::Content;
use serde_json; use serde_json;
use webfinger::*; use webfinger::*;
use BASE_URL; use plume_common::activity_pub::ap_url;
use activity_pub::ap_url; use plume_models::{BASE_URL, db_conn::DbConn, blogs::Blog, users::User};
use db_conn::DbConn;
use models::{blogs::Blog, users::User};
#[get("/.well-known/nodeinfo")] #[get("/.well-known/nodeinfo")]
fn nodeinfo() -> Content<String> { fn nodeinfo() -> Content<String> {

View File

@ -7,12 +7,12 @@ use std::path::Path;
use std::process::{exit, Command}; use std::process::{exit, Command};
use rpassword; use rpassword;
use DB_URL; use plume_models::{
use db_conn::DbConn; DB_URL,
use models::instance::*; db_conn::{DbConn, PgPool},
use models::users::*; instance::*,
users::*
pub type PgPool = Pool<ConnectionManager<PgConnection>>; };
/// Initializes a database pool. /// Initializes a database pool.
fn init_pool() -> Option<PgPool> { fn init_pool() -> Option<PgPool> {