summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-05-03 10:00:59 -0400
committerDessalines <tyhou13@gmx.com>2020-05-03 10:00:59 -0400
commita09c818746f159bbc7ece19ee263607002dbb6a5 (patch)
tree78f30d4b861dbd8b60ad7d25fc8ed9af6a5c0de2
parent5366797a4b14634f1cfee183b8b8309efd457f46 (diff)
Adding federated mod remove actions.
-rw-r--r--server/src/api/comment.rs6
-rw-r--r--server/src/api/community.rs6
-rw-r--r--server/src/api/post.rs6
-rw-r--r--server/src/apub/comment.rs93
-rw-r--r--server/src/apub/community.rs96
-rw-r--r--server/src/apub/fetcher.rs39
-rw-r--r--server/src/apub/mod.rs16
-rw-r--r--server/src/apub/post.rs86
-rw-r--r--server/src/apub/shared_inbox.rs472
-rw-r--r--server/src/apub/user.rs8
-rw-r--r--ui/src/api_tests/api.spec.ts276
11 files changed, 1079 insertions, 25 deletions
diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs
index 1ecedb2c..2853beb3 100644
--- a/server/src/api/comment.rs
+++ b/server/src/api/comment.rs
@@ -343,6 +343,12 @@ impl Perform for Oper<EditComment> {
} else {
updated_comment.send_undo_delete(&user, &conn)?;
}
+ } else if let Some(removed) = data.removed.to_owned() {
+ if removed {
+ updated_comment.send_remove(&user, &conn)?;
+ } else {
+ updated_comment.send_undo_remove(&user, &conn)?;
+ }
} else {
updated_comment.send_update(&user, &conn)?;
}
diff --git a/server/src/api/community.rs b/server/src/api/community.rs
index 71da6712..9659469b 100644
--- a/server/src/api/community.rs
+++ b/server/src/api/community.rs
@@ -386,6 +386,12 @@ impl Perform for Oper<EditCommunity> {
} else {
updated_community.send_undo_delete(&user, &conn)?;
}
+ } else if let Some(removed) = data.removed.to_owned() {
+ if removed {
+ updated_community.send_remove(&user, &conn)?;
+ } else {
+ updated_community.send_undo_remove(&user, &conn)?;
+ }
}
let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
diff --git a/server/src/api/post.rs b/server/src/api/post.rs
index 55e0612f..b9c4c083 100644
--- a/server/src/api/post.rs
+++ b/server/src/api/post.rs
@@ -547,6 +547,12 @@ impl Perform for Oper<EditPost> {
} else {
updated_post.send_undo_delete(&user, &conn)?;
}
+ } else if let Some(removed) = data.removed.to_owned() {
+ if removed {
+ updated_post.send_remove(&user, &conn)?;
+ } else {
+ updated_post.send_undo_remove(&user, &conn)?;
+ }
} else {
updated_post.send_update(&user, &conn)?;
}
diff --git a/server/src/apub/comment.rs b/server/src/apub/comment.rs
index 65dd3c19..87258275 100644
--- a/server/src/apub/comment.rs
+++ b/server/src/apub/comment.rs
@@ -187,7 +187,7 @@ impl ApubObjectType for Comment {
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
- user_id: self.creator_id,
+ user_id: creator.id,
data: serde_json::to_value(&delete)?,
local: true,
updated: None,
@@ -240,7 +240,7 @@ impl ApubObjectType for Comment {
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
- user_id: self.creator_id,
+ user_id: creator.id,
data: serde_json::to_value(&undo)?,
local: true,
updated: None,
@@ -255,6 +255,95 @@ impl ApubObjectType for Comment {
)?;
Ok(())
}
+
+ fn send_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error> {
+ let note = self.to_apub(&conn)?;
+ let post = Post::read(&conn, self.post_id)?;
+ let community = Community::read(&conn, post.community_id)?;
+ let id = format!("{}/remove/{}", self.ap_id, uuid::Uuid::new_v4());
+ let mut remove = Remove::default();
+
+ populate_object_props(
+ &mut remove.object_props,
+ &community.get_followers_url(),
+ &id,
+ )?;
+
+ remove
+ .remove_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(note)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ send_activity(
+ &remove,
+ &mod_.private_key.as_ref().unwrap(),
+ &mod_.actor_id,
+ community.get_follower_inboxes(&conn)?,
+ )?;
+ Ok(())
+ }
+
+ fn send_undo_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error> {
+ let note = self.to_apub(&conn)?;
+ let post = Post::read(&conn, self.post_id)?;
+ let community = Community::read(&conn, post.community_id)?;
+
+ // Generate a fake delete activity, with the correct object
+ let id = format!("{}/remove/{}", self.ap_id, uuid::Uuid::new_v4());
+ let mut remove = Remove::default();
+
+ populate_object_props(
+ &mut remove.object_props,
+ &community.get_followers_url(),
+ &id,
+ )?;
+
+ remove
+ .remove_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(note)?;
+
+ // Undo that fake activity
+ let undo_id = format!("{}/undo/remove/{}", self.ap_id, uuid::Uuid::new_v4());
+ let mut undo = Undo::default();
+
+ populate_object_props(
+ &mut undo.object_props,
+ &community.get_followers_url(),
+ &undo_id,
+ )?;
+
+ undo
+ .undo_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(remove)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&undo)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ send_activity(
+ &undo,
+ &mod_.private_key.as_ref().unwrap(),
+ &mod_.actor_id,
+ community.get_follower_inboxes(&conn)?,
+ )?;
+ Ok(())
+ }
}
impl ApubLikeableType for Comment {
diff --git a/server/src/apub/community.rs b/server/src/apub/community.rs
index c4d9bf83..3510fbff 100644
--- a/server/src/apub/community.rs
+++ b/server/src/apub/community.rs
@@ -14,13 +14,21 @@ impl ToApub for Community {
let mut group = Group::default();
let oprops: &mut ObjectProperties = group.as_mut();
- let creator = User_::read(conn, self.creator_id)?;
+ // The attributed to, is an ordered vector with the creator actor_ids first,
+ // then the rest of the moderators
+ // TODO Technically the instance admins can mod the community, but lets
+ // ignore that for now
+ let moderators = CommunityModeratorView::for_community(&conn, self.id)?
+ .into_iter()
+ .map(|m| m.user_actor_id)
+ .collect();
+
oprops
.set_context_xsd_any_uri(context())?
.set_id(self.actor_id.to_owned())?
.set_name_xsd_string(self.name.to_owned())?
.set_published(convert_datetime(self.published))?
- .set_attributed_to_xsd_any_uri(creator.actor_id)?;
+ .set_many_attributed_to_xsd_any_uris(moderators)?;
if let Some(u) = self.updated.to_owned() {
oprops.set_updated(convert_datetime(u))?;
@@ -181,6 +189,83 @@ impl ActorType for Community {
Ok(())
}
+ fn send_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error> {
+ let group = self.to_apub(conn)?;
+ let id = format!("{}/remove/{}", self.actor_id, uuid::Uuid::new_v4());
+
+ let mut remove = Remove::default();
+ populate_object_props(&mut remove.object_props, &self.get_followers_url(), &id)?;
+
+ remove
+ .remove_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(group)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ // Note: For an accept, since it was automatic, no one pushed a button,
+ // the community was the actor.
+ // But for delete, the creator is the actor, and does the signing
+ send_activity(
+ &remove,
+ &mod_.private_key.as_ref().unwrap(),
+ &mod_.actor_id,
+ self.get_follower_inboxes(&conn)?,
+ )?;
+ Ok(())
+ }
+
+ fn send_undo_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error> {
+ let group = self.to_apub(conn)?;
+ let id = format!("{}/remove/{}", self.actor_id, uuid::Uuid::new_v4());
+
+ let mut remove = Remove::default();
+ populate_object_props(&mut remove.object_props, &self.get_followers_url(), &id)?;
+
+ remove
+ .remove_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(group)?;
+
+ // Undo that fake activity
+ let undo_id = format!("{}/undo/remove/{}", self.actor_id, uuid::Uuid::new_v4());
+ let mut undo = Undo::default();
+
+ populate_object_props(&mut undo.object_props, &self.get_followers_url(), &undo_id)?;
+
+ undo
+ .undo_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(remove)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&undo)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ // Note: For an accept, since it was automatic, no one pushed a button,
+ // the community was the actor.
+ // But for remove , the creator is the actor, and does the signing
+ send_activity(
+ &undo,
+ &mod_.private_key.as_ref().unwrap(),
+ &mod_.actor_id,
+ self.get_follower_inboxes(&conn)?,
+ )?;
+ Ok(())
+ }
+
/// For a given community, returns the inboxes of all followers.
fn get_follower_inboxes(&self, conn: &PgConnection) -> Result<Vec<String>, Error> {
Ok(
@@ -220,8 +305,11 @@ impl FromApub for CommunityForm {
// TODO don't do extra fetching here
// let _outbox = fetch_remote_object::<OrderedCollection>(&outbox_uri)?;
// let _followers = fetch_remote_object::<UnorderedCollection>(&followers_uri)?;
- let apub_id = &oprops.get_attributed_to_xsd_any_uri().unwrap().to_string();
- let creator = get_or_fetch_and_upsert_remote_user(&apub_id, conn)?;
+ let mut creator_and_moderator_uris = oprops.get_many_attributed_to_xsd_any_uris().unwrap();
+ let creator = creator_and_moderator_uris
+ .next()
+ .map(|c| get_or_fetch_and_upsert_remote_user(&c.to_string(), &conn).unwrap())
+ .unwrap();
Ok(CommunityForm {
name: oprops.get_name_xsd_string().unwrap().to_string(),
diff --git a/server/src/apub/fetcher.rs b/server/src/apub/fetcher.rs
index e07e410b..e581e14d 100644
--- a/server/src/apub/fetcher.rs
+++ b/server/src/apub/fetcher.rs
@@ -86,10 +86,10 @@ pub fn get_or_fetch_and_upsert_remote_user(
match User_::read_from_actor_id(&conn, &apub_id) {
Ok(u) => {
// If its older than a day, re-fetch it
- // TODO the less than needs to be tested
- if u
- .last_refreshed_at
- .lt(&(naive_now() - chrono::Duration::days(1)))
+ if !u.local
+ && u
+ .last_refreshed_at
+ .lt(&(naive_now() - chrono::Duration::days(1)))
{
debug!("Fetching and updating from remote user: {}", apub_id);
let person = fetch_remote_object::<PersonExt>(&Url::parse(apub_id)?)?;
@@ -118,10 +118,10 @@ pub fn get_or_fetch_and_upsert_remote_community(
match Community::read_from_actor_id(&conn, &apub_id) {
Ok(c) => {
// If its older than a day, re-fetch it
- // TODO the less than needs to be tested
- if c
- .last_refreshed_at
- .lt(&(naive_now() - chrono::Duration::days(1)))
+ if !c.local
+ && c
+ .last_refreshed_at
+ .lt(&(naive_now() - chrono::Duration::days(1)))
{
debug!("Fetching and updating from remote community: {}", apub_id);
let group = fetch_remote_object::<GroupExt>(&Url::parse(apub_id)?)?;
@@ -136,7 +136,28 @@ pub fn get_or_fetch_and_upsert_remote_community(
debug!("Fetching and creating remote community: {}", apub_id);
let group = fetch_remote_object::<GroupExt>(&Url::parse(apub_id)?)?;
let cf = CommunityForm::from_apub(&group, conn)?;
- Ok(Community::create(conn, &cf)?)
+ let community = Community::create(conn, &cf)?;
+
+ // Also add the community moderators too
+ let creator_and_moderator_uris = group
+ .base
+ .base
+ .object_props
+ .get_many_attributed_to_xsd_any_uris()
+ .unwrap();
+ let creator_and_moderators = creator_and_moderator_uris
+ .map(|c| get_or_fetch_and_upsert_remote_user(&c.to_string(), &conn).unwrap())
+ .collect::<Vec<User_>>();
+
+ for mod_ in creator_and_moderators {
+ let community_moderator_form = CommunityModeratorForm {
+ community_id: community.id,
+ user_id: mod_.id,
+ };
+ CommunityModerator::join(&conn, &community_moderator_form)?;
+ }
+
+ Ok(community)
}
Err(e) => Err(Error::from(e)),
}
diff --git a/server/src/apub/mod.rs b/server/src/apub/mod.rs
index 1d860502..3c18a013 100644
--- a/server/src/apub/mod.rs
+++ b/server/src/apub/mod.rs
@@ -13,7 +13,7 @@ use crate::api::community::CommunityResponse;
use crate::websocket::server::SendCommunityRoomMessage;
use activitystreams::object::kind::{NoteType, PageType};
use activitystreams::{
- activity::{Accept, Create, Delete, Dislike, Follow, Like, Undo, Update},
+ activity::{Accept, Create, Delete, Dislike, Follow, Like, Remove, Undo, Update},
actor::{properties::ApActorProperties, Actor, Group, Person},
collection::UnorderedCollection,
context,
@@ -47,13 +47,16 @@ use crate::api::post::PostResponse;
use crate::api::site::SearchResponse;
use crate::db::comment::{Comment, CommentForm, CommentLike, CommentLikeForm};
use crate::db::comment_view::CommentView;
-use crate::db::community::{Community, CommunityFollower, CommunityFollowerForm, CommunityForm};
-use crate::db::community_view::{CommunityFollowerView, CommunityView};
+use crate::db::community::{
+ Community, CommunityFollower, CommunityFollowerForm, CommunityForm, CommunityModerator,
+ CommunityModeratorForm,
+};
+use crate::db::community_view::{CommunityFollowerView, CommunityModeratorView, CommunityView};
use crate::db::post::{Post, PostForm, PostLike, PostLikeForm};
use crate::db::post_view::PostView;
use crate::db::user::{UserForm, User_};
use crate::db::user_view::UserView;
-use crate::db::{activity, Crud, Followable, Likeable, SearchType};
+use crate::db::{activity, Crud, Followable, Joinable, Likeable, SearchType};
use crate::routes::nodeinfo::{NodeInfo, NodeInfoWellKnown};
use crate::routes::{ChatServerParam, DbPoolParam};
use crate::websocket::{
@@ -197,6 +200,8 @@ pub trait ApubObjectType {
fn send_update(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
fn send_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
fn send_undo_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
+ fn send_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
+ fn send_undo_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
}
pub trait ApubLikeableType {
@@ -239,6 +244,9 @@ pub trait ActorType {
fn send_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
fn send_undo_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
+ fn send_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
+ fn send_undo_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error>;
+
// TODO default because there is no user following yet.
#[allow(unused_variables)]
/// For a given community, returns the inboxes of all followers.
diff --git a/server/src/apub/post.rs b/server/src/apub/post.rs
index 5a7383c0..2d1f1c71 100644
--- a/server/src/apub/post.rs
+++ b/server/src/apub/post.rs
@@ -263,6 +263,92 @@ impl ApubObjectType for Post {
)?;
Ok(())
}
+
+ fn send_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error> {
+ let page = self.to_apub(conn)?;
+ let community = Community::read(conn, self.community_id)?;
+ let id = format!("{}/remove/{}", self.ap_id, uuid::Uuid::new_v4());
+ let mut remove = Remove::default();
+
+ populate_object_props(
+ &mut remove.object_props,
+ &community.get_followers_url(),
+ &id,
+ )?;
+
+ remove
+ .remove_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(page)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let community = Community::read(conn, self.community_id)?;
+ send_activity(
+ &remove,
+ &mod_.private_key.as_ref().unwrap(),
+ &mod_.actor_id,
+ community.get_follower_inboxes(&conn)?,
+ )?;
+ Ok(())
+ }
+ fn send_undo_remove(&self, mod_: &User_, conn: &PgConnection) -> Result<(), Error> {
+ let page = self.to_apub(conn)?;
+ let community = Community::read(conn, self.community_id)?;
+ let id = format!("{}/remove/{}", self.ap_id, uuid::Uuid::new_v4());
+ let mut remove = Remove::default();
+
+ populate_object_props(
+ &mut remove.object_props,
+ &community.get_followers_url(),
+ &id,
+ )?;
+
+ remove
+ .remove_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(page)?;
+
+ // Undo that fake activity
+ let undo_id = format!("{}/undo/remove/{}", self.ap_id, uuid::Uuid::new_v4());
+ let mut undo = Undo::default();
+
+ populate_object_props(
+ &mut undo.object_props,
+ &community.get_followers_url(),
+ &undo_id,
+ )?;
+
+ undo
+ .undo_props
+ .set_actor_xsd_any_uri(mod_.actor_id.to_owned())?
+ .set_object_base_box(remove)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&undo)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let community = Community::read(conn, self.community_id)?;
+ send_activity(
+ &undo,
+ &mod_.private_key.as_ref().unwrap(),
+ &mod_.actor_id,
+ community.get_follower_inboxes(&conn)?,
+ )?;
+ Ok(())
+ }
}
impl ApubLikeableType for Post {
diff --git a/server/src/apub/shared_inbox.rs b/server/src/apub/shared_inbox.rs
index a9a61020..d77788e5 100644
--- a/server/src/apub/shared_inbox.rs
+++ b/server/src/apub/shared_inbox.rs
@@ -3,12 +3,13 @@ use super::*;
#[serde(untagged)]
#[derive(Serialize, Deserialize, Debug)]
pub enum SharedAcceptedObjects {
- Create(Create),
- Update(Update),
- Like(Like),
- Dislike(Dislike),
- Delete(Delete),
- Undo(Undo),
+ Create(Box<Create>),
+ Update(Box<Update>),
+ Like(Box<Like>),
+ Dislike(Box<Dislike>),
+ Delete(Box<Delete>),
+ Undo(Box<Undo>),
+ Remove(Box<Remove>),
}
impl SharedAcceptedObjects {
@@ -20,6 +21,7 @@ impl SharedAcceptedObjects {
SharedAcceptedObjects::Dislike(d) => d.dislike_props.get_object_base_box(),
SharedAcceptedObjects::Delete(d) => d.delete_props.get_object_base_box(),
SharedAcceptedObjects::Undo(d) => d.undo_props.get_object_base_box(),
+ SharedAcceptedObjects::Remove(r) => r.remove_props.get_object_base_box(),
}
}
}
@@ -56,6 +58,9 @@ pub async fn shared_inbox(
(SharedAcceptedObjects::Delete(d), Some("Page")) => {
receive_delete_post(&d, &request, &conn, chat_server)
}
+ (SharedAcceptedObjects::Remove(r), Some("Page")) => {
+ receive_remove_post(&r, &request, &conn, chat_server)
+ }
(SharedAcceptedObjects::Create(c), Some("Note")) => {
receive_create_comment(&c, &request, &conn, chat_server)
}
@@ -71,12 +76,21 @@ pub async fn shared_inbox(
(SharedAcceptedObjects::Delete(d), Some("Note")) => {
receive_delete_comment(&d, &request, &conn, chat_server)
}
+ (SharedAcceptedObjects::Remove(r), Some("Note")) => {
+ receive_remove_comment(&r, &request, &conn, chat_server)
+ }
(SharedAcceptedObjects::Delete(d), Some("Group")) => {
receive_delete_community(&d, &request, &conn, chat_server)
}
+ (SharedAcceptedObjects::Remove(r), Some("Group")) => {
+ receive_remove_community(&r, &request, &conn, chat_server)
+ }
(SharedAcceptedObjects::Undo(u), Some("Delete")) => {
receive_undo_delete(&u, &request, &conn, chat_server)
}
+ (SharedAcceptedObjects::Undo(u), Some("Remove")) => {
+ receive_undo_remove(&u, &request, &conn, chat_server)
+ }
_ => Err(format_err!("Unknown incoming activity type.")),
}
}
@@ -588,6 +602,75 @@ fn receive_delete_community(
Ok(HttpResponse::Ok().finish())
}
+fn receive_remove_community(
+ remove: &Remove,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let mod_uri = remove
+ .remove_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string();
+
+ let group = remove
+ .remove_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .into_concrete::<GroupExt>()?;
+
+ let mod_ = get_or_fetch_and_upsert_remote_user(&mod_uri, &conn)?;
+ verify(request, &mod_.public_key.unwrap())?;
+
+ // Insert the received activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: false,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let community_actor_id = CommunityForm::from_apub(&group, &conn)?.actor_id;
+ let community = Community::read_from_actor_id(conn, &community_actor_id)?;
+
+ let community_form = CommunityForm {
+ name: community.name.to_owned(),
+ title: community.title.to_owned(),
+ description: community.description.to_owned(),
+ category_id: community.category_id, // Note: need to keep this due to foreign key constraint
+ creator_id: community.creator_id, // Note: need to keep this due to foreign key constraint
+ removed: Some(true),
+ published: None,
+ updated: Some(naive_now()),
+ deleted: None,
+ nsfw: community.nsfw,
+ actor_id: community.actor_id,
+ local: community.local,
+ private_key: community.private_key,
+ public_key: community.public_key,
+ last_refreshed_at: None,
+ };
+
+ Community::update(&conn, community.id, &community_form)?;
+
+ let res = CommunityResponse {
+ community: CommunityView::read(&conn, community.id, None)?,
+ };
+
+ chat_server.do_send(SendCommunityRoomMessage {
+ op: UserOperation::EditCommunity,
+ response: res,
+ community_id: community.id,
+ my_id: None,
+ });
+
+ Ok(HttpResponse::Ok().finish())
+}
+
fn receive_delete_post(
delete: &Delete,
request: &HttpRequest,
@@ -659,6 +742,77 @@ fn receive_delete_post(
Ok(HttpResponse::Ok().finish())
}
+fn receive_remove_post(
+ remove: &Remove,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let mod_uri = remove
+ .remove_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string();
+
+ let page = remove
+ .remove_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .into_concrete::<Page>()?;
+
+ let mod_ = get_or_fetch_and_upsert_remote_user(&mod_uri, &conn)?;
+ verify(request, &mod_.public_key.unwrap())?;
+
+ // Insert the received activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: false,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let post_ap_id = PostForm::from_apub(&page, conn)?.ap_id;
+ let post = Post::read_from_apub_id(conn, &post_ap_id)?;
+
+ let post_form = PostForm {
+ name: post.name.to_owned(),
+ url: post.url.to_owned(),
+ body: post.body.to_owned(),
+ creator_id: post.creator_id.to_owned(),
+ community_id: post.community_id,
+ removed: Some(true),
+ deleted: None,
+ nsfw: post.nsfw,
+ locked: None,
+ stickied: None,
+ updated: Some(naive_now()),
+ embed_title: post.embed_title,
+ embed_description: post.embed_description,
+ embed_html: post.embed_html,
+ thumbnail_url: post.thumbnail_url,
+ ap_id: post.ap_id,
+ local: post.local,
+ published: None,
+ };
+ Post::update(&conn, post.id, &post_form)?;
+
+ // Refetch the view
+ let post_view = PostView::read(&conn, post.id, None)?;
+
+ let res = PostResponse { post: post_view };
+
+ chat_server.do_send(SendPost {
+ op: UserOperation::EditPost,
+ post: res,
+ my_id: None,
+ });
+
+ Ok(HttpResponse::Ok().finish())
+}
+
fn receive_delete_comment(
delete: &Delete,
request: &HttpRequest,
@@ -727,6 +881,74 @@ fn receive_delete_comment(
Ok(HttpResponse::Ok().finish())
}
+fn receive_remove_comment(
+ remove: &Remove,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let mod_uri = remove
+ .remove_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string();
+
+ let note = remove
+ .remove_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .into_concrete::<Note>()?;
+
+ let mod_ = get_or_fetch_and_upsert_remote_user(&mod_uri, &conn)?;
+ verify(request, &mod_.public_key.unwrap())?;
+
+ // Insert the received activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: false,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let comment_ap_id = CommentForm::from_apub(&note, &conn)?.ap_id;
+ let comment = Comment::read_from_apub_id(conn, &comment_ap_id)?;
+ let comment_form = CommentForm {
+ content: comment.content.to_owned(),
+ parent_id: comment.parent_id,
+ post_id: comment.post_id,
+ creator_id: comment.creator_id,
+ removed: Some(true),
+ deleted: None,
+ read: None,
+ published: None,
+ updated: Some(naive_now()),
+ ap_id: comment.ap_id,
+ local: comment.local,
+ };
+ Comment::update(&conn, comment.id, &comment_form)?;
+
+ // Refetch the view
+ let comment_view = CommentView::read(&conn, comment.id, None)?;
+
+ // TODO get those recipient actor ids from somewhere
+ let recipient_ids = vec![];
+ let res = CommentResponse {
+ comment: comment_view,
+ recipient_ids,
+ };
+
+ chat_server.do_send(SendComment {
+ op: UserOperation::EditComment,
+ comment: res,
+ my_id: None,
+ });
+
+ Ok(HttpResponse::Ok().finish())
+}
+
fn receive_undo_delete(
undo: &Undo,
request: &HttpRequest,
@@ -757,6 +979,36 @@ fn receive_undo_delete(
}
}
+fn receive_undo_remove(
+ undo: &Undo,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let remove = undo
+ .undo_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .into_concrete::<Remove>()?;
+
+ let type_ = remove
+ .remove_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .kind()
+ .unwrap();
+
+ match type_ {
+ "Note" => receive_undo_remove_comment(&remove, &request, &conn, chat_server),
+ "Page" => receive_undo_remove_post(&remove, &request, &conn, chat_server),
+ "Group" => receive_undo_remove_community(&remove, &request, &conn, chat_server),
+ d => Err(format_err!("Undo Delete type {} not supported", d)),
+ }
+}
+
fn receive_undo_delete_comment(
delete: &Delete,
request: &HttpRequest,
@@ -825,6 +1077,74 @@ fn receive_undo_delete_comment(
Ok(HttpResponse::Ok().finish())
}
+fn receive_undo_remove_comment(
+ remove: &Remove,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let mod_uri = remove
+ .remove_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string();
+
+ let note = remove
+ .remove_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .into_concrete::<Note>()?;
+
+ let mod_ = get_or_fetch_and_upsert_remote_user(&mod_uri, &conn)?;
+ verify(request, &mod_.public_key.unwrap())?;
+
+ // Insert the received activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: false,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let comment_ap_id = CommentForm::from_apub(&note, &conn)?.ap_id;
+ let comment = Comment::read_from_apub_id(conn, &comment_ap_id)?;
+ let comment_form = CommentForm {
+ content: comment.content.to_owned(),
+ parent_id: comment.parent_id,
+ post_id: comment.post_id,
+ creator_id: comment.creator_id,
+ removed: Some(false),
+ deleted: None,
+ read: None,
+ published: None,
+ updated: Some(naive_now()),
+ ap_id: comment.ap_id,
+ local: comment.local,
+ };
+ Comment::update(&conn, comment.id, &comment_form)?;
+
+ // Refetch the view
+ let comment_view = CommentView::read(&conn, comment.id, None)?;
+
+ // TODO get those recipient actor ids from somewhere
+ let recipient_ids = vec![];
+ let res = CommentResponse {
+ comment: comment_view,
+ recipient_ids,
+ };
+
+ chat_server.do_send(SendComment {
+ op: UserOperation::EditComment,
+ comment: res,
+ my_id: None,
+ });
+
+ Ok(HttpResponse::Ok().finish())
+}
+
fn receive_undo_delete_post(
delete: &Delete,
request: &HttpRequest,
@@ -896,6 +1216,77 @@ fn receive_undo_delete_post(
Ok(HttpResponse::Ok().finish())
}
+fn receive_undo_remove_post(
+ remove: &Remove,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let mod_uri = remove
+ .remove_props
+ .get_actor_xsd_any_uri()
+ .unwrap()
+ .to_string();
+
+ let page = remove
+ .remove_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .into_concrete::<Page>()?;
+
+ let mod_ = get_or_fetch_and_upsert_remote_user(&mod_uri, &conn)?;
+ verify(request, &mod_.public_key.unwrap())?;
+
+ // Insert the received activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: mod_.id,
+ data: serde_json::to_value(&remove)?,
+ local: false,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let post_ap_id = PostForm::from_apub(&page, conn)?.ap_id;
+ let post = Post::read_from_apub_id(conn, &post_ap_id)?;
+
+ let post_form = PostForm {
+ name: post.name.to_owned(),
+ url: post.url.to_owned(),
+ body: post.body.to_owned(),
+ creator_id: post.creator_id.to_owned(),
+ community_id: post.community_id,
+ removed: Some(false),
+ deleted: None,
+ nsfw: post.nsfw,
+ locked: None,
+ stickied: None,
+ updated: Some(naive_now()),
+ embed_title: post.embed_title,
+ embed_description: post.embed_description,
+ embed_html: post.embed_html,
+ thumbnail_url: post.thumbnail_url,
+ ap_id: post.ap_id,
+ local: post.local,
+ published: None,
+ };
+ Post::update(&conn, post.id, &post_form)?;
+
+ // Refetch the view
+ let post_view = PostView::read(&conn, post.id, None)?