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",
|
"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]]
|
[[package]]
|
||||||
name = "activitystreams-derive"
|
name = "activitystreams-derive"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -27,6 +42,16 @@ dependencies = [
|
|||||||
"syn 0.13.11",
|
"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]]
|
[[package]]
|
||||||
name = "activitystreams-traits"
|
name = "activitystreams-traits"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -205,6 +230,16 @@ version = "0.10.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5"
|
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]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.52"
|
version = "0.1.52"
|
||||||
@ -3136,6 +3171,7 @@ name = "plume-common"
|
|||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitypub",
|
"activitypub",
|
||||||
|
"activitystreams",
|
||||||
"activitystreams-derive",
|
"activitystreams-derive",
|
||||||
"activitystreams-traits",
|
"activitystreams-traits",
|
||||||
"array_tool",
|
"array_tool",
|
||||||
@ -3190,7 +3226,9 @@ name = "plume-models"
|
|||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitypub",
|
"activitypub",
|
||||||
|
"activitystreams",
|
||||||
"ammonia",
|
"ammonia",
|
||||||
|
"assert-json-diff",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
@ -5232,6 +5270,7 @@ dependencies = [
|
|||||||
"idna 0.2.3",
|
"idna 0.2.3",
|
||||||
"matches",
|
"matches",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
|
"serde 1.0.133",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -24,6 +24,7 @@ tokio = "0.1.22"
|
|||||||
regex-syntax = { version = "0.6.17", default-features = false, features = ["unicode-perl"] }
|
regex-syntax = { version = "0.6.17", default-features = false, features = ["unicode-perl"] }
|
||||||
tracing = "0.1.30"
|
tracing = "0.1.30"
|
||||||
askama_escape = "0.10.2"
|
askama_escape = "0.10.2"
|
||||||
|
activitystreams = "0.7.0-alpha.14"
|
||||||
|
|
||||||
[dependencies.chrono]
|
[dependencies.chrono]
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
|
@ -271,7 +271,7 @@ pub fn md_to_html<'a>(
|
|||||||
media_processor: Option<MediaProcessor<'a>>,
|
media_processor: Option<MediaProcessor<'a>>,
|
||||||
) -> (String, HashSet<String>, HashSet<String>) {
|
) -> (String, HashSet<String>, HashSet<String>) {
|
||||||
let base_url = if let Some(base_url) = base_url {
|
let base_url = if let Some(base_url) = base_url {
|
||||||
format!("//{}/", base_url)
|
format!("https://{}/", base_url)
|
||||||
} else {
|
} else {
|
||||||
"/".to_owned()
|
"/".to_owned()
|
||||||
};
|
};
|
||||||
|
@ -35,6 +35,7 @@ riker = "0.4.2"
|
|||||||
once_cell = "1.5.2"
|
once_cell = "1.5.2"
|
||||||
lettre = "0.9.6"
|
lettre = "0.9.6"
|
||||||
native-tls = "0.2.8"
|
native-tls = "0.2.8"
|
||||||
|
activitystreams = "0.7.0-alpha.14"
|
||||||
|
|
||||||
[dependencies.chrono]
|
[dependencies.chrono]
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
@ -54,6 +55,7 @@ path = "../plume-common"
|
|||||||
path = "../plume-macro"
|
path = "../plume-macro"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
assert-json-diff = "2.0.1"
|
||||||
diesel_migrations = "1.3.0"
|
diesel_migrations = "1.3.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -16,7 +16,7 @@ use activitypub::{
|
|||||||
link,
|
link,
|
||||||
object::{Note, Tombstone},
|
object::{Note, Tombstone},
|
||||||
};
|
};
|
||||||
use chrono::{self, NaiveDateTime};
|
use chrono::{self, NaiveDateTime, TimeZone, Utc};
|
||||||
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl};
|
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl};
|
||||||
use plume_common::{
|
use plume_common::{
|
||||||
activity_pub::{
|
activity_pub::{
|
||||||
@ -59,7 +59,7 @@ impl Comment {
|
|||||||
insert!(comments, NewComment, |inserted, conn| {
|
insert!(comments, NewComment, |inserted, conn| {
|
||||||
if inserted.ap_url.is_none() {
|
if inserted.ap_url.is_none() {
|
||||||
inserted.ap_url = Some(format!(
|
inserted.ap_url = Some(format!(
|
||||||
"{}comment/{}",
|
"{}/comment/{}",
|
||||||
inserted.get_post(conn)?.ap_url,
|
inserted.get_post(conn)?.ap_url,
|
||||||
inserted.id
|
inserted.id
|
||||||
));
|
));
|
||||||
@ -129,7 +129,7 @@ impl Comment {
|
|||||||
|id| Ok(Comment::get(conn, id)?.ap_url.unwrap_or_default()) as Result<String>,
|
|id| Ok(Comment::get(conn, id)?.ap_url.unwrap_or_default()) as Result<String>,
|
||||||
)?))?;
|
)?))?;
|
||||||
note.object_props
|
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_attributed_to_link(author.into_id())?;
|
||||||
note.object_props.set_to_link_vec(to)?;
|
note.object_props.set_to_link_vec(to)?;
|
||||||
note.object_props.set_tag_link_vec(
|
note.object_props.set_tag_link_vec(
|
||||||
@ -402,23 +402,21 @@ impl CommentTree {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::blogs::Blog;
|
||||||
use crate::inbox::{inbox, tests::fill_database, InboxResult};
|
use crate::inbox::{inbox, tests::fill_database, InboxResult};
|
||||||
use crate::safe_string::SafeString;
|
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 diesel::Connection;
|
||||||
|
use serde_json::{json, to_value};
|
||||||
|
|
||||||
// creates a post, get it's Create activity, delete the post,
|
fn prepare_activity(conn: &DbConn) -> (Comment, Vec<Post>, Vec<User>, Vec<Blog>) {
|
||||||
// "send" the Create to the inbox, and check it works
|
let (posts, users, blogs) = fill_database(&conn);
|
||||||
#[test]
|
|
||||||
fn self_federation() {
|
|
||||||
let conn = &db();
|
|
||||||
conn.test_transaction::<_, (), _>(|| {
|
|
||||||
let (posts, users, _) = fill_database(&conn);
|
|
||||||
|
|
||||||
let original_comm = Comment::insert(
|
let comment = Comment::insert(
|
||||||
conn,
|
conn,
|
||||||
NewComment {
|
NewComment {
|
||||||
content: SafeString::new("My comment"),
|
content: SafeString::new("My comment, mentioning to @user"),
|
||||||
in_response_to_id: None,
|
in_response_to_id: None,
|
||||||
post_id: posts[0].id,
|
post_id: posts[0].id,
|
||||||
author_id: users[0].id,
|
author_id: users[0].id,
|
||||||
@ -429,14 +427,87 @@ mod tests {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.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
|
||||||
|
#[test]
|
||||||
|
fn self_federation() {
|
||||||
|
let conn = &db();
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (original_comm, posts, users, _blogs) = prepare_activity(&conn);
|
||||||
let act = original_comm.create_activity(&conn).unwrap();
|
let act = original_comm.create_activity(&conn).unwrap();
|
||||||
|
|
||||||
|
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(""),
|
||||||
|
in_response_to_id: Some(original_comm.id),
|
||||||
|
post_id: posts[0].id,
|
||||||
|
author_id: users[1].id,
|
||||||
|
ap_url: None,
|
||||||
|
sensitive: false,
|
||||||
|
spoiler_text: "".into(),
|
||||||
|
public_visibility: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.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(
|
inbox(
|
||||||
&conn,
|
&conn,
|
||||||
serde_json::to_value(original_comm.build_delete(&conn).unwrap()).unwrap(),
|
serde_json::to_value(original_comm.build_delete(&conn).unwrap()).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match inbox(&conn, serde_json::to_value(act).unwrap()).unwrap() {
|
match inbox(&conn, to_value(act).unwrap()).unwrap() {
|
||||||
InboxResult::Commented(c) => {
|
InboxResult::Commented(c) => {
|
||||||
// TODO: one is HTML, the other markdown: assert_eq!(c.content, original_comm.content);
|
// 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);
|
assert_eq!(c.in_response_to_id, original_comm.in_response_to_id);
|
||||||
@ -451,4 +522,60 @@ mod tests {
|
|||||||
Ok(())
|
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)?;
|
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 mut accept = Accept::default();
|
||||||
let accept_id = ap_url(&format!(
|
let accept_id = ap_url(&format!(
|
||||||
"{}/follow/{}/accept",
|
"{}/follows/{}/accept",
|
||||||
CONFIG.base_url.as_str(),
|
CONFIG.base_url.as_str(),
|
||||||
&res.id
|
self.id
|
||||||
));
|
));
|
||||||
accept.object_props.set_id_string(accept_id)?;
|
accept.object_props.set_id_string(accept_id)?;
|
||||||
accept
|
accept
|
||||||
@ -116,13 +132,8 @@ impl Follow {
|
|||||||
.accept_props
|
.accept_props
|
||||||
.set_actor_link::<Id>(target.clone().into_id())?;
|
.set_actor_link::<Id>(target.clone().into_id())?;
|
||||||
accept.accept_props.set_object_object(follow)?;
|
accept.accept_props.set_object_object(follow)?;
|
||||||
broadcast(
|
|
||||||
&*target,
|
Ok(accept)
|
||||||
accept,
|
|
||||||
vec![from.clone()],
|
|
||||||
CONFIG.proxy().cloned(),
|
|
||||||
);
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_undo(&self, conn: &Connection) -> Result<Undo> {
|
pub fn build_undo(&self, conn: &Connection) -> Result<Undo> {
|
||||||
@ -219,8 +230,29 @@ impl IntoId for Follow {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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 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]
|
#[test]
|
||||||
fn test_id() {
|
fn test_id() {
|
||||||
@ -255,4 +287,77 @@ mod tests {
|
|||||||
Ok(())
|
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]
|
#[macro_use]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{db_conn, migrations::IMPORTED_MIGRATIONS, Connection as Conn, CONFIG};
|
use crate::{db_conn, migrations::IMPORTED_MIGRATIONS, Connection as Conn, CONFIG};
|
||||||
|
use chrono::{naive::NaiveDateTime, Datelike, Timelike};
|
||||||
use diesel::r2d2::ConnectionManager;
|
use diesel::r2d2::ConnectionManager;
|
||||||
use plume_common::utils::random_hex;
|
use plume_common::utils::random_hex;
|
||||||
use std::env::temp_dir;
|
use std::env::temp_dir;
|
||||||
@ -366,6 +367,33 @@ mod tests {
|
|||||||
pool
|
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;
|
pub mod admin;
|
||||||
|
@ -165,8 +165,7 @@ impl AsObject<User, activity::Undo, &DbConn> for Like {
|
|||||||
|
|
||||||
impl NewLike {
|
impl NewLike {
|
||||||
pub fn new(p: &Post, u: &User) -> Self {
|
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 {
|
NewLike {
|
||||||
post_id: p.id,
|
post_id: p.id,
|
||||||
user_id: u.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) {
|
pub(crate) fn clean(conn: &Conn) {
|
||||||
//used to remove files generated by tests
|
//used to remove files generated by tests
|
||||||
for media in Media::list_all_medias(conn).unwrap() {
|
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 article = self.to_activity(conn)?;
|
||||||
let mut act = Create::default();
|
let mut act = Create::default();
|
||||||
act.object_props
|
act.object_props
|
||||||
.set_id_string(format!("{}activity", self.ap_url))?;
|
.set_id_string(format!("{}/activity", self.ap_url))?;
|
||||||
act.object_props
|
act.object_props
|
||||||
.set_to_link_vec::<Id>(article.object.object_props.to_link_vec()?)?;
|
.set_to_link_vec::<Id>(article.object.object_props.to_link_vec()?)?;
|
||||||
act.object_props
|
act.object_props
|
||||||
@ -942,9 +942,28 @@ impl From<PostEvent> for Arc<Post> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::inbox::{inbox, tests::fill_database, InboxResult};
|
use crate::inbox::{inbox, tests::fill_database, InboxResult};
|
||||||
|
use crate::mentions::{Mention, NewMention};
|
||||||
use crate::safe_string::SafeString;
|
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 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,
|
// creates a post, get it's Create activity, delete the post,
|
||||||
// "send" the Create to the inbox, and check it works
|
// "send" the Create to the inbox, and check it works
|
||||||
@ -1038,4 +1057,153 @@ mod tests {
|
|||||||
&article.object.object_props.id_string().unwrap()
|
&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 {
|
impl NewReshare {
|
||||||
pub fn new(p: &Post, u: &User) -> Self {
|
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 {
|
NewReshare {
|
||||||
post_id: p.id,
|
post_id: p.id,
|
||||||
user_id: u.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)
|
.map_err(Error::from)
|
||||||
}
|
}
|
||||||
pub fn outbox(&self, conn: &Connection) -> Result<ActivityStream<OrderedCollection>> {
|
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 mut coll = OrderedCollection::default();
|
||||||
let first = &format!("{}?page=1", &self.outbox_url);
|
let first = &format!("{}?page=1", &self.outbox_url);
|
||||||
let last = &format!(
|
let last = &format!(
|
||||||
@ -440,13 +443,22 @@ impl User {
|
|||||||
coll.collection_props.set_last_link(Id::new(last))?;
|
coll.collection_props.set_last_link(Id::new(last))?;
|
||||||
coll.collection_props
|
coll.collection_props
|
||||||
.set_total_items_u64(self.get_activities_count(conn) as u64)?;
|
.set_total_items_u64(self.get_activities_count(conn) as u64)?;
|
||||||
Ok(ActivityStream::new(coll))
|
Ok(coll)
|
||||||
}
|
}
|
||||||
pub fn outbox_page(
|
pub fn outbox_page(
|
||||||
&self,
|
&self,
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
(min, max): (i32, i32),
|
(min, max): (i32, i32),
|
||||||
) -> Result<ActivityStream<OrderedCollectionPage>> {
|
) -> 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 acts = self.get_activities_page(conn, (min, max))?;
|
||||||
let n_acts = self.get_activities_count(conn);
|
let n_acts = self.get_activities_count(conn);
|
||||||
let mut coll = OrderedCollectionPage::default();
|
let mut coll = OrderedCollectionPage::default();
|
||||||
@ -467,7 +479,7 @@ impl User {
|
|||||||
coll.collection_props.items = serde_json::to_value(acts)?;
|
coll.collection_props.items = serde_json::to_value(acts)?;
|
||||||
coll.collection_page_props
|
coll.collection_page_props
|
||||||
.set_part_of_link(Id::new(&self.outbox_url))?;
|
.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>)> {
|
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())?;
|
let mut res = get(url, Self::get_sender(), CONFIG.proxy().cloned())?;
|
||||||
@ -763,13 +775,13 @@ impl User {
|
|||||||
let mut ap_signature = ApSignature::default();
|
let mut ap_signature = ApSignature::default();
|
||||||
ap_signature.set_public_key_publickey(public_key)?;
|
ap_signature.set_public_key_publickey(public_key)?;
|
||||||
|
|
||||||
|
if let Some(avatar_id) = self.avatar_id {
|
||||||
let mut avatar = Image::default();
|
let mut avatar = Image::default();
|
||||||
avatar.object_props.set_url_string(
|
avatar
|
||||||
self.avatar_id
|
.object_props
|
||||||
.and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok())
|
.set_url_string(Media::get(conn, avatar_id)?.url()?)?;
|
||||||
.unwrap_or_default(),
|
|
||||||
)?;
|
|
||||||
actor.object_props.set_icon_object(avatar)?;
|
actor.object_props.set_icon_object(avatar)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(CustomPerson::new(actor, ap_signature))
|
Ok(CustomPerson::new(actor, ap_signature))
|
||||||
}
|
}
|
||||||
@ -1142,10 +1154,13 @@ pub(crate) mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
instance::{tests as instance_tests, Instance},
|
instance::{tests as instance_tests, Instance},
|
||||||
|
medias::{Media, NewMedia},
|
||||||
tests::db,
|
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> {
|
pub(crate) fn fill_database(conn: &Conn) -> Vec<User> {
|
||||||
instance_tests::fill_database(conn);
|
instance_tests::fill_database(conn);
|
||||||
@ -1169,7 +1184,7 @@ pub(crate) mod tests {
|
|||||||
Some("invalid_user_password".to_owned()),
|
Some("invalid_user_password".to_owned()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let other = NewUser::new_local(
|
let mut other = NewUser::new_local(
|
||||||
conn,
|
conn,
|
||||||
"other".to_owned(),
|
"other".to_owned(),
|
||||||
"Another user".to_owned(),
|
"Another user".to_owned(),
|
||||||
@ -1179,9 +1194,73 @@ pub(crate) mod tests {
|
|||||||
Some("invalid_other_password".to_owned()),
|
Some("invalid_other_password".to_owned()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.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]
|
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]
|
#[test]
|
||||||
fn find_by() {
|
fn find_by() {
|
||||||
let conn = db();
|
let conn = db();
|
||||||
@ -1342,4 +1421,139 @@ pub(crate) mod tests {
|
|||||||
Ok(())
|
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…
Reference in New Issue
Block a user