X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fapub%2Fsrc%2Fprotocol%2Fobjects%2Fgroup.rs;h=9c679fdf10a6bd6b5f87281e1e616fe67305dd05;hb=3471f3533cb724b2cf6953d563aadfcc9f66c1d2;hp=dbc823748bcbef77c89223053d383d1ba34e8e90;hpb=2edf8ba1576d67234d1129cd97b131c0654a54f7;p=lemmy.git diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs index dbc82374..9c679fdf 100644 --- a/crates/apub/src/protocol/objects/group.rs +++ b/crates/apub/src/protocol/objects/group.rs @@ -1,26 +1,44 @@ use crate::{ - check_is_apub_id_valid, + check_apub_id_valid_with_strictness, collections::{ + community_featured::ApubCommunityFeatured, community_moderators::ApubCommunityModerators, community_outbox::ApubCommunityOutbox, }, - objects::{community::ApubCommunity, get_summary_from_string_or_source}, - protocol::{ImageObject, Source}, + local_site_data_cached, + objects::{community::ApubCommunity, read_from_string_or_source_opt}, + protocol::{ + objects::{Endpoints, LanguageTag}, + ImageObject, + Source, + }, }; -use activitystreams::{ - actor::{kind::GroupType, Endpoints}, - unparsed::Unparsed, +use activitypub_federation::{ + fetch::{collection_id::CollectionId, object_id::ObjectId}, + kinds::actor::GroupType, + protocol::{ + helpers::deserialize_skip_error, + public_key::PublicKey, + verification::verify_domains_match, + }, }; use chrono::{DateTime, FixedOffset}; -use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey, verify::verify_domains_match}; -use lemmy_db_schema::{naive_now, source::community::CommunityForm}; +use lemmy_api_common::{ + context::LemmyContext, + utils::{local_site_opt_to_slur_regex, sanitize_html, sanitize_html_opt}, +}; +use lemmy_db_schema::{ + newtypes::InstanceId, + source::community::{CommunityInsertForm, CommunityUpdateForm}, + utils::naive_now, +}; use lemmy_utils::{ - settings::structs::Settings, - utils::{check_slurs, check_slurs_opt}, - LemmyError, + error::LemmyError, + utils::slurs::{check_slurs, check_slurs_opt}, }; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; +use std::fmt::Debug; use url::Url; #[skip_serializing_none] @@ -30,68 +48,114 @@ pub struct Group { #[serde(rename = "type")] pub(crate) kind: GroupType, pub(crate) id: ObjectId, - /// username, set at account creation and can never be changed + /// username, set at account creation and usually fixed after that pub(crate) preferred_username: String, - /// title (can be changed at any time) - pub(crate) name: String, + pub(crate) inbox: Url, + pub(crate) followers: Url, + pub(crate) public_key: PublicKey, + + /// title + pub(crate) name: Option, pub(crate) summary: Option, + #[serde(deserialize_with = "deserialize_skip_error", default)] pub(crate) source: Option, pub(crate) icon: Option, /// banner pub(crate) image: Option, // lemmy extension pub(crate) sensitive: Option, + #[serde(deserialize_with = "deserialize_skip_error", default)] + pub(crate) attributed_to: Option>, // lemmy extension - pub(crate) moderators: Option>, - pub(crate) inbox: Url, - pub(crate) outbox: ObjectId, - pub(crate) followers: Url, - pub(crate) endpoints: Endpoints, - pub(crate) public_key: PublicKey, + pub(crate) posting_restricted_to_mods: Option, + pub(crate) outbox: CollectionId, + pub(crate) endpoints: Option, + pub(crate) featured: Option>, + #[serde(default)] + pub(crate) language: Vec, pub(crate) published: Option>, pub(crate) updated: Option>, - #[serde(flatten)] - pub(crate) unparsed: Unparsed, } impl Group { - pub(crate) async fn from_apub_to_form( - group: &Group, + pub(crate) async fn verify( + &self, expected_domain: &Url, - settings: &Settings, - ) -> Result { - check_is_apub_id_valid(group.id.inner(), true, settings)?; - verify_domains_match(expected_domain, group.id.inner())?; - let name = group.preferred_username.clone(); - let title = group.name.clone(); - let description = get_summary_from_string_or_source(&group.summary, &group.source); - let shared_inbox = group.endpoints.shared_inbox.clone().map(|s| s.into()); + context: &LemmyContext, + ) -> Result<(), LemmyError> { + check_apub_id_valid_with_strictness(self.id.inner(), true, context).await?; + verify_domains_match(expected_domain, self.id.inner())?; - let slur_regex = &settings.slur_regex(); - check_slurs(&name, slur_regex)?; - check_slurs(&title, slur_regex)?; + let local_site_data = local_site_data_cached(&mut context.pool()).await?; + let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site); + + check_slurs(&self.preferred_username, slur_regex)?; + check_slurs_opt(&self.name, slur_regex)?; + let description = read_from_string_or_source_opt(&self.summary, &None, &self.source); check_slurs_opt(&description, slur_regex)?; + Ok(()) + } + + pub(crate) fn into_insert_form(self, instance_id: InstanceId) -> CommunityInsertForm { + let name = sanitize_html(&self.preferred_username); + let title = sanitize_html(&self.name.unwrap_or(self.preferred_username)); + let description = read_from_string_or_source_opt(&self.summary, &None, &self.source); + let description = sanitize_html_opt(&description); - // TODO: test_parse_lemmy_community_moderators() keeps failing here with stack overflow - Ok(CommunityForm { + CommunityInsertForm { name, title, description, removed: None, - published: group.published.map(|u| u.naive_local()), - updated: group.updated.map(|u| u.naive_local()), - deleted: None, - nsfw: Some(group.sensitive.unwrap_or(false)), - actor_id: Some(group.id.clone().into()), + published: self.published.map(|u| u.naive_local()), + updated: self.updated.map(|u| u.naive_local()), + deleted: Some(false), + nsfw: Some(self.sensitive.unwrap_or(false)), + actor_id: Some(self.id.into()), local: Some(false), private_key: None, - public_key: Some(group.public_key.public_key_pem.clone()), + hidden: None, + public_key: self.public_key.public_key_pem, + last_refreshed_at: Some(naive_now()), + icon: self.icon.map(|i| i.url.into()), + banner: self.image.map(|i| i.url.into()), + followers_url: Some(self.followers.into()), + inbox_url: Some(self.inbox.into()), + shared_inbox_url: self.endpoints.map(|e| e.shared_inbox.into()), + moderators_url: self.attributed_to.map(Into::into), + posting_restricted_to_mods: self.posting_restricted_to_mods, + instance_id, + featured_url: self.featured.map(Into::into), + } + } + + pub(crate) fn into_update_form(self) -> CommunityUpdateForm { + CommunityUpdateForm { + title: Some(self.name.unwrap_or(self.preferred_username)), + description: Some(read_from_string_or_source_opt( + &self.summary, + &None, + &self.source, + )), + removed: None, + published: self.published.map(|u| u.naive_local()), + updated: Some(self.updated.map(|u| u.naive_local())), + deleted: None, + nsfw: Some(self.sensitive.unwrap_or(false)), + actor_id: Some(self.id.into()), + local: None, + private_key: None, + hidden: None, + public_key: Some(self.public_key.public_key_pem), last_refreshed_at: Some(naive_now()), - icon: Some(group.icon.clone().map(|i| i.url.into())), - banner: Some(group.image.clone().map(|i| i.url.into())), - followers_url: Some(group.followers.clone().into()), - inbox_url: Some(group.inbox.clone().into()), - shared_inbox_url: Some(shared_inbox), - }) + icon: Some(self.icon.map(|i| i.url.into())), + banner: Some(self.image.map(|i| i.url.into())), + followers_url: Some(self.followers.into()), + inbox_url: Some(self.inbox.into()), + shared_inbox_url: Some(self.endpoints.map(|e| e.shared_inbox.into())), + moderators_url: self.attributed_to.map(Into::into), + posting_restricted_to_mods: self.posting_restricted_to_mods, + featured_url: self.featured.map(Into::into), + } } }