published: None,
};
- let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
+ let updated_community = match Community::update(&conn, data.edit_id, &community_form) {
Ok(community) => community,
Err(_e) => return Err(APIError::err("couldnt_update_community").into()),
};
expires,
};
ModRemoveCommunity::create(&conn, &form)?;
+ updated_community.send_delete(&conn)?;
+ }
+
+ if let Some(_deleted) = data.deleted.to_owned() {
+ updated_community.send_delete(&conn)?;
}
let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
impl ToApub for Comment {
type Response = Note;
- fn to_apub(&self, conn: &PgConnection) -> Result<Note, Error> {
+ fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<Note>, Error> {
let mut comment = Note::default();
let oprops: &mut ObjectProperties = comment.as_mut();
let creator = User_::read(&conn, self.creator_id)?;
oprops.set_updated(convert_datetime(u))?;
}
- Ok(comment)
+ Ok(ResponseOrTombstone::Response(comment))
}
}
create
.create_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(note)?;
+ .set_object_base_box(note.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
update
.update_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(note)?;
+ .set_object_base_box(note.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
like
.like_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(note)?;
+ .set_object_base_box(note.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
dislike
.dislike_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(note)?;
+ .set_object_base_box(note.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
type Response = GroupExt;
// Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
- fn to_apub(&self, conn: &PgConnection) -> Result<GroupExt, Error> {
+ fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<GroupExt>, Error> {
+ if self.deleted || self.removed {
+ let mut tombstone = Tombstone::default();
+ // TODO: might want to include updated/deleted times as well
+ tombstone
+ .object_props
+ .set_id(self.actor_id.to_owned())?
+ .set_published(convert_datetime(self.published))?;
+ return Ok(ResponseOrTombstone::Tombstone(Box::new(tombstone)));
+ }
+
let mut group = Group::default();
let oprops: &mut ObjectProperties = group.as_mut();
.set_endpoints(endpoint_props)?
.set_followers(self.get_followers_url())?;
- Ok(group.extend(actor_props).extend(self.get_public_key_ext()))
+ Ok(ResponseOrTombstone::Response(
+ group.extend(actor_props).extend(self.get_public_key_ext()),
+ ))
}
}
Ok(())
}
+ fn send_delete(&self, conn: &PgConnection) -> Result<(), Error> {
+ let community = self.to_apub(conn)?;
+ let mut delete = Delete::default();
+ delete
+ .delete_props
+ .set_actor_xsd_any_uri(self.actor_id.to_owned())?
+ .set_object_base_box(BaseBox::from_concrete(
+ community.as_tombstone()?.to_owned(),
+ )?)?;
+
+ // Insert the sent activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: self.creator_id,
+ data: serde_json::to_value(&delete)?,
+ local: true,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ send_activity(
+ &delete,
+ &self.private_key.to_owned().unwrap(),
+ &self.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> {
- debug!("got here.");
-
Ok(
CommunityFollowerView::for_community(conn, self.id)?
.into_iter()
pub mod user_inbox;
use activitystreams::{
- activity::{Accept, Create, Dislike, Follow, Like, Update},
+ activity::{Accept, Create, Delete, Dislike, Follow, Like, Update},
actor::{properties::ApActorProperties, Actor, Group, Person},
collection::UnorderedCollection,
context,
endpoint::EndpointProperties,
ext::{Ext, Extensible, Extension},
- object::{properties::ObjectProperties, Note, Page},
+ object::{properties::ObjectProperties, Note, Page, Tombstone},
public, BaseBox,
};
use actix_web::body::Body;
}
}
+#[derive(Serialize)]
+pub enum ResponseOrTombstone<Response> {
+ Response(Response),
+ Tombstone(Box<Tombstone>),
+}
+
+impl<Response> ResponseOrTombstone<Response> {
+ fn as_response(&self) -> Result<&Response, Error> {
+ match self {
+ ResponseOrTombstone::Response(r) => Ok(r),
+ ResponseOrTombstone::Tombstone(_t) => Err(format_err!("Value is a tombstone")),
+ }
+ }
+ fn as_tombstone(&self) -> Result<&Tombstone, Error> {
+ match self {
+ ResponseOrTombstone::Tombstone(t) => Ok(t),
+ ResponseOrTombstone::Response(_r) => Err(format_err!("Value is a response")),
+ }
+ }
+}
+
// TODO Not sure good names for these
pub trait ToApub {
type Response;
- fn to_apub(&self, conn: &PgConnection) -> Result<Self::Response, Error>;
+ fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<Self::Response>, Error>;
}
pub trait FromApub {
pub trait ApubObjectType {
fn send_create(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
fn send_update(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
+ //fn send_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
}
pub trait ApubLikeableType {
Err(format_err!("Accept not implemented."))
}
+ fn send_delete(&self, 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.
type Response = Page;
// Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
- fn to_apub(&self, conn: &PgConnection) -> Result<Page, Error> {
+ fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<Page>, Error> {
let mut page = Page::default();
let oprops: &mut ObjectProperties = page.as_mut();
let creator = User_::read(conn, self.creator_id)?;
oprops.set_updated(convert_datetime(u))?;
}
- Ok(page)
+ Ok(ResponseOrTombstone::Response(page))
}
}
create
.create_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(page)?;
+ .set_object_base_box(page.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
update
.update_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(page)?;
+ .set_object_base_box(page.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
like
.like_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(page)?;
+ .set_object_base_box(page.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
dislike
.dislike_props
.set_actor_xsd_any_uri(creator.actor_id.to_owned())?
- .set_object_base_box(page)?;
+ .set_object_base_box(page.as_response()?.to_owned())?;
// Insert the sent activity into the activity table
let activity_form = activity::ActivityForm {
use super::*;
+use crate::api::community::CommunityResponse;
+use crate::websocket::server::SendCommunityRoomMessage;
#[serde(untagged)]
#[derive(Serialize, Deserialize, Debug)]
Update(Update),
Like(Like),
Dislike(Dislike),
+ Delete(Delete),
}
impl SharedAcceptedObjects {
SharedAcceptedObjects::Update(u) => u.update_props.get_object_base_box(),
SharedAcceptedObjects::Like(l) => l.like_props.get_object_base_box(),
SharedAcceptedObjects::Dislike(d) => d.dislike_props.get_object_base_box(),
+ SharedAcceptedObjects::Delete(d) => d.delete_props.get_object_base_box(),
}
}
}
(SharedAcceptedObjects::Dislike(d), Some("Note")) => {
receive_dislike_comment(&d, &request, &conn, chat_server)
}
+ (SharedAcceptedObjects::Delete(d), Some("Tombstone")) => {
+ receive_delete_community(&d, &request, &conn, chat_server)
+ }
_ => Err(format_err!("Unknown incoming activity type.")),
}
}
Ok(HttpResponse::Ok().finish())
}
+
+fn receive_delete_community(
+ delete: &Delete,
+ request: &HttpRequest,
+ conn: &PgConnection,
+ chat_server: ChatServerParam,
+) -> Result<HttpResponse, Error> {
+ let tombstone = delete
+ .delete_props
+ .get_object_base_box()
+ .to_owned()
+ .unwrap()
+ .to_owned()
+ .to_concrete::<Tombstone>()?;
+ let community_apub_id = tombstone.object_props.get_id().unwrap().to_string();
+
+ let community = Community::read_from_actor_id(conn, &community_apub_id)?;
+ verify(request, &community.public_key.clone().unwrap())?;
+
+ // Insert the received activity into the activity table
+ let activity_form = activity::ActivityForm {
+ user_id: community.creator_id,
+ data: serde_json::to_value(&delete)?,
+ local: false,
+ updated: None,
+ };
+ activity::Activity::create(&conn, &activity_form)?;
+
+ let community_form = CommunityForm {
+ name: "".to_string(),
+ title: "".to_string(),
+ description: None,
+ 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: None,
+ published: None,
+ updated: None,
+ deleted: Some(true),
+ nsfw: false,
+ actor_id: community.actor_id,
+ local: false,
+ private_key: None,
+ public_key: community.public_key,
+ last_refreshed_at: Some(community.last_refreshed_at),
+ };
+
+ 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())
+}
type Response = PersonExt;
// Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
- fn to_apub(&self, _conn: &PgConnection) -> Result<PersonExt, Error> {
+ fn to_apub(&self, _conn: &PgConnection) -> Result<ResponseOrTombstone<PersonExt>, Error> {
// TODO go through all these to_string and to_owned()
let mut person = Person::default();
let oprops: &mut ObjectProperties = person.as_mut();
.set_following(self.get_following_url())?
.set_liked(self.get_liked_url())?;
- Ok(person.extend(actor_props).extend(self.get_public_key_ext()))
+ Ok(ResponseOrTombstone::Response(
+ person.extend(actor_props).extend(self.get_public_key_ext()),
+ ))
}
}
)?;
Ok(())
}
+
+ fn send_delete(&self, _conn: &PgConnection) -> Result<(), Error> {
+ unimplemented!()
+ }
}
impl FromApub for UserForm {