Mention all subscribers when creating subscribers-only post
This commit is contained in:
parent
5122fe2b78
commit
9f3b95c41d
5 changed files with 27 additions and 42 deletions
|
@ -20,7 +20,6 @@ use crate::errors::DatabaseError;
|
||||||
use crate::frontend::get_tag_page_url;
|
use crate::frontend::get_tag_page_url;
|
||||||
use crate::models::posts::queries::get_post_author;
|
use crate::models::posts::queries::get_post_author;
|
||||||
use crate::models::posts::types::{Post, Visibility};
|
use crate::models::posts::types::{Post, Visibility};
|
||||||
use crate::models::profiles::types::DbActorProfile;
|
|
||||||
use crate::models::relationships::queries::{get_followers, get_subscribers};
|
use crate::models::relationships::queries::{get_followers, get_subscribers};
|
||||||
use crate::models::users::types::User;
|
use crate::models::users::types::User;
|
||||||
use crate::utils::files::get_file_url;
|
use crate::utils::files::get_file_url;
|
||||||
|
@ -59,7 +58,6 @@ pub fn build_note(
|
||||||
instance_host: &str,
|
instance_host: &str,
|
||||||
instance_url: &str,
|
instance_url: &str,
|
||||||
post: &Post,
|
post: &Post,
|
||||||
subscribers: Vec<DbActorProfile>,
|
|
||||||
) -> Note {
|
) -> Note {
|
||||||
let object_id = local_object_id(instance_url, &post.id);
|
let object_id = local_object_id(instance_url, &post.id);
|
||||||
let actor_id = local_actor_id(instance_url, &post.author.username);
|
let actor_id = local_actor_id(instance_url, &post.author.username);
|
||||||
|
@ -95,13 +93,7 @@ pub fn build_note(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tags = vec![];
|
let mut tags = vec![];
|
||||||
let mut mentions = post.mentions.clone();
|
for profile in &post.mentions {
|
||||||
if post.visibility == Visibility::Subscribers {
|
|
||||||
// Mention all subscribers
|
|
||||||
// (for recipients that don't support subscribers-only posts)
|
|
||||||
mentions.extend(subscribers);
|
|
||||||
};
|
|
||||||
for profile in mentions {
|
|
||||||
let tag_name = format!("@{}", profile.actor_address(instance_host));
|
let tag_name = format!("@{}", profile.actor_address(instance_host));
|
||||||
let actor_id = profile.actor_id(instance_url);
|
let actor_id = profile.actor_id(instance_url);
|
||||||
if !primary_audience.contains(&actor_id) {
|
if !primary_audience.contains(&actor_id) {
|
||||||
|
@ -154,9 +146,8 @@ pub fn build_create_note(
|
||||||
instance_host: &str,
|
instance_host: &str,
|
||||||
instance_url: &str,
|
instance_url: &str,
|
||||||
post: &Post,
|
post: &Post,
|
||||||
subscribers: Vec<DbActorProfile>,
|
|
||||||
) -> Activity {
|
) -> Activity {
|
||||||
let object = build_note(instance_host, instance_url, post, subscribers);
|
let object = build_note(instance_host, instance_url, post);
|
||||||
let primary_audience = object.to.clone();
|
let primary_audience = object.to.clone();
|
||||||
let secondary_audience = object.cc.clone();
|
let secondary_audience = object.cc.clone();
|
||||||
let activity_id = format!("{}/create", object.id);
|
let activity_id = format!("{}/create", object.id);
|
||||||
|
@ -212,16 +203,10 @@ pub async fn prepare_create_note(
|
||||||
post: &Post,
|
post: &Post,
|
||||||
) -> Result<OutgoingActivity<Activity>, DatabaseError> {
|
) -> Result<OutgoingActivity<Activity>, DatabaseError> {
|
||||||
assert_eq!(author.id, post.author.id);
|
assert_eq!(author.id, post.author.id);
|
||||||
let subscribers = if post.visibility == Visibility::Subscribers {
|
|
||||||
get_subscribers(db_client, &author.id).await?
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
let activity = build_create_note(
|
let activity = build_create_note(
|
||||||
&instance.host(),
|
&instance.host(),
|
||||||
&instance.url(),
|
&instance.url(),
|
||||||
post,
|
post,
|
||||||
subscribers,
|
|
||||||
);
|
);
|
||||||
let recipients = get_note_recipients(db_client, author, post).await?;
|
let recipients = get_note_recipients(db_client, author, post).await?;
|
||||||
Ok(OutgoingActivity {
|
Ok(OutgoingActivity {
|
||||||
|
@ -235,6 +220,7 @@ pub async fn prepare_create_note(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use crate::models::profiles::types::DbActorProfile;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const INSTANCE_HOST: &str = "example.com";
|
const INSTANCE_HOST: &str = "example.com";
|
||||||
|
@ -247,7 +233,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let post = Post { author, ..Default::default() };
|
let post = Post { author, ..Default::default() };
|
||||||
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post, vec![]);
|
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
note.id,
|
note.id,
|
||||||
|
@ -272,7 +258,7 @@ mod tests {
|
||||||
visibility: Visibility::Followers,
|
visibility: Visibility::Followers,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post, vec![]);
|
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post);
|
||||||
|
|
||||||
assert_eq!(note.to, vec![
|
assert_eq!(note.to, vec![
|
||||||
local_actor_followers(INSTANCE_URL, &post.author.username),
|
local_actor_followers(INSTANCE_URL, &post.author.username),
|
||||||
|
@ -282,10 +268,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_note_subscribers_only() {
|
fn test_build_note_subscribers_only() {
|
||||||
let post = Post {
|
|
||||||
visibility: Visibility::Subscribers,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let subscriber_id = "https://test.com/users/3";
|
let subscriber_id = "https://test.com/users/3";
|
||||||
let subscriber = DbActorProfile {
|
let subscriber = DbActorProfile {
|
||||||
username: "subscriber".to_string(),
|
username: "subscriber".to_string(),
|
||||||
|
@ -296,7 +278,12 @@ mod tests {
|
||||||
actor_id: Some(subscriber_id.to_string()),
|
actor_id: Some(subscriber_id.to_string()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post, vec![subscriber]);
|
let post = Post {
|
||||||
|
visibility: Visibility::Subscribers,
|
||||||
|
mentions: vec![subscriber],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post);
|
||||||
|
|
||||||
assert_eq!(note.to, vec![
|
assert_eq!(note.to, vec![
|
||||||
local_actor_subscribers(INSTANCE_URL, &post.author.username),
|
local_actor_subscribers(INSTANCE_URL, &post.author.username),
|
||||||
|
@ -322,7 +309,7 @@ mod tests {
|
||||||
mentions: vec![mentioned],
|
mentions: vec![mentioned],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post, vec![]);
|
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post);
|
||||||
|
|
||||||
assert_eq!(note.to, vec![mentioned_id]);
|
assert_eq!(note.to, vec![mentioned_id]);
|
||||||
assert_eq!(note.cc.is_empty(), true);
|
assert_eq!(note.cc.is_empty(), true);
|
||||||
|
@ -336,7 +323,7 @@ mod tests {
|
||||||
in_reply_to: Some(Box::new(parent.clone())),
|
in_reply_to: Some(Box::new(parent.clone())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post, vec![]);
|
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
note.in_reply_to.unwrap(),
|
note.in_reply_to.unwrap(),
|
||||||
|
@ -374,7 +361,7 @@ mod tests {
|
||||||
mentions: vec![parent_author],
|
mentions: vec![parent_author],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post, vec![]);
|
let note = build_note(INSTANCE_HOST, INSTANCE_URL, &post);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
note.in_reply_to.unwrap(),
|
note.in_reply_to.unwrap(),
|
||||||
|
@ -399,7 +386,6 @@ mod tests {
|
||||||
INSTANCE_HOST,
|
INSTANCE_HOST,
|
||||||
INSTANCE_URL,
|
INSTANCE_URL,
|
||||||
&post,
|
&post,
|
||||||
vec![],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -7,9 +7,7 @@ use crate::activitypub::deliverer::OutgoingActivity;
|
||||||
use crate::activitypub::vocabulary::{DELETE, NOTE, TOMBSTONE};
|
use crate::activitypub::vocabulary::{DELETE, NOTE, TOMBSTONE};
|
||||||
use crate::config::Instance;
|
use crate::config::Instance;
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::models::posts::types::{Post, Visibility};
|
use crate::models::posts::types::Post;
|
||||||
use crate::models::profiles::types::DbActorProfile;
|
|
||||||
use crate::models::relationships::queries::get_subscribers;
|
|
||||||
use crate::models::users::types::User;
|
use crate::models::users::types::User;
|
||||||
use super::create_note::{
|
use super::create_note::{
|
||||||
build_note,
|
build_note,
|
||||||
|
@ -21,7 +19,6 @@ fn build_delete_note(
|
||||||
instance_host: &str,
|
instance_host: &str,
|
||||||
instance_url: &str,
|
instance_url: &str,
|
||||||
post: &Post,
|
post: &Post,
|
||||||
subscribers: Vec<DbActorProfile>,
|
|
||||||
) -> Activity {
|
) -> Activity {
|
||||||
let object_id = post.get_object_id(instance_url);
|
let object_id = post.get_object_id(instance_url);
|
||||||
let object = Object {
|
let object = Object {
|
||||||
|
@ -36,7 +33,6 @@ fn build_delete_note(
|
||||||
instance_host,
|
instance_host,
|
||||||
instance_url,
|
instance_url,
|
||||||
post,
|
post,
|
||||||
subscribers,
|
|
||||||
);
|
);
|
||||||
let activity = create_activity(
|
let activity = create_activity(
|
||||||
instance_url,
|
instance_url,
|
||||||
|
@ -57,16 +53,10 @@ pub async fn prepare_delete_note(
|
||||||
post: &Post,
|
post: &Post,
|
||||||
) -> Result<OutgoingActivity<Activity>, DatabaseError> {
|
) -> Result<OutgoingActivity<Activity>, DatabaseError> {
|
||||||
assert_eq!(author.id, post.author.id);
|
assert_eq!(author.id, post.author.id);
|
||||||
let subscribers = if post.visibility == Visibility::Subscribers {
|
|
||||||
get_subscribers(db_client, &author.id).await?
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
let activity = build_delete_note(
|
let activity = build_delete_note(
|
||||||
&instance.host(),
|
&instance.host(),
|
||||||
&instance.url(),
|
&instance.url(),
|
||||||
post,
|
post,
|
||||||
subscribers,
|
|
||||||
);
|
);
|
||||||
let recipients = get_note_recipients(db_client, author, post).await?;
|
let recipients = get_note_recipients(db_client, author, post).await?;
|
||||||
Ok(OutgoingActivity {
|
Ok(OutgoingActivity {
|
||||||
|
@ -84,6 +74,7 @@ mod tests {
|
||||||
constants::AP_PUBLIC,
|
constants::AP_PUBLIC,
|
||||||
identifiers::local_actor_followers,
|
identifiers::local_actor_followers,
|
||||||
};
|
};
|
||||||
|
use crate::models::profiles::types::DbActorProfile;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const INSTANCE_HOST: &str = "example.com";
|
const INSTANCE_HOST: &str = "example.com";
|
||||||
|
@ -100,7 +91,6 @@ mod tests {
|
||||||
INSTANCE_HOST,
|
INSTANCE_HOST,
|
||||||
INSTANCE_URL,
|
INSTANCE_URL,
|
||||||
&post,
|
&post,
|
||||||
vec![],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -146,7 +146,6 @@ async fn outbox(
|
||||||
&instance.host(),
|
&instance.host(),
|
||||||
&instance.url(),
|
&instance.url(),
|
||||||
post,
|
post,
|
||||||
vec![], // subscribers-only posts are not included
|
|
||||||
);
|
);
|
||||||
Some(activity)
|
Some(activity)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
@ -300,7 +299,6 @@ pub async fn object_view(
|
||||||
&config.instance().host(),
|
&config.instance().host(),
|
||||||
&config.instance().url(),
|
&config.instance().url(),
|
||||||
&post,
|
&post,
|
||||||
vec![], // subscribers-only posts are not accessible
|
|
||||||
);
|
);
|
||||||
let response = HttpResponse::Ok()
|
let response = HttpResponse::Ok()
|
||||||
.content_type(ACTIVITY_CONTENT_TYPE)
|
.content_type(ACTIVITY_CONTENT_TYPE)
|
||||||
|
|
|
@ -38,6 +38,7 @@ use crate::models::reactions::queries::{
|
||||||
create_reaction,
|
create_reaction,
|
||||||
delete_reaction,
|
delete_reaction,
|
||||||
};
|
};
|
||||||
|
use crate::models::relationships::queries::get_subscribers;
|
||||||
use crate::utils::currencies::Currency;
|
use crate::utils::currencies::Currency;
|
||||||
use super::helpers::{
|
use super::helpers::{
|
||||||
build_status,
|
build_status,
|
||||||
|
@ -71,6 +72,15 @@ async fn create_status(
|
||||||
);
|
);
|
||||||
post_data.mentions.extend(mention_map.values()
|
post_data.mentions.extend(mention_map.values()
|
||||||
.map(|profile| profile.id));
|
.map(|profile| profile.id));
|
||||||
|
if post_data.visibility == Visibility::Subscribers {
|
||||||
|
// Mention all subscribers.
|
||||||
|
// This makes post accessible only to active subscribers
|
||||||
|
// and is required for sending activities to subscribers
|
||||||
|
// on other instances.
|
||||||
|
let subscribers = get_subscribers(db_client, ¤t_user.id).await?
|
||||||
|
.into_iter().map(|profile| profile.id);
|
||||||
|
post_data.mentions.extend(subscribers);
|
||||||
|
};
|
||||||
post_data.mentions.sort();
|
post_data.mentions.sort();
|
||||||
post_data.mentions.dedup();
|
post_data.mentions.dedup();
|
||||||
// Hashtags
|
// Hashtags
|
||||||
|
|
|
@ -263,6 +263,7 @@ fn build_visibility_filter() -> String {
|
||||||
AND target_id = post.author_id
|
AND target_id = post.author_id
|
||||||
AND relationship_type = {relationship_follow}
|
AND relationship_type = {relationship_follow}
|
||||||
)
|
)
|
||||||
|
-- TODO: remove and rely on mentions instead
|
||||||
OR post.visibility = {visibility_subscribers} AND EXISTS (
|
OR post.visibility = {visibility_subscribers} AND EXISTS (
|
||||||
SELECT 1 FROM relationship
|
SELECT 1 FROM relationship
|
||||||
WHERE
|
WHERE
|
||||||
|
|
Loading…
Reference in a new issue