//! Types and traits for dealing with Actor attributes //! //! ```rust //! # fn main() -> Result<(), anyhow::Error> { //! use activitystreams::{ //! actor::{ApActor, Person}, //! prelude::*, //! iri, //! }; //! //! let mut person = ApActor::new( //! iri!("https://example.com/actor/inbox"), //! Person::new(), //! ); //! //! person //! .set_outbox(iri!("https://example.com/actor/outbox")) //! .set_following(iri!("https://example.com/actor/following")) //! .set_followers(iri!("https://example.com/actor/followers")); //! # //! # Ok(()) //! # } //! ``` use std::collections::HashMap; use crate::{ base::{AsBase, Base, Extends}, checked::CheckError, markers, object::{ApObject, AsApObject, AsObject, Object}, prelude::BaseExt, primitives::OneOrMany, unparsed::{Unparsed, UnparsedMut, UnparsedMutExt}, }; use iri_string::{components::AuthorityComponents, types::IriString}; pub use activitystreams_kinds::actor as kind; use self::kind::*; fn check_opt( iri: &IriString, authority_components: Option<&AuthorityComponents>, ) -> Result<(), CheckError> { if iri.authority_components().as_ref() == authority_components { Ok(()) } else { Err(CheckError(Some(iri.clone()))) } } /// Implementation trait for deriving ActivityPub Actor methods for a type /// /// Any type implementing AsObject will automatically gain methods provided by ApActorExt pub trait AsApActor: markers::Actor { type Inner; /// Immutable borrow of `ApActor` fn ap_actor_ref(&self) -> &ApActor; /// Mutable borrow of `ApActor` fn ap_actor_mut(&mut self) -> &mut ApActor; } /// Helper methods for interacting with ActivityPub Actor types /// /// This trait represents methods valid for any ActivityPub Actor. /// /// Documentation for the fields related to these methods can be found on the `ApActor` struct pub trait ApActorExt: AsApActor { /// Fetch the inbox for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// let inbox_ref = person.inbox(); /// ``` fn inbox<'a>(&'a self) -> Result<&'a IriString, CheckError> where Self::Inner: 'a, Self: BaseExt, { let inbox = self.inbox_unchecked(); self.check_authority(inbox) } /// Fetch the inbox for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// let inbox_ref = person.inbox_unchecked(); /// ``` fn inbox_unchecked<'a>(&'a self) -> &'a IriString where Self::Inner: 'a, { &self.ap_actor_ref().inbox } /// Fetch a mutable referece to the current actor's inbox /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// let inbox_mut = person.inbox_mut(); /// ``` fn inbox_mut<'a>(&'a mut self) -> &'a mut IriString where Self::Inner: 'a, { &mut self.ap_actor_mut().inbox } /// Set the inbox for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_inbox(iri!("https://example.com/inbox")); /// # Ok(()) /// # } /// ``` fn set_inbox(&mut self, inbox: IriString) -> &mut Self { self.ap_actor_mut().inbox = inbox; self } /// Fetch the outbox for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// let outbox_ref = person.outbox(); /// ``` fn outbox<'a>(&'a self) -> Result, CheckError> where Self::Inner: 'a, Self: BaseExt, { self.outbox_unchecked() .map(|outbox| self.check_authority(outbox)) .transpose() } /// Fetch the outbox for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// let outbox_ref = person.outbox_unchecked(); /// ``` fn outbox_unchecked<'a>(&'a self) -> Option<&'a IriString> where Self::Inner: 'a, { self.ap_actor_ref().outbox.as_ref() } /// Mutably fetch the outbox for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(outbox) = person.outbox_mut() { /// println!("{:?}", outbox); /// } /// ``` fn outbox_mut<'a>(&'a mut self) -> Option<&'a mut IriString> where Self::Inner: 'a, { self.ap_actor_mut().outbox.as_mut() } /// Set the outbox for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_outbox(iri!("https://example.com/outbox")); /// # Ok(()) /// # } /// ``` fn set_outbox(&mut self, outbox: IriString) -> &mut Self { self.ap_actor_mut().outbox = Some(outbox); self } /// Take the outbox from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(outbox) = person.take_outbox() { /// println!("{:?}", outbox); /// } /// ``` fn take_outbox(&mut self) -> Option { self.ap_actor_mut().outbox.take() } /// Delete the outbox from the current object /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_outbox(iri!("https://example.com/outbox")); /// use activitystreams::prelude::*; /// /// assert!(person.outbox_unchecked().is_some()); /// person.delete_outbox(); /// assert!(person.outbox_unchecked().is_none()); /// # Ok(()) /// # } /// ``` fn delete_outbox(&mut self) -> &mut Self { self.ap_actor_mut().outbox = None; self } /// Fetch the following link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Ok(following) = person.following() { /// println!("{:?}", following); /// } /// ``` fn following<'a>(&'a self) -> Result, CheckError> where Self::Inner: 'a, Self: BaseExt, { self.following_unchecked() .map(|following| self.check_authority(following)) .transpose() } /// Fetch the following link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(following) = person.following_unchecked() { /// println!("{:?}", following); /// } /// ``` fn following_unchecked<'a>(&'a self) -> Option<&'a IriString> where Self::Inner: 'a, { self.ap_actor_ref().following.as_ref() } /// Mutably fetch the following link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(following) = person.following_mut() { /// println!("{:?}", following); /// } /// ``` fn following_mut<'a>(&'a mut self) -> Option<&'a mut IriString> where Self::Inner: 'a, { self.ap_actor_mut().following.as_mut() } /// Set the following link for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_following(iri!("https://example.com/following")); /// # Ok(()) /// # } /// ``` fn set_following(&mut self, following: IriString) -> &mut Self { self.ap_actor_mut().following = Some(following); self } /// Take the following link from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(following) = person.take_following() { /// println!("{:?}", following); /// } /// ``` fn take_following(&mut self) -> Option { self.ap_actor_mut().following.take() } /// Delete the following link from the current object /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_following(iri!("https://example.com/following")); /// use activitystreams::prelude::*; /// /// assert!(person.following_unchecked().is_some()); /// person.delete_following(); /// assert!(person.following_unchecked().is_none()); /// # Ok(()) /// # } /// ``` fn delete_following(&mut self) -> &mut Self { self.ap_actor_mut().following = None; self } /// Fetch the followers link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Ok(followers) = person.followers() { /// println!("{:?}", followers); /// } /// ``` fn followers<'a>(&'a self) -> Result, CheckError> where Self::Inner: 'a, Self: BaseExt, { self.followers_unchecked() .map(|followers| self.check_authority(followers)) .transpose() } /// Fetch the followers link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(followers) = person.followers_unchecked() { /// println!("{:?}", followers); /// } /// ``` fn followers_unchecked<'a>(&'a self) -> Option<&'a IriString> where Self::Inner: 'a, { self.ap_actor_ref().followers.as_ref() } /// Mutably fetch the followers link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(followers) = person.followers_mut() { /// println!("{:?}", followers); /// } /// ``` fn followers_mut<'a>(&'a mut self) -> Option<&'a mut IriString> where Self::Inner: 'a, { self.ap_actor_mut().followers.as_mut() } /// Set the followers link for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_followers(iri!("https://example.com/followers")); /// # Ok(()) /// # } /// ``` fn set_followers(&mut self, followers: IriString) -> &mut Self { self.ap_actor_mut().followers = Some(followers); self } /// Take the followers link from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(followers) = person.take_followers() { /// println!("{:?}", followers); /// } /// ``` fn take_followers(&mut self) -> Option { self.ap_actor_mut().followers.take() } /// Delete the followers link from the current object /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_followers(iri!("https://example.com/followers")); /// use activitystreams::prelude::*; /// /// assert!(person.followers_unchecked().is_some()); /// person.delete_followers(); /// assert!(person.followers_unchecked().is_none()); /// # Ok(()) /// # } /// ``` fn delete_followers(&mut self) -> &mut Self { self.ap_actor_mut().followers = None; self } /// Fetch the liked link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Ok(liked) = person.liked() { /// println!("{:?}", liked); /// } /// ``` fn liked<'a>(&'a self) -> Result, CheckError> where Self::Inner: 'a, Self: BaseExt, { self.liked_unchecked() .map(|liked| self.check_authority(liked)) .transpose() } /// Fetch the liked link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(liked) = person.liked_unchecked() { /// println!("{:?}", liked); /// } /// ``` fn liked_unchecked<'a>(&'a self) -> Option<&'a IriString> where Self::Inner: 'a, { self.ap_actor_ref().liked.as_ref() } /// Mutably fetch the liked link for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(liked) = person.liked_mut() { /// println!("{:?}", liked); /// } /// ``` fn liked_mut<'a>(&'a mut self) -> Option<&'a mut IriString> where Self::Inner: 'a, { self.ap_actor_mut().liked.as_mut() } /// Set the liked link for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_stream(iri!("https://example.com/liked")); /// # Ok(()) /// # } /// ``` fn set_liked(&mut self, liked: IriString) -> &mut Self { self.ap_actor_mut().liked = Some(liked); self } /// Take the liked link from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(liked) = person.take_liked() { /// println!("{:?}", liked); /// } /// ``` fn take_liked(&mut self) -> Option { self.ap_actor_mut().liked.take() } /// Delete the liked link from the current object /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_liked(iri!("https://example.com/liked")); /// use activitystreams::prelude::*; /// /// assert!(person.liked_unchecked().is_some()); /// person.delete_liked(); /// assert!(person.liked_unchecked().is_none()); /// # Ok(()) /// # } /// ``` fn delete_liked(&mut self) -> &mut Self { self.ap_actor_mut().liked = None; self } /// Fetch the streams links for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Ok(streams) = person.streams() { /// println!("{:?}", streams); /// } /// ``` fn streams<'a>(&'a self) -> Result>, CheckError> where Self::Inner: 'a, Self: BaseExt, { if let Some(streams) = self.streams_unchecked() { for id in &streams { self.check_authority(id)?; } Ok(Some(streams)) } else { Ok(None) } } /// Fetch the streams links for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(streams) = person.streams_unchecked() { /// println!("{:?}", streams); /// } /// ``` fn streams_unchecked<'a>(&'a self) -> Option> where Self::Inner: 'a, { self.ap_actor_ref().streams.as_ref().map(|o| o.as_ref()) } /// Mutably fetch the streams links for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(mut streams) = person.streams_mut() { /// for url in streams.iter_mut() { /// // whatever /// } /// println!("{:?}", streams); /// } /// ``` fn streams_mut<'a>(&'a mut self) -> Option> where Self::Inner: 'a, { self.ap_actor_mut().streams.as_mut().map(|o| o.as_mut()) } /// Set the streams links for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_stream(iri!("https://example.com/streams")); /// # Ok(()) /// # } /// ``` fn set_stream(&mut self, streams: IriString) -> &mut Self { self.ap_actor_mut().streams = Some(streams.into()); self } /// Set many streams links for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_many_streams(vec![ /// iri!("https://example.com/streams1"), /// iri!("https://example.com/streams2"), /// ]); /// # Ok(()) /// # } /// ``` fn set_many_streams(&mut self, items: I) -> &mut Self where I: IntoIterator, U: Into, { let v: Vec = items.into_iter().map(|u| u.into()).collect(); self.ap_actor_mut().streams = Some(v.into()); self } /// Add a streams link for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person /// .add_stream(iri!("https://example.com/streams1")) /// .add_stream(iri!("https://example.com/streams2")); /// # Ok(()) /// # } /// ``` fn add_stream(&mut self, stream: IriString) -> &mut Self { let v = match self.ap_actor_mut().streams.take() { Some(mut v) => { v.add(stream); v } None => vec![stream].into(), }; self.ap_actor_mut().streams = Some(v); self } /// Take the streams links from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(streams) = person.take_streams() { /// println!("{:?}", streams); /// } /// ``` fn take_streams(&mut self) -> Option> { self.ap_actor_mut().streams.take() } /// Delete the streams links from the current object /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_stream(iri!("https://example.com/streams")); /// use activitystreams::prelude::*; /// /// assert!(person.streams_unchecked().is_some()); /// person.delete_streams(); /// assert!(person.streams_unchecked().is_none()); /// # Ok(()) /// # } /// ``` fn delete_streams(&mut self) -> &mut Self { self.ap_actor_mut().streams = None; self } /// Fetch the preferred_username for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(preferred_username) = person.preferred_username() { /// println!("{:?}", preferred_username); /// } /// ``` fn preferred_username<'a>(&'a self) -> Option<&'a str> where Self::Inner: 'a, { self.ap_actor_ref().preferred_username.as_deref() } /// Set the preferred_username for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_preferred_username("user123"); /// # Ok(()) /// # } /// ``` fn set_preferred_username(&mut self, string: T) -> &mut Self where T: Into, { self.ap_actor_mut().preferred_username = Some(string.into()); self } /// Take the preferred_username from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(preferred_username) = person.take_preferred_username() { /// println!("{:?}", preferred_username); /// } /// ``` fn take_preferred_username(&mut self) -> Option { self.ap_actor_mut().preferred_username.take() } /// Delete the preferred_username from the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_preferred_username("hey"); /// use activitystreams::prelude::*; /// /// assert!(person.preferred_username().is_some()); /// person.delete_preferred_username(); /// assert!(person.preferred_username().is_none()); /// ``` fn delete_preferred_username(&mut self) -> &mut Self { self.ap_actor_mut().preferred_username = None; self } /// Fetch the endpoints for the current actor, erroring if the Endpoints' domains do not /// match the ID's domain /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Endpoints, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_id(context()).set_endpoints(Endpoints { /// # shared_inbox: Some(context()), /// # ..Default::default() /// # }); /// use activitystreams::prelude::*; /// /// if let Some(endpoints) = person.endpoints()? { /// println!("{:?}", endpoints); /// } /// # Ok(()) /// # } /// ``` fn endpoints<'a>(&'a self) -> Result>, CheckError> where Self: BaseExt, Self::Inner: 'a, { if let Some(endpoints) = self.endpoints_unchecked() { let authority_opt = self.id_unchecked().and_then(|id| id.authority_components()); endpoints .proxy_url .as_ref() .map(|i| check_opt(i, authority_opt.as_ref())) .transpose()?; endpoints .oauth_authorization_endpoint .as_ref() .map(|i| check_opt(i, authority_opt.as_ref())) .transpose()?; endpoints .oauth_token_endpoint .as_ref() .map(|i| check_opt(i, authority_opt.as_ref())) .transpose()?; endpoints .provide_client_key .as_ref() .map(|i| check_opt(i, authority_opt.as_ref())) .transpose()?; endpoints .sign_client_key .as_ref() .map(|i| check_opt(i, authority_opt.as_ref())) .transpose()?; endpoints .shared_inbox .as_ref() .map(|i| check_opt(i, authority_opt.as_ref())) .transpose()?; endpoints .nonstandard .values() .try_for_each(|v| check_opt(v, authority_opt.as_ref()))?; return Ok(Some(endpoints)); } Ok(None) } /// Fetch the endpoints for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(endpoints) = person.endpoints_unchecked() { /// println!("{:?}", endpoints); /// } /// ``` fn endpoints_unchecked<'a>(&'a self) -> Option<&'a Endpoints> where Self::Inner: 'a, { self.ap_actor_ref().endpoints.as_ref() } /// Mutably fetch the endpoints for the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(mut endpoints) = person.endpoints_mut() { /// if let Some(url) = endpoints.shared_inbox.as_mut() { /// // whatever /// } /// println!("{:?}", endpoints); /// } /// ``` fn endpoints_mut<'a>(&'a mut self) -> Option<&'a mut Endpoints> where Self::Inner: 'a, { self.ap_actor_mut().endpoints.as_mut() } /// Set the endpoints for the current actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// # use activitystreams::{actor::{ApActor, Endpoints, Person}, context, iri}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// person.set_endpoints(Endpoints { /// shared_inbox: Some(iri!("https://example.com/inbox")), /// ..Default::default() /// }); /// # Ok(()) /// # } /// ``` fn set_endpoints(&mut self, endpoints: Endpoints) -> &mut Self { self.ap_actor_mut().endpoints = Some(endpoints); self } /// Take the endpoints from the current actor, leaving nothing /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// use activitystreams::prelude::*; /// /// if let Some(endpoints) = person.take_endpoints() { /// println!("{:?}", endpoints); /// } /// ``` fn take_endpoints(&mut self) -> Option> { self.ap_actor_mut().endpoints.take() } /// Delete the endpoints from the current actor /// /// ```rust /// # use activitystreams::{actor::{ApActor, Person}, context}; /// # let mut person = ApActor::new(context(), Person::new()); /// # person.set_endpoints(Default::default()); /// use activitystreams::prelude::*; /// /// assert!(person.endpoints_unchecked().is_some()); /// person.delete_endpoints(); /// assert!(person.endpoints_unchecked().is_none()); /// ``` fn delete_endpoints(&mut self) -> &mut Self { self.ap_actor_mut().endpoints = None; self } } /// Describes a software application. /// /// This is just an alias for `Actor` because there's no fields inherent to /// Application that aren't already present on an Actor. pub type Application = Actor; /// Represents a formal or informal collective of Actors. /// /// This is just an alias for `Actor` because there's no fields inherent to /// Group that aren't already present on an Actor. pub type Group = Actor; /// Represents an organization. /// /// This is just an alias for `Actor` because there's no fields inherent to /// Organization that aren't already present on an Actor. pub type Organization = Actor; /// Represents an individual person. /// /// This is just an alias for `Actor` because there's no fields inherent to /// Person that aren't already present on an Actor. pub type Person = Actor; /// Represents a service of any kind. /// /// This is just an alias for `Actor` because there's no fields inherent to /// Service that aren't already present on an Actor. pub type Service = Actor; /// Actor types are Object types that are capable of performing activities. /// /// This specification intentionally defines Actors in only the most generalized way, stopping /// short of defining semantically specific properties for each. All Actor objects are /// specializations of Object and inherit all of the core properties common to all Objects. /// External vocabularies can be used to express additional detail not covered by the Activity /// Vocabulary. VCard [vcard-rdf SHOULD be used to provide additional metadata for Person, Group, /// and Organization instances. /// /// While implementations are free to introduce new types of Actors beyond those defined by the /// Activity Vocabulary, interoperability issues can arise when applications rely too much on /// extension types that are not recognized by other implementations. Care should be taken to not /// unduly overlap with or duplicate the existing Actor types. /// /// When an implementation uses an extension type that overlaps with a core vocabulary type, the /// implementation MUST also specify the core vocabulary type. For instance, some vocabularies /// (e.g. VCard) define their own types for describing people. An implementation that wishes, for /// example, to use a vcard:Individual as an Actor MUST also identify that Actor as a Person. #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct ApActor { /// A reference to an [ActivityStreams] OrderedCollection comprised of all the messages received by the actor. /// /// - Range: xsd:anyUri /// - Functional: true inbox: IriString, /// An ActivityStreams] OrderedCollection comprised of all the messages produced by the actor. /// /// - Range: xsd:anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] outbox: Option, /// A link to an [ActivityStreams] collection of the actors that this actor is following. /// /// - Range: xsd:anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] following: Option, /// A link to an [ActivityStreams] collection of the actors that follow this actor. /// /// - Range: xsd:anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] followers: Option, /// A link to an [ActivityStreams] collection of objects this actor has liked. /// /// - Range: xsd:anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] liked: Option, /// A list of supplementary Collections which may be of interest. /// /// - Range: xsd:anyUri /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] streams: Option>, /// A short username which may be used to refer to the actor, with no uniqueness guarantees. /// /// - Range: xsd:string /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] preferred_username: Option, /// A json object which maps additional (typically server/domain-wide) endpoints which may be /// useful either for this actor or someone referencing this actor. /// /// This mapping may be nested inside the actor document as the value or may be a link to a /// JSON-LD document with these properties. /// /// - Range: Endpoint /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] endpoints: Option>, /// base fields and unparsed json ends up here #[serde(flatten)] inner: Inner, } /// A json object which maps additional (typically server/domain-wide) endpoints which may be /// useful either for this actor or someone referencing this actor. /// /// This mapping may be nested inside the actor document as the value or may be a link to a /// JSON-LD document with these properties. #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct Endpoints { /// Endpoint URI so this actor's clients may access remote ActivityStreams objects which /// require authentication to access. /// /// To use this endpoint, the client posts an x-www-form-urlencoded id parameter with the /// value being the id of the requested ActivityStreams object. /// /// - Range: anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] pub proxy_url: Option, /// If OAuth 2.0 bearer tokens [RFC6749](https://tools.ietf.org/html/rfc6749) /// [RFC6750](https://tools.ietf.org/html/rfc6750) are being used for authenticating client to /// server interactions, this endpoint specifies a URI at which a browser-authenticated user /// may obtain a new authorization grant. /// /// - Range: anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] pub oauth_authorization_endpoint: Option, /// If OAuth 2.0 bearer tokens [RFC6749](https://tools.ietf.org/html/rfc6749) /// [RFC6750](https://tools.ietf.org/html/rfc6750) are being used for authenticating client to /// server interactions, this endpoint specifies a URI at which a client may acquire an access /// token. /// /// - Range: anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] pub oauth_token_endpoint: Option, /// If Linked Data Signatures and HTTP Signatures are being used for authentication and /// authorization, this endpoint specifies a URI at which browser-authenticated users may /// authorize a client's public key for client to server interactions. /// /// - Range: anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] pub provide_client_key: Option, /// If Linked Data Signatures and HTTP Signatures are being used for authentication and /// authorization, this endpoint specifies a URI at which a client key may be signed by the /// actor's key for a time window to act on behalf of the actor in interacting with foreign /// servers. /// /// - Range: anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] pub sign_client_key: Option, /// An optional endpoint used for wide delivery of publicly addressed activities and /// activities sent to followers. /// /// shared_inbox endpoints SHOULD also be publicly readable OrderedCollection objects /// containing objects addressed to the Public special collection. Reading from the /// shared_inbox endpoint MUST NOT present objects which are not addressed to the Public /// endpoint. /// /// - Range: anyUri /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] pub shared_inbox: Option, /// Any nonstandard endpoints present in the endpoints record end up here. /// /// Software like Pleroma and Akkoma provide additional URLs here and extending Endpoints /// specifically the way objects are normally extended isn't possible for nested structs like /// this. #[serde(flatten)] pub nonstandard: HashMap, } /// A simple type to create an Actor out of any Object /// /// ```rust /// # use activitystreams::{object::Object, actor::Actor, prelude::*}; /// let object = Object::::new(); /// let mut actor = Actor(object); /// actor.set_kind("MyCustomActor".into()); /// ``` #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(transparent)] pub struct Actor(pub Object); impl Actor { /// Create a new Actor /// /// ```rust /// # use activitystreams::actor::Actor; /// let actor = Actor::::new(); /// ``` pub fn new() -> Self where Kind: Default, { Actor(Object::new()) } /// Create a new actor with `None` for it's `kind` property /// /// This means that no `type` field will be present in serialized JSON /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// use activitystreams::actor::Actor; /// /// let actor = Actor::<()>::new_none_type(); /// /// let s = serde_json::to_string(&actor)?; /// /// assert_eq!(s, "{}"); /// # Ok(()) /// # } /// ``` pub fn new_none_type() -> Self { Actor(Object::new_none_type()) } } impl ApActor { /// Create a new ActivityPub Actor /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// use activitystreams::{actor::{ApActor, Person}, iri}; /// /// let actor = ApActor::new( /// iri!("https://example.com/inbox"), /// Person::new(), /// ); /// # Ok(()) /// # } /// ``` pub fn new(inbox: IriString, inner: Inner) -> Self where Inner: markers::Actor, { ApActor { inbox, outbox: None, following: None, followers: None, liked: None, streams: None, preferred_username: None, endpoints: None, inner, } } #[allow(clippy::type_complexity)] /// Deconstruct the ApActor into its parts /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// use activitystreams::{actor::{ApActor, Person}, iri}; /// /// let actor = ApActor::new(iri!("https://inbox.url"), Person::new()); /// /// let ( /// inbox, /// outbox, /// following, /// followers, /// liked, /// streams, /// preferred_username, /// endpoints, /// person, /// ) = actor.into_parts(); /// # Ok(()) /// # } /// ``` pub fn into_parts( self, ) -> ( IriString, Option, Option, Option, Option, Option>, Option, Option>, Inner, ) { ( self.inbox, self.outbox, self.following, self.followers, self.liked, self.streams, self.preferred_username, self.endpoints, self.inner, ) } fn extending(mut inner: Inner) -> Result where Inner: UnparsedMut + markers::Actor, { let inbox = inner.remove("inbox")?; let outbox = inner.remove("outbox")?; let following = inner.remove("following")?; let followers = inner.remove("followers")?; let liked = inner.remove("liked")?; let streams = inner.remove("streams")?; let preferred_username = inner.remove("preferredUsername")?; let endpoints = inner.remove("endpoints")?; Ok(ApActor { inbox, outbox, following, followers, liked, streams, preferred_username, endpoints, inner, }) } fn retracting(self) -> Result where Inner: UnparsedMut + markers::Actor, { let ApActor { inbox, outbox, following, followers, liked, streams, preferred_username, endpoints, mut inner, } = self; inner .insert("endpoints", endpoints)? .insert("preferredUsername", preferred_username)? .insert("streams", streams)? .insert("liked", liked)? .insert("followers", followers)? .insert("following", following)? .insert("outbox", outbox)? .insert("inbox", inbox)?; Ok(inner) } } impl Endpoints { /// Map the URLs in Endpoints from T to U /// /// ```rust /// # fn main() -> Result<(), anyhow::Error> { /// use activitystreams::{actor::Endpoints, iri}; /// use iri_string::types::IriString; /// /// let endpoints: Endpoints = Endpoints { /// shared_inbox: Some(iri!("https://example.com")), /// ..Default::default() /// }; /// /// let endpoint_strings = endpoints.map(|u| u.to_string()); /// /// assert_eq!(endpoint_strings.shared_inbox, Some(String::from("https://example.com"))); /// # Ok(()) /// # } /// ``` pub fn map(self, f: F) -> Endpoints where F: Fn(T) -> U + Copy, { Endpoints { proxy_url: self.proxy_url.map(f), oauth_authorization_endpoint: self.oauth_authorization_endpoint.map(f), oauth_token_endpoint: self.oauth_token_endpoint.map(f), provide_client_key: self.provide_client_key.map(f), sign_client_key: self.sign_client_key.map(f), shared_inbox: self.shared_inbox.map(f), nonstandard: self .nonstandard .into_iter() .map(|(k, v)| (k, (f)(v))) .collect(), } } } impl Default for Endpoints { fn default() -> Self { Endpoints { proxy_url: None, oauth_authorization_endpoint: None, oauth_token_endpoint: None, provide_client_key: None, sign_client_key: None, shared_inbox: None, nonstandard: HashMap::new(), } } } impl markers::Base for Actor {} impl markers::Object for Actor {} impl markers::Actor for Actor {} impl markers::Base for ApActor where Inner: markers::Base {} impl markers::Object for ApActor where Inner: markers::Object {} impl markers::Actor for ApActor where Inner: markers::Actor {} impl markers::Actor for ApObject where Inner: markers::Actor {} impl Extends for ApActor where Inner: Extends + UnparsedMut + markers::Actor, Error: From + std::error::Error, { type Kind = Inner::Kind; type Error = Error; fn extends(base: Base) -> Result { let inner = Inner::extends(base)?; Ok(Self::extending(inner)?) } fn retracts(self) -> Result, Self::Error> { let inner = self.retracting()?; inner.retracts() } } impl UnparsedMut for ApActor where Inner: UnparsedMut, { fn unparsed_mut(&mut self) -> &mut Unparsed { self.inner.unparsed_mut() } } impl AsBase for ApActor where Inner: AsBase, { type Kind = Inner::Kind; fn base_ref(&self) -> &Base { self.inner.base_ref() } fn base_mut(&mut self) -> &mut Base { self.inner.base_mut() } } impl AsObject for ApActor where Inner: AsObject, { type Kind = Inner::Kind; fn object_ref(&self) -> &Object { self.inner.object_ref() } fn object_mut(&mut self) -> &mut Object { self.inner.object_mut() } } impl AsApActor for ApActor where Inner: markers::Actor, { type Inner = Inner; fn ap_actor_ref(&self) -> &ApActor { self } fn ap_actor_mut(&mut self) -> &mut ApActor { self } } impl AsApObject for ApActor where Inner: AsApObject, { type Inner = Inner::Inner; fn ap_object_ref(&self) -> &ApObject { self.inner.ap_object_ref() } fn ap_object_mut(&mut self) -> &mut ApObject { self.inner.ap_object_mut() } } impl Extends for Actor { type Kind = Kind; type Error = serde_json::Error; fn extends(base: Base) -> Result { Object::extends(base).map(Actor) } fn retracts(self) -> Result, Self::Error> { self.0.retracts() } } impl UnparsedMut for Actor { fn unparsed_mut(&mut self) -> &mut Unparsed { self.0.unparsed_mut() } } impl AsBase for Actor { type Kind = Kind; fn base_ref(&self) -> &Base { self.0.base_ref() } fn base_mut(&mut self) -> &mut Base { self.0.base_mut() } } impl AsObject for Actor { type Kind = Kind; fn object_ref(&self) -> &Object { self.0.object_ref() } fn object_mut(&mut self) -> &mut Object { self.0.object_mut() } } impl ApActorExt for T where T: AsApActor {} impl AsApActor for ApObject where Inner: AsApActor, { type Inner = Inner::Inner; fn ap_actor_ref(&self) -> &ApActor { self.inner().ap_actor_ref() } fn ap_actor_mut(&mut self) -> &mut ApActor { self.inner_mut().ap_actor_mut() } } impl Default for Actor where Kind: Default, { fn default() -> Self { Self::new() } }