Resolve activitystream TODOs
This commit is contained in:
		
							parent
							
								
									0e24ccbf29
								
							
						
					
					
						commit
						4a86af6fc1
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -869,6 +869,7 @@ name = "plume" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "activitystreams 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)", | ||||
|  "activitystreams-types 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  | ||||
| @ -4,6 +4,7 @@ name = "plume" | ||||
| version = "0.1.0" | ||||
| [dependencies] | ||||
| activitystreams = "0.1" | ||||
| activitystreams-derive = "0.1" | ||||
| activitystreams-traits = "0.1" | ||||
| activitystreams-types = "0.1" | ||||
| array_tool = "1.0" | ||||
|  | ||||
| @ -8,7 +8,7 @@ use diesel::PgConnection; | ||||
| use failure::Error; | ||||
| use serde_json; | ||||
| 
 | ||||
| use activity_pub::{broadcast, IntoId}; | ||||
| use activity_pub::{broadcast, Id, IntoId}; | ||||
| use activity_pub::actor::Actor as APActor; | ||||
| use activity_pub::sign::*; | ||||
| use models::blogs::Blog; | ||||
| @ -118,7 +118,7 @@ pub trait Inbox { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn accept_follow<A: Signer + IntoId, B: Clone + WithInbox + Actor>( | ||||
|     fn accept_follow<A: Signer + IntoId + Clone, B: Clone + WithInbox + Actor>( | ||||
|         &self, | ||||
|         conn: &PgConnection, | ||||
|         from: &A, | ||||
| @ -132,8 +132,8 @@ pub trait Inbox { | ||||
|             following_id: target_id | ||||
|         }); | ||||
| 
 | ||||
|         let mut accept = Accept::default();//new(target, follow, conn);
 | ||||
|         accept.set_actor_link(from.into()).unwrap(); | ||||
|         let mut accept = Accept::default(); | ||||
|         accept.set_actor_link::<Id>(from.clone().into_id()).unwrap(); | ||||
|         accept.set_object_object(follow).unwrap(); | ||||
|         broadcast(conn, &*from, accept, vec![target.clone()]); | ||||
|     } | ||||
|  | ||||
| @ -102,7 +102,7 @@ pub fn broadcast<A: Activity + Clone, S: sign::Signer, T: inbox::WithInbox + Act | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize)] | ||||
| #[derive(Clone, Serialize, Deserialize)] | ||||
| pub struct Id { | ||||
|     #[serde(flatten)] | ||||
|     id: String | ||||
| @ -117,7 +117,7 @@ impl Id { | ||||
| } | ||||
| 
 | ||||
| pub trait IntoId { | ||||
|     fn into(&self) -> Id; | ||||
|     fn into_id(self) -> Id; | ||||
| } | ||||
| 
 | ||||
| impl Link for Id {} | ||||
|  | ||||
| @ -2,6 +2,8 @@ | ||||
| #![plugin(rocket_codegen)] | ||||
| 
 | ||||
| extern crate activitystreams; | ||||
| #[macro_use] | ||||
| extern crate activitystreams_derive; | ||||
| extern crate activitystreams_traits; | ||||
| extern crate activitystreams_types; | ||||
| extern crate array_tool; | ||||
|  | ||||
| @ -12,7 +12,7 @@ use openssl::pkey::{PKey, Private}; | ||||
| use openssl::rsa::Rsa; | ||||
| use openssl::sign::Signer; | ||||
| 
 | ||||
| use activity_pub::{ActivityStream, Id}; | ||||
| use activity_pub::{ActivityStream, Id, IntoId}; | ||||
| use activity_pub::actor::{Actor as APActor, ActorType}; | ||||
| use activity_pub::inbox::WithInbox; | ||||
| use activity_pub::sign; | ||||
| @ -175,8 +175,8 @@ impl Blog { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Into<Id> for Blog { | ||||
|     fn into(self) -> Id { | ||||
| impl IntoId for Blog { | ||||
|     fn into_id(self) -> Id { | ||||
|         Id::new(self.ap_url) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,12 @@ | ||||
| use activitystreams_types::{ | ||||
|     activity::Create, | ||||
|     object::{Note, properties::ObjectProperties} | ||||
| }; | ||||
| use chrono; | ||||
| use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods}; | ||||
| use serde_json; | ||||
| 
 | ||||
| use activity_pub::{ap_url, PUBLIC_VISIBILTY}; | ||||
| use activity_pub::{ap_url, IntoId, PUBLIC_VISIBILTY}; | ||||
| use activity_pub::actor::Actor; | ||||
| use activity_pub::object::Object; | ||||
| use models::posts::Post; | ||||
| @ -71,6 +75,37 @@ impl Comment { | ||||
|     pub fn get_post(&self, conn: &PgConnection) -> Post { | ||||
|         Post::get(conn, self.post_id).unwrap()        
 | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_activity(&self, conn: &PgConnection) -> Note { | ||||
|         let mut to = self.get_author(conn).get_followers(conn).into_iter().map(|f| f.ap_url).collect::<Vec<String>>(); | ||||
|         to.append(&mut self.get_post(conn).get_receivers_urls(conn)); | ||||
|         to.push(PUBLIC_VISIBILTY.to_string()); | ||||
| 
 | ||||
|         let mut comment = Note::default(); | ||||
|         comment.object_props = ObjectProperties { | ||||
|             id: Some(serde_json::to_value(self.ap_url.clone()).unwrap()), | ||||
|             summary: Some(serde_json::to_value(self.spoiler_text.clone()).unwrap()), | ||||
|             content: Some(serde_json::to_value(self.content.clone()).unwrap()), | ||||
|             in_reply_to: Some(serde_json::to_value(self.in_response_to_id.map_or_else(|| self.get_post(conn).ap_url, |id| { | ||||
|                 let comm = Comment::get(conn, id).unwrap(); | ||||
|                 comm.ap_url.clone().unwrap_or(comm.compute_id(conn)) | ||||
|             })).unwrap()), | ||||
|             published: Some(serde_json::to_value(self.creation_date).unwrap()), | ||||
|             attributed_to: Some(serde_json::to_value(self.get_author(conn).compute_id(conn)).unwrap()), | ||||
|             to: Some(serde_json::to_value(to).unwrap()), | ||||
|             cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()), | ||||
|             ..ObjectProperties::default() | ||||
|         }; | ||||
|         comment | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_activity(&self, conn: &PgConnection) -> Create { | ||||
|         let mut act = Create::default(); | ||||
|         act.set_actor_link(self.get_author(conn).into_id()).unwrap(); | ||||
|         act.set_object_object(self.into_activity(conn)).unwrap(); | ||||
|         act.object_props.set_id_string(format!("{}/activity", self.ap_url.clone().unwrap())).unwrap(); | ||||
|         act | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Object for Comment { | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| use activitystreams_types::activity; | ||||
| use chrono; | ||||
| use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; | ||||
| use serde_json; | ||||
| 
 | ||||
| use activity_pub::IntoId; | ||||
| use activity_pub::actor::Actor; | ||||
| use activity_pub::object::Object; | ||||
| use models::posts::Post; | ||||
| @ -66,8 +68,25 @@ impl Like { | ||||
|             .into_iter().nth(0) | ||||
|     } | ||||
| 
 | ||||
|     pub fn delete(&self, conn: &PgConnection) { | ||||
|     pub fn delete(&self, conn: &PgConnection) -> activity::Undo { | ||||
|         diesel::delete(self).execute(conn).unwrap(); | ||||
| 
 | ||||
|         let mut act = activity::Undo::default(); | ||||
|         act.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); | ||||
|         act.set_object_object(self.into_activity(conn)).unwrap(); | ||||
|         act | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_activity(&self, conn: &PgConnection) -> activity::Like { | ||||
|         let mut act = activity::Like::default(); | ||||
|         act.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); | ||||
|         act.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap(); | ||||
|         act.object_props.set_id_string(format!("{}/like/{}", | ||||
|             User::get(conn, self.user_id).unwrap().ap_url, | ||||
|             Post::get(conn, self.post_id).unwrap().ap_url | ||||
|         )).unwrap(); | ||||
| 
 | ||||
|         act | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,10 +1,14 @@ | ||||
| use activitystreams_types::{ | ||||
|     activity::Create, | ||||
|     object::{Article, properties::ObjectProperties} | ||||
| }; | ||||
| use chrono::NaiveDateTime; | ||||
| use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl}; | ||||
| use diesel::dsl::any; | ||||
| use serde_json; | ||||
| 
 | ||||
| use BASE_URL; | ||||
| use activity_pub::{PUBLIC_VISIBILTY, ap_url}; | ||||
| use activity_pub::{PUBLIC_VISIBILTY, ap_url, Id, IntoId}; | ||||
| use activity_pub::actor::Actor; | ||||
| use activity_pub::object::Object; | ||||
| use models::blogs::Blog; | ||||
| @ -137,6 +141,40 @@ impl Post { | ||||
|         }); | ||||
|         to | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_activity(&self, conn: &PgConnection) -> Article { | ||||
|         let mut to = self.get_receivers_urls(conn); | ||||
|         to.push(PUBLIC_VISIBILTY.to_string()); | ||||
| 
 | ||||
|         let mut article = Article::default(); | ||||
|         article.object_props = ObjectProperties { | ||||
|             name: Some(serde_json::to_value(self.title.clone()).unwrap()), | ||||
|             id: Some(serde_json::to_value(self.ap_url.clone()).unwrap()), | ||||
|             attributed_to: Some(serde_json::to_value(self.get_authors(conn).into_iter().map(|x| x.ap_url).collect::<Vec<String>>()).unwrap()), | ||||
|             content: Some(serde_json::to_value(self.content.clone()).unwrap()), | ||||
|             published: Some(serde_json::to_value(self.creation_date).unwrap()), | ||||
|             tag: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()), | ||||
|             url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()), | ||||
|             to: Some(serde_json::to_value(to).unwrap()), | ||||
|             cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()), | ||||
|             ..ObjectProperties::default()                
 | ||||
|         }; | ||||
|         article | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_activity(&self, conn: &PgConnection) -> Create { | ||||
|         let mut act = Create::default(); | ||||
|         act.object_props.set_id_string(format!("{}/activity", self.ap_url)).unwrap(); | ||||
|         act.set_actor_link(Id::new(self.get_authors(conn)[0].clone().ap_url)).unwrap(); | ||||
|         act.set_object_object(self.into_activity(conn)).unwrap(); | ||||
|         act | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl IntoId for Post { | ||||
|     fn into_id(self) -> Id { | ||||
|         Id::new(self.ap_url.clone()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Object for Post { | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| use activitystreams_traits::{Actor, Object}; | ||||
| use activitystreams_traits::{Actor, Object, Link}; | ||||
| use activitystreams_types::{ | ||||
|     activity::Create, | ||||
|     collection::OrderedCollection | ||||
|     actor::Person, | ||||
|     collection::OrderedCollection, | ||||
|     object::properties::ObjectProperties, | ||||
|     CustomObject | ||||
| }; | ||||
| use bcrypt; | ||||
| use chrono::NaiveDateTime; | ||||
| @ -227,8 +229,11 @@ impl User { | ||||
|     } | ||||
| 
 | ||||
|     pub fn outbox(&self, conn: &PgConnection) -> ActivityStream<OrderedCollection> { | ||||
|         let mut coll = OrderedCollection::default(); // TODO
 | ||||
|         coll.collection_props.items = serde_json::to_value(self.get_activities(conn)).unwrap(); | ||||
|         let acts = self.get_activities(conn); | ||||
|         let n_acts = acts.len(); | ||||
|         let mut coll = OrderedCollection::default(); | ||||
|         coll.collection_props.items = serde_json::to_value(acts).unwrap(); | ||||
|         coll.collection_props.set_total_items_u64(n_acts as u64).unwrap(); | ||||
|         ActivityStream::new(coll) | ||||
|     } | ||||
| 
 | ||||
| @ -237,10 +242,8 @@ impl User { | ||||
|         use schema::post_authors; | ||||
|         let posts_by_self = PostAuthor::belonging_to(self).select(post_authors::post_id); | ||||
|         let posts = posts::table.filter(posts::id.eq(any(posts_by_self))).load::<Post>(conn).unwrap(); | ||||
|         posts.into_iter().map(|_| { | ||||
|             // TODO Create::new(self, &p, conn)
 | ||||
|             // TODO: add a method to convert Post -> Create
 | ||||
|             serde_json::to_value(Create::default()).unwrap() | ||||
|         posts.into_iter().map(|p| { | ||||
|             serde_json::to_value(p.create_activity(conn)).unwrap() | ||||
|         }).collect::<Vec<serde_json::Value>>() | ||||
|     } | ||||
| 
 | ||||
| @ -278,6 +281,42 @@ impl User { | ||||
|     pub fn get_keypair(&self) -> PKey<Private> { | ||||
|         PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_activity(&self, conn: &PgConnection) -> CustomObject<ApProps, Person> { | ||||
|         let mut actor = Person::default(); | ||||
|         actor.object_props = ObjectProperties { | ||||
|             id: Some(serde_json::to_value(self.compute_id(conn)).unwrap()), | ||||
|             name: Some(serde_json::to_value(self.get_display_name()).unwrap()), | ||||
|             summary: Some(serde_json::to_value(self.get_summary()).unwrap()), | ||||
|             url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()), | ||||
|             ..ObjectProperties::default() | ||||
|         }; | ||||
| 
 | ||||
|         CustomObject::new(actor, ApProps { | ||||
|             inbox: Some(serde_json::to_value(self.compute_inbox(conn)).unwrap()), | ||||
|             outbox: Some(serde_json::to_value(self.compute_outbox(conn)).unwrap()), | ||||
|             preferred_username: Some(serde_json::to_value(self.get_actor_id()).unwrap()), | ||||
|             endpoints: Some(json!({ | ||||
|                 "sharedInbox": ap_url(format!("{}/inbox", BASE_URL.as_str())) | ||||
|             })) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Default, Properties)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct ApProps { | ||||
|     #[activitystreams(ab(Object, Link))] | ||||
|     inbox: Option<serde_json::Value>, | ||||
| 
 | ||||
|     #[activitystreams(ab(Object, Link))] | ||||
|     outbox: Option<serde_json::Value>, | ||||
| 
 | ||||
|     #[activitystreams(ab(Object, Link))] | ||||
|     preferred_username: Option<serde_json::Value>, | ||||
| 
 | ||||
|     #[activitystreams(ab(Object))] | ||||
|     endpoints: Option<serde_json::Value> | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'r> FromRequest<'a, 'r> for User { | ||||
| @ -359,7 +398,7 @@ impl APActor for User { | ||||
| } | ||||
| 
 | ||||
| impl IntoId for User { | ||||
|     fn into(&self) -> Id { | ||||
|     fn into_id(self) -> Id { | ||||
|         Id::new(self.ap_url.clone()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| use activitystreams_types::activity::Create; | ||||
| use rocket::request::Form; | ||||
| use rocket::response::Redirect; | ||||
| use rocket_contrib::Template; | ||||
| @ -41,8 +40,8 @@ fn create(blog: String, slug: String, query: CommentQuery, data: Form<NewComment | ||||
|         sensitive: false, | ||||
|         spoiler_text: "".to_string() | ||||
|     }); | ||||
|     // TODO: let act = Create::new(&user, &comment, &*conn);
 | ||||
|     // broadcast(&*conn, &user, act, user.get_followers(&*conn));
 | ||||
| 
 | ||||
|     broadcast(&*conn, &user, comment.create_activity(&*conn), user.get_followers(&*conn)); | ||||
| 
 | ||||
|     Redirect::to(format!("/~/{}/{}/#comment-{}", blog, slug, comment.id).as_ref()) | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| use activitystreams_types::activity::{Like, Undo}; | ||||
| use rocket::response::Redirect; | ||||
| 
 | ||||
| use activity_pub::broadcast; | ||||
| @ -18,12 +17,12 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { | ||||
|                 ap_url: "".to_string() | ||||
|         }); | ||||
|         like.update_ap_url(&*conn); | ||||
|         // TODO: let act = Like::new(&user, &post, &*conn);
 | ||||
|         // TODO: broadcast(&*conn, &user, act, user.get_followers(&*conn));
 | ||||
| 
 | ||||
|         broadcast(&*conn, &user, like.into_activity(&*conn), user.get_followers(&*conn)); | ||||
|     } else { | ||||
|         let like = likes::Like::find_by_user_on_post(&*conn, &user, &post).unwrap(); | ||||
|         // TODO: like.delete(&*conn);
 | ||||
|         // TODO: broadcast(&*conn, &user, Undo::new(&user, &like, &*conn), user.get_followers(&*conn));
 | ||||
|         let delete_act = like.delete(&*conn); | ||||
|         broadcast(&*conn, &user, delete_act, user.get_followers(&*conn)); | ||||
|     } | ||||
| 
 | ||||
|     Redirect::to(format!("/~/{}/{}/", blog, slug).as_ref()) | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| use activitystreams_types::activity::Create; | ||||
| use heck::KebabCase; | ||||
| use rocket::request::Form; | ||||
| use rocket::response::Redirect; | ||||
| use rocket_contrib::Template; | ||||
| use serde_json; | ||||
| 
 | ||||
| use activity_pub::{broadcast, context, activity_pub, ActivityPub, Id}; | ||||
| use activity_pub::{broadcast, context, activity_pub, ActivityPub}; | ||||
| use activity_pub::object::Object; | ||||
| use db_conn::DbConn; | ||||
| use models::blogs::*; | ||||
| @ -38,7 +37,7 @@ fn details(blog: String, slug: String, conn: DbConn, user: Option<User>) -> Temp | ||||
| 
 | ||||
| #[get("/~/<_blog>/<slug>", rank = 3, format = "application/activity+json")] | ||||
| fn activity_details(_blog: String, slug: String, conn: DbConn) -> ActivityPub { | ||||
|     // TODO: posts in different blogs may have the same slug
 | ||||
|     // FIXME: posts in different blogs may have the same slug
 | ||||
|     let post = Post::find_by_slug(&*conn, slug).unwrap(); | ||||
| 
 | ||||
|     let mut act = post.serialize(&*conn); | ||||
| @ -85,12 +84,8 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn) | ||||
|         author_id: user.id | ||||
|     }); | ||||
| 
 | ||||
|     // TODO: use Post -> Create conversion
 | ||||
|     // let act = Create::default();
 | ||||
|     // act.object_props.set_id_string(format!("{}/activity", post.compute_id(&*conn)));
 | ||||
|     // act.set_actor_link(Id::new(user.ap_url));
 | ||||
|     // act.set_object_object();
 | ||||
|     // broadcast(&*conn, &user, act, user.get_followers(&*conn));
 | ||||
|     let act = post.create_activity(&*conn); | ||||
|     broadcast(&*conn, &user, act, user.get_followers(&*conn)); | ||||
| 
 | ||||
|     Redirect::to(format!("/~/{}/{}", blog_name, slug).as_str()) | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ use rocket::response::Redirect; | ||||
| use rocket_contrib::Template; | ||||
| use serde_json; | ||||
| 
 | ||||
| use activity_pub::{activity_pub, ActivityPub, ActivityStream, context, broadcast}; | ||||
| use activity_pub::{activity_pub, ActivityPub, ActivityStream, context, broadcast, Id, IntoId}; | ||||
| use activity_pub::actor::Actor; | ||||
| use activity_pub::inbox::Inbox; | ||||
| use db_conn::DbConn; | ||||
| @ -56,8 +56,10 @@ fn follow(name: String, conn: DbConn, user: User) -> Redirect { | ||||
|         follower_id: user.id, | ||||
|         following_id: target.id | ||||
|     }); | ||||
|     let act = Follow::default(); | ||||
|     // TODO
 | ||||
|     let mut act = Follow::default(); | ||||
|     act.set_actor_link::<Id>(user.clone().into_id()).unwrap(); | ||||
|     act.set_object_object(user.into_activity(&*conn)).unwrap(); | ||||
|     act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap(); | ||||
|     broadcast(&*conn, &user, act, vec![target]); | ||||
|     Redirect::to(format!("/@/{}", name).as_ref()) | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user