Merge pull request 'Add ActivityPub tests and a little fixes' (#1021) from ap-tests into main
Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/1021
This commit is contained in:
		
						commit
						69eccc50a3
					
				
							
								
								
									
										39
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										39
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -16,6 +16,21 @@ dependencies = [ | ||||
|  "serde_json", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "activitystreams" | ||||
| version = "0.7.0-alpha.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6bcc3fbb392890a1942b1e5cca76cba93c8ed24b5ff50004cc3289afaab3f92c" | ||||
| dependencies = [ | ||||
|  "activitystreams-kinds", | ||||
|  "chrono", | ||||
|  "mime 0.3.16", | ||||
|  "serde 1.0.133", | ||||
|  "serde_json", | ||||
|  "thiserror", | ||||
|  "url 2.2.2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "activitystreams-derive" | ||||
| version = "0.1.1" | ||||
| @ -27,6 +42,16 @@ dependencies = [ | ||||
|  "syn 0.13.11", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "activitystreams-kinds" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0784e99afd032199d3ed70cefb8eb3a8d1aef15f7f2c4e68d033c4e12bb6079e" | ||||
| dependencies = [ | ||||
|  "serde 1.0.133", | ||||
|  "url 2.2.2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "activitystreams-traits" | ||||
| version = "0.1.0" | ||||
| @ -205,6 +230,16 @@ version = "0.10.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "assert-json-diff" | ||||
| version = "2.0.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "50f1c3703dd33532d7f0ca049168930e9099ecac238e23cf932f3a69c42f06da" | ||||
| dependencies = [ | ||||
|  "serde 1.0.133", | ||||
|  "serde_json", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "async-trait" | ||||
| version = "0.1.52" | ||||
| @ -3136,6 +3171,7 @@ name = "plume-common" | ||||
| version = "0.7.1" | ||||
| dependencies = [ | ||||
|  "activitypub", | ||||
|  "activitystreams", | ||||
|  "activitystreams-derive", | ||||
|  "activitystreams-traits", | ||||
|  "array_tool", | ||||
| @ -3190,7 +3226,9 @@ name = "plume-models" | ||||
| version = "0.7.1" | ||||
| dependencies = [ | ||||
|  "activitypub", | ||||
|  "activitystreams", | ||||
|  "ammonia", | ||||
|  "assert-json-diff", | ||||
|  "bcrypt", | ||||
|  "chrono", | ||||
|  "diesel", | ||||
| @ -5232,6 +5270,7 @@ dependencies = [ | ||||
|  "idna 0.2.3", | ||||
|  "matches", | ||||
|  "percent-encoding 2.1.0", | ||||
|  "serde 1.0.133", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | ||||
| @ -24,6 +24,7 @@ tokio = "0.1.22" | ||||
| regex-syntax = { version = "0.6.17", default-features = false, features = ["unicode-perl"] } | ||||
| tracing = "0.1.30" | ||||
| askama_escape = "0.10.2" | ||||
| activitystreams = "0.7.0-alpha.14" | ||||
| 
 | ||||
| [dependencies.chrono] | ||||
| features = ["serde"] | ||||
|  | ||||
| @ -271,7 +271,7 @@ pub fn md_to_html<'a>( | ||||
|     media_processor: Option<MediaProcessor<'a>>, | ||||
| ) -> (String, HashSet<String>, HashSet<String>) { | ||||
|     let base_url = if let Some(base_url) = base_url { | ||||
|         format!("//{}/", base_url) | ||||
|         format!("https://{}/", base_url) | ||||
|     } else { | ||||
|         "/".to_owned() | ||||
|     }; | ||||
|  | ||||
| @ -35,6 +35,7 @@ riker = "0.4.2" | ||||
| once_cell = "1.5.2" | ||||
| lettre = "0.9.6" | ||||
| native-tls = "0.2.8" | ||||
| activitystreams = "0.7.0-alpha.14" | ||||
| 
 | ||||
| [dependencies.chrono] | ||||
| features = ["serde"] | ||||
| @ -54,6 +55,7 @@ path = "../plume-common" | ||||
| path = "../plume-macro" | ||||
| 
 | ||||
| [dev-dependencies] | ||||
| assert-json-diff = "2.0.1" | ||||
| diesel_migrations = "1.3.0" | ||||
| 
 | ||||
| [features] | ||||
|  | ||||
| @ -16,7 +16,7 @@ use activitypub::{ | ||||
|     link, | ||||
|     object::{Note, Tombstone}, | ||||
| }; | ||||
| use chrono::{self, NaiveDateTime}; | ||||
| use chrono::{self, NaiveDateTime, TimeZone, Utc}; | ||||
| use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl}; | ||||
| use plume_common::{ | ||||
|     activity_pub::{ | ||||
| @ -59,7 +59,7 @@ impl Comment { | ||||
|     insert!(comments, NewComment, |inserted, conn| { | ||||
|         if inserted.ap_url.is_none() { | ||||
|             inserted.ap_url = Some(format!( | ||||
|                 "{}comment/{}", | ||||
|                 "{}/comment/{}", | ||||
|                 inserted.get_post(conn)?.ap_url, | ||||
|                 inserted.id | ||||
|             )); | ||||
| @ -129,7 +129,7 @@ impl Comment { | ||||
|                 |id| Ok(Comment::get(conn, id)?.ap_url.unwrap_or_default()) as Result<String>, | ||||
|             )?))?; | ||||
|         note.object_props | ||||
|             .set_published_string(chrono::Utc::now().to_rfc3339())?; | ||||
|             .set_published_utctime(Utc.from_utc_datetime(&self.creation_date))?; | ||||
|         note.object_props.set_attributed_to_link(author.into_id())?; | ||||
|         note.object_props.set_to_link_vec(to)?; | ||||
|         note.object_props.set_tag_link_vec( | ||||
| @ -402,10 +402,34 @@ impl CommentTree { | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use crate::blogs::Blog; | ||||
|     use crate::inbox::{inbox, tests::fill_database, InboxResult}; | ||||
|     use crate::safe_string::SafeString; | ||||
|     use crate::tests::db; | ||||
|     use crate::tests::{db, format_datetime}; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use diesel::Connection; | ||||
|     use serde_json::{json, to_value}; | ||||
| 
 | ||||
|     fn prepare_activity(conn: &DbConn) -> (Comment, Vec<Post>, Vec<User>, Vec<Blog>) { | ||||
|         let (posts, users, blogs) = fill_database(&conn); | ||||
| 
 | ||||
|         let comment = Comment::insert( | ||||
|             conn, | ||||
|             NewComment { | ||||
|                 content: SafeString::new("My comment, mentioning to @user"), | ||||
|                 in_response_to_id: None, | ||||
|                 post_id: posts[0].id, | ||||
|                 author_id: users[0].id, | ||||
|                 ap_url: None, | ||||
|                 sensitive: true, | ||||
|                 spoiler_text: "My CW".into(), | ||||
|                 public_visibility: true, | ||||
|             }, | ||||
|         ) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|         (comment, posts, users, blogs) | ||||
|     } | ||||
| 
 | ||||
|     // creates a post, get it's Create activity, delete the post,
 | ||||
|     // "send" the Create to the inbox, and check it works
 | ||||
| @ -413,30 +437,77 @@ mod tests { | ||||
|     fn self_federation() { | ||||
|         let conn = &db(); | ||||
|         conn.test_transaction::<_, (), _>(|| { | ||||
|             let (posts, users, _) = fill_database(&conn); | ||||
|             let (original_comm, posts, users, _blogs) = prepare_activity(&conn); | ||||
|             let act = original_comm.create_activity(&conn).unwrap(); | ||||
| 
 | ||||
|             let original_comm = Comment::insert( | ||||
|             assert_json_eq!(to_value(&act).unwrap(), json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": ["https://plu.me/@/admin/followers"], | ||||
|                 "id": format!("https://plu.me/~/BlogName/testing/comment/{}/activity", original_comm.id), | ||||
|                 "object": { | ||||
|                     "attributedTo": "https://plu.me/@/admin/", | ||||
|                     "content": r###"<p dir="auto">My comment, mentioning to <a href="https://plu.me/@/user/" title="user">@user</a></p>
 | ||||
| "###,
 | ||||
|                     "id": format!("https://plu.me/~/BlogName/testing/comment/{}", original_comm.id), | ||||
|                     "inReplyTo": "https://plu.me/~/BlogName/testing", | ||||
|                     "published": format_datetime(&original_comm.creation_date), | ||||
|                     "summary": "My CW", | ||||
|                     "tag": [ | ||||
|                         { | ||||
|                             "href": "https://plu.me/@/user/", | ||||
|                             "name": "@user", | ||||
|                             "type": "Mention" | ||||
|                         } | ||||
|                     ], | ||||
|                     "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "type": "Note" | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Create", | ||||
|             })); | ||||
| 
 | ||||
|             let reply = Comment::insert( | ||||
|                 conn, | ||||
|                 NewComment { | ||||
|                     content: SafeString::new("My comment"), | ||||
|                     in_response_to_id: None, | ||||
|                     content: SafeString::new(""), | ||||
|                     in_response_to_id: Some(original_comm.id), | ||||
|                     post_id: posts[0].id, | ||||
|                     author_id: users[0].id, | ||||
|                     author_id: users[1].id, | ||||
|                     ap_url: None, | ||||
|                     sensitive: true, | ||||
|                     spoiler_text: "My CW".into(), | ||||
|                     sensitive: false, | ||||
|                     spoiler_text: "".into(), | ||||
|                     public_visibility: true, | ||||
|                 }, | ||||
|             ) | ||||
|             .unwrap(); | ||||
|             let act = original_comm.create_activity(&conn).unwrap(); | ||||
|             let reply_act = reply.create_activity(&conn).unwrap(); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(&reply_act).unwrap(), json!({ | ||||
|                 "actor": "https://plu.me/@/user/", | ||||
|                 "cc": ["https://plu.me/@/user/followers"], | ||||
|                 "id": format!("https://plu.me/~/BlogName/testing/comment/{}/activity", reply.id), | ||||
|                 "object": { | ||||
|                     "attributedTo": "https://plu.me/@/user/", | ||||
|                     "content": "", | ||||
|                     "id": format!("https://plu.me/~/BlogName/testing/comment/{}", reply.id), | ||||
|                     "inReplyTo": format!("https://plu.me/~/BlogName/testing/comment/{}", original_comm.id), | ||||
|                     "published": format_datetime(&reply.creation_date), | ||||
|                     "summary": "", | ||||
|                     "tag": [], | ||||
|                     "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "type": "Note" | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Create" | ||||
|             })); | ||||
| 
 | ||||
|             inbox( | ||||
|                 &conn, | ||||
|                 serde_json::to_value(original_comm.build_delete(&conn).unwrap()).unwrap(), | ||||
|             ) | ||||
|             .unwrap(); | ||||
| 
 | ||||
|             match inbox(&conn, serde_json::to_value(act).unwrap()).unwrap() { | ||||
|             match inbox(&conn, to_value(act).unwrap()).unwrap() { | ||||
|                 InboxResult::Commented(c) => { | ||||
|                     // TODO: one is HTML, the other markdown: assert_eq!(c.content, original_comm.content);
 | ||||
|                     assert_eq!(c.in_response_to_id, original_comm.in_response_to_id); | ||||
| @ -451,4 +522,60 @@ mod tests { | ||||
|             Ok(()) | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (comment, _posts, _users, _blogs) = prepare_activity(&conn); | ||||
|             let act = comment.to_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "attributedTo": "https://plu.me/@/admin/", | ||||
|                 "content": r###"<p dir="auto">My comment, mentioning to <a href="https://plu.me/@/user/" title="user">@user</a></p>
 | ||||
| "###,
 | ||||
|                 "id": format!("https://plu.me/~/BlogName/testing/comment/{}", comment.id), | ||||
|                 "inReplyTo": "https://plu.me/~/BlogName/testing", | ||||
|                 "published": format_datetime(&comment.creation_date), | ||||
|                 "summary": "My CW", | ||||
|                 "tag": [ | ||||
|                     { | ||||
|                         "href": "https://plu.me/@/user/", | ||||
|                         "name": "@user", | ||||
|                         "type": "Mention" | ||||
|                     } | ||||
|                 ], | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Note" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn build_delete() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (comment, _posts, _users, _blogs) = prepare_activity(&conn); | ||||
|             let act = comment.build_delete(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "id": format!("https://plu.me/~/BlogName/testing/comment/{}#delete", comment.id), | ||||
|                 "object": { | ||||
|                     "id": format!("https://plu.me/~/BlogName/testing/comment/{}", comment.id), | ||||
|                     "type": "Tombstone" | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Delete" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -99,11 +99,27 @@ impl Follow { | ||||
|         )?; | ||||
|         res.notify(conn)?; | ||||
| 
 | ||||
|         let accept = res.build_accept(from, target, follow)?; | ||||
|         broadcast( | ||||
|             &*target, | ||||
|             accept, | ||||
|             vec![from.clone()], | ||||
|             CONFIG.proxy().cloned(), | ||||
|         ); | ||||
|         Ok(res) | ||||
|     } | ||||
| 
 | ||||
|     pub fn build_accept<A: Signer + IntoId + Clone, B: Clone + AsActor<T> + IntoId, T>( | ||||
|         &self, | ||||
|         from: &B, | ||||
|         target: &A, | ||||
|         follow: FollowAct, | ||||
|     ) -> Result<Accept> { | ||||
|         let mut accept = Accept::default(); | ||||
|         let accept_id = ap_url(&format!( | ||||
|             "{}/follow/{}/accept", | ||||
|             "{}/follows/{}/accept", | ||||
|             CONFIG.base_url.as_str(), | ||||
|             &res.id | ||||
|             self.id | ||||
|         )); | ||||
|         accept.object_props.set_id_string(accept_id)?; | ||||
|         accept | ||||
| @ -116,13 +132,8 @@ impl Follow { | ||||
|             .accept_props | ||||
|             .set_actor_link::<Id>(target.clone().into_id())?; | ||||
|         accept.accept_props.set_object_object(follow)?; | ||||
|         broadcast( | ||||
|             &*target, | ||||
|             accept, | ||||
|             vec![from.clone()], | ||||
|             CONFIG.proxy().cloned(), | ||||
|         ); | ||||
|         Ok(res) | ||||
| 
 | ||||
|         Ok(accept) | ||||
|     } | ||||
| 
 | ||||
|     pub fn build_undo(&self, conn: &Connection) -> Result<Undo> { | ||||
| @ -219,8 +230,29 @@ impl IntoId for Follow { | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use crate::{tests::db, users::tests as user_tests}; | ||||
|     use crate::{tests::db, users::tests as user_tests, users::tests::fill_database}; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use diesel::Connection; | ||||
|     use serde_json::{json, to_value}; | ||||
| 
 | ||||
|     fn prepare_activity(conn: &DbConn) -> (Follow, User, User, Vec<User>) { | ||||
|         let users = fill_database(conn); | ||||
|         let following = &users[1]; | ||||
|         let follower = &users[2]; | ||||
|         let mut follow = Follow::insert( | ||||
|             conn, | ||||
|             NewFollow { | ||||
|                 follower_id: follower.id, | ||||
|                 following_id: following.id, | ||||
|                 ap_url: "".into(), | ||||
|             }, | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         // following.ap_url = format!("https://plu.me/follows/{}", follow.id);
 | ||||
|         follow.ap_url = format!("https://plu.me/follows/{}", follow.id); | ||||
| 
 | ||||
|         (follow, following.to_owned(), follower.to_owned(), users) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_id() { | ||||
| @ -255,4 +287,77 @@ mod tests { | ||||
|             Ok(()) | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (follow, _following, _follower, _users) = prepare_activity(&conn); | ||||
|             let act = follow.to_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/other/", | ||||
|                 "cc": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "id": format!("https://plu.me/follows/{}", follow.id), | ||||
|                 "object": "https://plu.me/@/user/", | ||||
|                 "to": ["https://plu.me/@/user/"], | ||||
|                 "type": "Follow" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn build_accept() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (follow, following, follower, _users) = prepare_activity(&conn); | ||||
|             let act = follow.build_accept(&follower, &following, follow.to_activity(&conn)?)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/user/", | ||||
|                 "cc": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "id": format!("https://127.0.0.1:7878/follows/{}/accept", follow.id), | ||||
|                 "object": { | ||||
|                     "actor": "https://plu.me/@/other/", | ||||
|                     "cc": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "id": format!("https://plu.me/follows/{}", follow.id), | ||||
|                     "object": "https://plu.me/@/user/", | ||||
|                     "to": ["https://plu.me/@/user/"], | ||||
|                     "type": "Follow" | ||||
|                 }, | ||||
|                 "to": ["https://plu.me/@/other/"], | ||||
|                 "type": "Accept" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn build_undo() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (follow, _following, _follower, _users) = prepare_activity(&conn); | ||||
|             let act = follow.build_undo(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/other/", | ||||
|                 "cc": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "id": format!("https://plu.me/follows/{}/undo", follow.id), | ||||
|                 "object": format!("https://plu.me/follows/{}", follow.id), | ||||
|                 "to": ["https://plu.me/@/user/"], | ||||
|                 "type": "Undo" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -334,6 +334,7 @@ impl SmtpNewWithAddr for smtp::SmtpClient { | ||||
| #[macro_use] | ||||
| mod tests { | ||||
|     use crate::{db_conn, migrations::IMPORTED_MIGRATIONS, Connection as Conn, CONFIG}; | ||||
|     use chrono::{naive::NaiveDateTime, Datelike, Timelike}; | ||||
|     use diesel::r2d2::ConnectionManager; | ||||
|     use plume_common::utils::random_hex; | ||||
|     use std::env::temp_dir; | ||||
| @ -366,6 +367,33 @@ mod tests { | ||||
|             pool | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(feature = "postgres")] | ||||
|     pub(crate) fn format_datetime(dt: &NaiveDateTime) -> String { | ||||
|         format!( | ||||
|             "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:06}Z", | ||||
|             dt.year(), | ||||
|             dt.month(), | ||||
|             dt.day(), | ||||
|             dt.hour(), | ||||
|             dt.minute(), | ||||
|             dt.second(), | ||||
|             dt.timestamp_subsec_micros() | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(feature = "sqlite")] | ||||
|     pub(crate) fn format_datetime(dt: &NaiveDateTime) -> String { | ||||
|         format!( | ||||
|             "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z", | ||||
|             dt.year(), | ||||
|             dt.month(), | ||||
|             dt.day(), | ||||
|             dt.hour(), | ||||
|             dt.minute(), | ||||
|             dt.second() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub mod admin; | ||||
|  | ||||
| @ -165,8 +165,7 @@ impl AsObject<User, activity::Undo, &DbConn> for Like { | ||||
| 
 | ||||
| impl NewLike { | ||||
|     pub fn new(p: &Post, u: &User) -> Self { | ||||
|         // TODO: this URL is not valid
 | ||||
|         let ap_url = format!("{}/like/{}", u.ap_url, p.ap_url); | ||||
|         let ap_url = format!("{}like/{}", u.ap_url, p.ap_url); | ||||
|         NewLike { | ||||
|             post_id: p.id, | ||||
|             user_id: u.id, | ||||
| @ -174,3 +173,67 @@ impl NewLike { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use crate::diesel::Connection; | ||||
|     use crate::{inbox::tests::fill_database, tests::db}; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use serde_json::{json, to_value}; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (posts, _users, _blogs) = fill_database(&conn); | ||||
|             let post = &posts[0]; | ||||
|             let user = &post.get_authors(&conn)?[0]; | ||||
|             let like = Like::insert(&*conn, NewLike::new(post, user))?; | ||||
|             let act = like.to_activity(&conn).unwrap(); | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": ["https://plu.me/@/admin/followers"], | ||||
|                 "id": "https://plu.me/@/admin/like/https://plu.me/~/BlogName/testing", | ||||
|                 "object": "https://plu.me/~/BlogName/testing", | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Like", | ||||
|             }); | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn build_undo() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (posts, _users, _blogs) = fill_database(&conn); | ||||
|             let post = &posts[0]; | ||||
|             let user = &post.get_authors(&conn)?[0]; | ||||
|             let like = Like::insert(&*conn, NewLike::new(post, user))?; | ||||
|             let act = like.build_undo(&*conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": ["https://plu.me/@/admin/followers"], | ||||
|                 "id": "https://plu.me/@/admin/like/https://plu.me/~/BlogName/testing#delete", | ||||
|                 "object": { | ||||
|                     "actor": "https://plu.me/@/admin/", | ||||
|                     "cc": ["https://plu.me/@/admin/followers"], | ||||
|                     "id": "https://plu.me/@/admin/like/https://plu.me/~/BlogName/testing", | ||||
|                     "object": "https://plu.me/~/BlogName/testing", | ||||
|                     "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "type": "Like", | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Undo", | ||||
|             }); | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -400,7 +400,15 @@ pub(crate) mod tests { | ||||
|     pub(crate) fn clean(conn: &Conn) { | ||||
|         //used to remove files generated by tests
 | ||||
|         for media in Media::list_all_medias(conn).unwrap() { | ||||
|             media.delete(conn).unwrap(); | ||||
|             if let Some(err) = media.delete(conn).err() { | ||||
|                 match &err { | ||||
|                     Error::Io(e) => match e.kind() { | ||||
|                         std::io::ErrorKind::NotFound => (), | ||||
|                         _ => panic!("{:?}", err), | ||||
|                     }, | ||||
|                     _ => panic!("{:?}", err), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -145,3 +145,62 @@ impl Mention { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use crate::{inbox::tests::fill_database, tests::db, Error}; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use diesel::Connection; | ||||
|     use serde_json::{json, to_value}; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn build_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (_posts, users, _blogs) = fill_database(&conn); | ||||
|             let user = &users[0]; | ||||
|             let name = &user.username; | ||||
|             let act = Mention::build_activity(&conn, name)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "href": "https://plu.me/@/admin/", | ||||
|                 "name": "@admin", | ||||
|                 "type": "Mention", | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (posts, users, _blogs) = fill_database(&conn); | ||||
|             let post = &posts[0]; | ||||
|             let user = &users[0]; | ||||
|             let mention = Mention::insert( | ||||
|                 &conn, | ||||
|                 NewMention { | ||||
|                     mentioned_id: user.id, | ||||
|                     post_id: Some(post.id), | ||||
|                     comment_id: None, | ||||
|                 }, | ||||
|             )?; | ||||
|             let act = mention.to_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "href": "https://plu.me/@/admin/", | ||||
|                 "name": "@admin", | ||||
|                 "type": "Mention", | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -413,7 +413,7 @@ impl Post { | ||||
|         let article = self.to_activity(conn)?; | ||||
|         let mut act = Create::default(); | ||||
|         act.object_props | ||||
|             .set_id_string(format!("{}activity", self.ap_url))?; | ||||
|             .set_id_string(format!("{}/activity", self.ap_url))?; | ||||
|         act.object_props | ||||
|             .set_to_link_vec::<Id>(article.object.object_props.to_link_vec()?)?; | ||||
|         act.object_props | ||||
| @ -942,9 +942,28 @@ impl From<PostEvent> for Arc<Post> { | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use crate::inbox::{inbox, tests::fill_database, InboxResult}; | ||||
|     use crate::mentions::{Mention, NewMention}; | ||||
|     use crate::safe_string::SafeString; | ||||
|     use crate::tests::db; | ||||
|     use crate::tests::{db, format_datetime}; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use diesel::Connection; | ||||
|     use serde_json::{json, to_value}; | ||||
| 
 | ||||
|     fn prepare_activity(conn: &DbConn) -> (Post, Mention, Vec<Post>, Vec<User>, Vec<Blog>) { | ||||
|         let (posts, users, blogs) = fill_database(conn); | ||||
|         let post = &posts[0]; | ||||
|         let mentioned = &users[1]; | ||||
|         let mention = Mention::insert( | ||||
|             &conn, | ||||
|             NewMention { | ||||
|                 mentioned_id: mentioned.id, | ||||
|                 post_id: Some(post.id), | ||||
|                 comment_id: None, | ||||
|             }, | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         (post.to_owned(), mention.to_owned(), posts, users, blogs) | ||||
|     } | ||||
| 
 | ||||
|     // creates a post, get it's Create activity, delete the post,
 | ||||
|     // "send" the Create to the inbox, and check it works
 | ||||
| @ -1038,4 +1057,153 @@ mod tests { | ||||
|             &article.object.object_props.id_string().unwrap() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (post, _mention, _posts, _users, _blogs) = prepare_activity(&conn); | ||||
|             let act = post.to_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "attributedTo": ["https://plu.me/@/admin/", "https://plu.me/~/BlogName/"], | ||||
|                 "cc": [], | ||||
|                 "content": "Hello", | ||||
|                 "id": "https://plu.me/~/BlogName/testing", | ||||
|                 "license": "WTFPL", | ||||
|                 "name": "Testing", | ||||
|                 "published": format_datetime(&post.creation_date), | ||||
|                 "source": { | ||||
|                     "content": "", | ||||
|                     "mediaType": "text/markdown" | ||||
|                 }, | ||||
|                 "summary": "", | ||||
|                 "tag": [ | ||||
|                     { | ||||
|                         "href": "https://plu.me/@/user/", | ||||
|                         "name": "@user", | ||||
|                         "type": "Mention" | ||||
|                     } | ||||
|                 ], | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Article", | ||||
|                 "url": "https://plu.me/~/BlogName/testing" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn create_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (post, _mention, _posts, _users, _blogs) = prepare_activity(&conn); | ||||
|             let act = post.create_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": [], | ||||
|                 "id": "https://plu.me/~/BlogName/testing/activity", | ||||
|                 "object": { | ||||
|                     "attributedTo": ["https://plu.me/@/admin/", "https://plu.me/~/BlogName/"], | ||||
|                     "cc": [], | ||||
|                     "content": "Hello", | ||||
|                     "id": "https://plu.me/~/BlogName/testing", | ||||
|                     "license": "WTFPL", | ||||
|                     "name": "Testing", | ||||
|                     "published": format_datetime(&post.creation_date), | ||||
|                     "source": { | ||||
|                         "content": "", | ||||
|                         "mediaType": "text/markdown" | ||||
|                     }, | ||||
|                     "summary": "", | ||||
|                     "tag": [ | ||||
|                         { | ||||
|                             "href": "https://plu.me/@/user/", | ||||
|                             "name": "@user", | ||||
|                             "type": "Mention" | ||||
|                         } | ||||
|                     ], | ||||
|                     "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "type": "Article", | ||||
|                     "url": "https://plu.me/~/BlogName/testing" | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Create" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn update_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (post, _mention, _posts, _users, _blogs) = prepare_activity(&conn); | ||||
|             let act = post.update_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": [], | ||||
|                 "id": "https://plu.me/~/BlogName/testing/update-", | ||||
|                 "object": { | ||||
|                     "attributedTo": ["https://plu.me/@/admin/", "https://plu.me/~/BlogName/"], | ||||
|                     "cc": [], | ||||
|                     "content": "Hello", | ||||
|                     "id": "https://plu.me/~/BlogName/testing", | ||||
|                     "license": "WTFPL", | ||||
|                     "name": "Testing", | ||||
|                     "published": format_datetime(&post.creation_date), | ||||
|                     "source": { | ||||
|                         "content": "", | ||||
|                         "mediaType": "text/markdown" | ||||
|                     }, | ||||
|                     "summary": "", | ||||
|                     "tag": [ | ||||
|                         { | ||||
|                             "href": "https://plu.me/@/user/", | ||||
|                             "name": "@user", | ||||
|                             "type": "Mention" | ||||
|                         } | ||||
|                     ], | ||||
|                     "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "type": "Article", | ||||
|                     "url": "https://plu.me/~/BlogName/testing" | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Update" | ||||
|             }); | ||||
|             let actual = to_value(act)?; | ||||
| 
 | ||||
|             let id = actual["id"].to_string(); | ||||
|             let (id_pre, id_post) = id.rsplit_once("-").unwrap(); | ||||
|             assert_eq!(post.ap_url, "https://plu.me/~/BlogName/testing"); | ||||
|             assert_eq!( | ||||
|                 id_pre, | ||||
|                 to_value("\"https://plu.me/~/BlogName/testing/update") | ||||
|                     .unwrap() | ||||
|                     .as_str() | ||||
|                     .unwrap() | ||||
|             ); | ||||
|             assert_eq!(id_post.len(), 11); | ||||
|             assert_eq!( | ||||
|                 id_post.matches(char::is_numeric).collect::<String>().len(), | ||||
|                 10 | ||||
|             ); | ||||
|             for (key, value) in actual.as_object().unwrap().into_iter() { | ||||
|                 if key == "id" { | ||||
|                     continue; | ||||
|                 } | ||||
|                 assert_eq!(value, expected.get(key).unwrap()); | ||||
|             } | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -191,7 +191,7 @@ impl AsObject<User, Undo, &DbConn> for Reshare { | ||||
| 
 | ||||
| impl NewReshare { | ||||
|     pub fn new(p: &Post, u: &User) -> Self { | ||||
|         let ap_url = format!("{}/reshare/{}", u.ap_url, p.ap_url); | ||||
|         let ap_url = format!("{}reshare/{}", u.ap_url, p.ap_url); | ||||
|         NewReshare { | ||||
|             post_id: p.id, | ||||
|             user_id: u.id, | ||||
| @ -199,3 +199,67 @@ impl NewReshare { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use super::*; | ||||
|     use crate::diesel::Connection; | ||||
|     use crate::{inbox::tests::fill_database, tests::db}; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use serde_json::{json, to_value}; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (posts, _users, _blogs) = fill_database(&conn); | ||||
|             let post = &posts[0]; | ||||
|             let user = &post.get_authors(&conn)?[0]; | ||||
|             let reshare = Reshare::insert(&*conn, NewReshare::new(post, user))?; | ||||
|             let act = reshare.to_activity(&conn).unwrap(); | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": ["https://plu.me/@/admin/followers"], | ||||
|                 "id": "https://plu.me/@/admin/reshare/https://plu.me/~/BlogName/testing", | ||||
|                 "object": "https://plu.me/~/BlogName/testing", | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Announce", | ||||
|             }); | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn build_undo() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (posts, _users, _blogs) = fill_database(&conn); | ||||
|             let post = &posts[0]; | ||||
|             let user = &post.get_authors(&conn)?[0]; | ||||
|             let reshare = Reshare::insert(&*conn, NewReshare::new(post, user))?; | ||||
|             let act = reshare.build_undo(&*conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/admin/", | ||||
|                 "cc": ["https://plu.me/@/admin/followers"], | ||||
|                 "id": "https://plu.me/@/admin/reshare/https://plu.me/~/BlogName/testing#delete", | ||||
|                 "object": { | ||||
|                     "actor": "https://plu.me/@/admin/", | ||||
|                     "cc": ["https://plu.me/@/admin/followers"], | ||||
|                     "id": "https://plu.me/@/admin/reshare/https://plu.me/~/BlogName/testing", | ||||
|                     "object": "https://plu.me/~/BlogName/testing", | ||||
|                     "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                     "type": "Announce" | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Undo", | ||||
|             }); | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -429,6 +429,9 @@ impl User { | ||||
|             .map_err(Error::from) | ||||
|     } | ||||
|     pub fn outbox(&self, conn: &Connection) -> Result<ActivityStream<OrderedCollection>> { | ||||
|         Ok(ActivityStream::new(self.outbox_collection(conn)?)) | ||||
|     } | ||||
|     pub fn outbox_collection(&self, conn: &Connection) -> Result<OrderedCollection> { | ||||
|         let mut coll = OrderedCollection::default(); | ||||
|         let first = &format!("{}?page=1", &self.outbox_url); | ||||
|         let last = &format!( | ||||
| @ -440,13 +443,22 @@ impl User { | ||||
|         coll.collection_props.set_last_link(Id::new(last))?; | ||||
|         coll.collection_props | ||||
|             .set_total_items_u64(self.get_activities_count(conn) as u64)?; | ||||
|         Ok(ActivityStream::new(coll)) | ||||
|         Ok(coll) | ||||
|     } | ||||
|     pub fn outbox_page( | ||||
|         &self, | ||||
|         conn: &Connection, | ||||
|         (min, max): (i32, i32), | ||||
|     ) -> Result<ActivityStream<OrderedCollectionPage>> { | ||||
|         Ok(ActivityStream::new( | ||||
|             self.outbox_collection_page(conn, (min, max))?, | ||||
|         )) | ||||
|     } | ||||
|     pub fn outbox_collection_page( | ||||
|         &self, | ||||
|         conn: &Connection, | ||||
|         (min, max): (i32, i32), | ||||
|     ) -> Result<OrderedCollectionPage> { | ||||
|         let acts = self.get_activities_page(conn, (min, max))?; | ||||
|         let n_acts = self.get_activities_count(conn); | ||||
|         let mut coll = OrderedCollectionPage::default(); | ||||
| @ -467,7 +479,7 @@ impl User { | ||||
|         coll.collection_props.items = serde_json::to_value(acts)?; | ||||
|         coll.collection_page_props | ||||
|             .set_part_of_link(Id::new(&self.outbox_url))?; | ||||
|         Ok(ActivityStream::new(coll)) | ||||
|         Ok(coll) | ||||
|     } | ||||
|     fn fetch_outbox_page<T: Activity>(&self, url: &str) -> Result<(Vec<T>, Option<String>)> { | ||||
|         let mut res = get(url, Self::get_sender(), CONFIG.proxy().cloned())?; | ||||
| @ -763,13 +775,13 @@ impl User { | ||||
|         let mut ap_signature = ApSignature::default(); | ||||
|         ap_signature.set_public_key_publickey(public_key)?; | ||||
| 
 | ||||
|         let mut avatar = Image::default(); | ||||
|         avatar.object_props.set_url_string( | ||||
|             self.avatar_id | ||||
|                 .and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok()) | ||||
|                 .unwrap_or_default(), | ||||
|         )?; | ||||
|         actor.object_props.set_icon_object(avatar)?; | ||||
|         if let Some(avatar_id) = self.avatar_id { | ||||
|             let mut avatar = Image::default(); | ||||
|             avatar | ||||
|                 .object_props | ||||
|                 .set_url_string(Media::get(conn, avatar_id)?.url()?)?; | ||||
|             actor.object_props.set_icon_object(avatar)?; | ||||
|         } | ||||
| 
 | ||||
|         Ok(CustomPerson::new(actor, ap_signature)) | ||||
|     } | ||||
| @ -1142,10 +1154,13 @@ pub(crate) mod tests { | ||||
|     use super::*; | ||||
|     use crate::{ | ||||
|         instance::{tests as instance_tests, Instance}, | ||||
|         medias::{Media, NewMedia}, | ||||
|         tests::db, | ||||
|         Connection as Conn, | ||||
|         Connection as Conn, ITEMS_PER_PAGE, | ||||
|     }; | ||||
|     use diesel::Connection; | ||||
|     use assert_json_diff::assert_json_eq; | ||||
|     use diesel::{Connection, SaveChangesDsl}; | ||||
|     use serde_json::to_value; | ||||
| 
 | ||||
|     pub(crate) fn fill_database(conn: &Conn) -> Vec<User> { | ||||
|         instance_tests::fill_database(conn); | ||||
| @ -1169,7 +1184,7 @@ pub(crate) mod tests { | ||||
|             Some("invalid_user_password".to_owned()), | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         let other = NewUser::new_local( | ||||
|         let mut other = NewUser::new_local( | ||||
|             conn, | ||||
|             "other".to_owned(), | ||||
|             "Another user".to_owned(), | ||||
| @ -1179,9 +1194,73 @@ pub(crate) mod tests { | ||||
|             Some("invalid_other_password".to_owned()), | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         let avatar = Media::insert( | ||||
|             conn, | ||||
|             NewMedia { | ||||
|                 file_path: "static/media/example.png".into(), | ||||
|                 alt_text: "Another user".into(), | ||||
|                 is_remote: false, | ||||
|                 remote_url: None, | ||||
|                 sensitive: false, | ||||
|                 content_warning: None, | ||||
|                 owner_id: other.id, | ||||
|             }, | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         other.avatar_id = Some(avatar.id); | ||||
|         let other = other.save_changes::<User>(&*conn).unwrap(); | ||||
| 
 | ||||
|         vec![admin, user, other] | ||||
|     } | ||||
| 
 | ||||
|     fn fill_pages( | ||||
|         conn: &DbConn, | ||||
|     ) -> ( | ||||
|         Vec<crate::posts::Post>, | ||||
|         Vec<crate::users::User>, | ||||
|         Vec<crate::blogs::Blog>, | ||||
|     ) { | ||||
|         use crate::post_authors::NewPostAuthor; | ||||
|         use crate::posts::NewPost; | ||||
| 
 | ||||
|         let (mut posts, users, blogs) = crate::inbox::tests::fill_database(conn); | ||||
|         let user = &users[0]; | ||||
|         let blog = &blogs[0]; | ||||
| 
 | ||||
|         for i in 1..(ITEMS_PER_PAGE * 4 + 3) { | ||||
|             let title = format!("Post {}", i); | ||||
|             let content = format!("Content for post {}.", i); | ||||
|             let post = Post::insert( | ||||
|                 conn, | ||||
|                 NewPost { | ||||
|                     blog_id: blog.id, | ||||
|                     slug: title.clone(), | ||||
|                     title: title.clone(), | ||||
|                     content: SafeString::new(&content), | ||||
|                     published: true, | ||||
|                     license: "CC-0".into(), | ||||
|                     creation_date: None, | ||||
|                     ap_url: format!("{}/{}", blog.ap_url, title), | ||||
|                     subtitle: "".into(), | ||||
|                     source: content, | ||||
|                     cover_id: None, | ||||
|                 }, | ||||
|             ) | ||||
|             .unwrap(); | ||||
|             PostAuthor::insert( | ||||
|                 conn, | ||||
|                 NewPostAuthor { | ||||
|                     post_id: post.id, | ||||
|                     author_id: user.id, | ||||
|                 }, | ||||
|             ) | ||||
|             .unwrap(); | ||||
|             posts.push(post); | ||||
|         } | ||||
| 
 | ||||
|         (posts, users, blogs) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn find_by() { | ||||
|         let conn = db(); | ||||
| @ -1342,4 +1421,139 @@ pub(crate) mod tests { | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn to_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let users = fill_database(&conn); | ||||
|             let user = &users[0]; | ||||
|             let act = user.to_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "endpoints": { | ||||
|                     "sharedInbox": "https://plu.me/inbox" | ||||
|                 }, | ||||
|                 "followers": "https://plu.me/@/admin/followers", | ||||
|                 "following": null, | ||||
|                 "id": "https://plu.me/@/admin/", | ||||
|                 "inbox": "https://plu.me/@/admin/inbox", | ||||
|                 "liked": null, | ||||
|                 "name": "The admin", | ||||
|                 "outbox": "https://plu.me/@/admin/outbox", | ||||
|                 "preferredUsername": "admin", | ||||
|                 "publicKey": { | ||||
|                     "id": "https://plu.me/@/admin/#main-key", | ||||
|                     "owner": "https://plu.me/@/admin/", | ||||
|                     "publicKeyPem": user.public_key, | ||||
|                 }, | ||||
|                 "summary": "<p dir=\"auto\">Hello there, I’m the admin</p>\n", | ||||
|                 "type": "Person", | ||||
|                 "url": "https://plu.me/@/admin/" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             let other = &users[2]; | ||||
|             let other_act = other.to_activity(&conn)?; | ||||
|             let expected_other = json!({ | ||||
|                 "endpoints": { | ||||
|                     "sharedInbox": "https://plu.me/inbox" | ||||
|                 }, | ||||
|                 "followers": "https://plu.me/@/other/followers", | ||||
|                 "following": null, | ||||
|                 "icon": { | ||||
|                     "url": "https://plu.me/static/media/example.png", | ||||
|                     "type": "Image", | ||||
|                 }, | ||||
|                 "id": "https://plu.me/@/other/", | ||||
|                 "inbox": "https://plu.me/@/other/inbox", | ||||
|                 "liked": null, | ||||
|                 "name": "Another user", | ||||
|                 "outbox": "https://plu.me/@/other/outbox", | ||||
|                 "preferredUsername": "other", | ||||
|                 "publicKey": { | ||||
|                     "id": "https://plu.me/@/other/#main-key", | ||||
|                     "owner": "https://plu.me/@/other/", | ||||
|                     "publicKeyPem": other.public_key, | ||||
|                 }, | ||||
|                 "summary": "<p dir=\"auto\">Hello there, I’m someone else</p>\n", | ||||
|                 "type": "Person", | ||||
|                 "url": "https://plu.me/@/other/" | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(other_act)?, expected_other); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn delete_activity() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let users = fill_database(&conn); | ||||
|             let user = &users[1]; | ||||
|             let act = user.delete_activity(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "actor": "https://plu.me/@/user/", | ||||
|                 "cc": [], | ||||
|                 "id": "https://plu.me/@/user/#delete", | ||||
|                 "object": { | ||||
|                     "id": "https://plu.me/@/user/", | ||||
|                     "type": "Tombstone", | ||||
|                 }, | ||||
|                 "to": ["https://www.w3.org/ns/activitystreams#Public"], | ||||
|                 "type": "Delete", | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn outbox_collection() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let (_pages, users, _blogs) = fill_pages(&conn); | ||||
|             let user = &users[0]; | ||||
|             let act = user.outbox_collection(&conn)?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "first": "https://plu.me/@/admin/outbox?page=1", | ||||
|                 "items": null, | ||||
|                 "last": "https://plu.me/@/admin/outbox?page=5", | ||||
|                 "totalItems": 51, | ||||
|                 "type": "OrderedCollection", | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn outbox_collection_page() { | ||||
|         let conn = db(); | ||||
|         conn.test_transaction::<_, Error, _>(|| { | ||||
|             let users = fill_database(&conn); | ||||
|             let user = &users[0]; | ||||
|             let act = user.outbox_collection_page(&conn, (33, 36))?; | ||||
| 
 | ||||
|             let expected = json!({ | ||||
|                 "items": [], | ||||
|                 "partOf": "https://plu.me/@/admin/outbox", | ||||
|                 "prev": "https://plu.me/@/admin/outbox?page=2", | ||||
|                 "type": "OrderedCollectionPage", | ||||
|             }); | ||||
| 
 | ||||
|             assert_json_eq!(to_value(act)?, expected); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user