mirror of
https://git.asonix.dog/asonix/activitystreams.git
synced 2025-04-16 13:14:06 +00:00
Start checking again
This commit is contained in:
parent
71fae0bbd4
commit
aef1bdf588
10 changed files with 460 additions and 43 deletions
52
.drone.yml
52
.drone.yml
|
@ -39,7 +39,7 @@ trigger:
|
|||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: tests
|
||||
name: tests-amd64
|
||||
|
||||
platform:
|
||||
arch: amd64
|
||||
|
@ -70,6 +70,39 @@ trigger:
|
|||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: tests-arm64v8
|
||||
|
||||
platform:
|
||||
arch: arm64
|
||||
|
||||
clone:
|
||||
disable: true
|
||||
|
||||
steps:
|
||||
- name: clone
|
||||
image: alpine/git:latest
|
||||
user: root
|
||||
commands:
|
||||
- git clone $DRONE_GIT_HTTP_URL .
|
||||
- git checkout $DRONE_COMMIT
|
||||
- chown -R 991:991 .
|
||||
|
||||
- name: tests
|
||||
image: asonix/rust-builder:latest-linux-amd64
|
||||
pull: always
|
||||
commands:
|
||||
- cargo test
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: check-amd64
|
||||
|
@ -210,6 +243,11 @@ trigger:
|
|||
event:
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- clippy
|
||||
- tests-amd64
|
||||
- tests-arm64v8
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
|
@ -242,6 +280,11 @@ trigger:
|
|||
event:
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- clippy
|
||||
- tests-amd64
|
||||
- tests-arm64v8
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
|
@ -274,6 +317,11 @@ trigger:
|
|||
event:
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- clippy
|
||||
- tests-amd64
|
||||
- tests-arm64v8
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
|
@ -328,8 +376,6 @@ steps:
|
|||
- cargo publish -p activitystreams-ext --token $CRATES_IO_TOKEN
|
||||
|
||||
depends_on:
|
||||
- clippy
|
||||
- tests
|
||||
- build-amd64
|
||||
- build-arm64v8
|
||||
- build-arm32v7
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
# Unreleased
|
||||
- implement `IntoIterator` for `&OneOrMany<T>` and `&mut OneOrMany<T>`
|
||||
- add `check` function for verifying an IRI's authority
|
||||
- add `BaseExt::check_authority` for verifying an IRI's authority against an object's ID
|
||||
- add back checked `Base::id`, `Activity::actor`, `Activity::object`, `Actor::inbox`,
|
||||
`Actor::outbox`, `Actor::following`, `Actor::followers`, `Actor::liked`, `Actor::streams`,
|
||||
`Actor::endpoints`
|
||||
|
||||
# 0.7.0-alpha.14
|
||||
- switch to iri-string from url
|
||||
|
|
|
@ -19,8 +19,8 @@ members = [
|
|||
]
|
||||
|
||||
[dependencies]
|
||||
activitystreams-kinds = { version = "0.1.0", path = "./activitystreams-kinds/", default-features = false, features = ["iri-string"] }
|
||||
iri-string = { version = "0.4.1", features = ["serde", "serde-std"] }
|
||||
activitystreams-kinds = { version = "0.2.0", path = "./activitystreams-kinds/", default-features = false, features = ["iri-string"] }
|
||||
iri-string = { version = "0.5.0-beta.1", features = ["alloc", "serde", "serde-alloc", "serde-std", "std"] }
|
||||
mime = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "activitystreams-kinds"
|
||||
description = "Type-safe activitystreams 'type' values"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
license = "GPL-3.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
repository = "https://git.asonix.dog/asonix/activitystreams"
|
||||
|
@ -17,7 +17,7 @@ default = ["url"]
|
|||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
url = { version = "2", optional = true }
|
||||
iri-string = { version = "0.4.1", optional = true }
|
||||
iri-string = { version = "0.5.0-beta.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1"
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
//! ```
|
||||
use crate::{
|
||||
base::{AnyBase, AsBase, Base, Extends},
|
||||
checked::CheckError,
|
||||
markers,
|
||||
object::{ApObject, AsObject, Object},
|
||||
prelude::BaseExt,
|
||||
primitives::OneOrMany,
|
||||
unparsed::{Unparsed, UnparsedMut, UnparsedMutExt},
|
||||
};
|
||||
|
@ -420,7 +422,32 @@ pub trait ActorAndObjectRefExt: ActorAndObjectRef {
|
|||
/// let actor_ref = create.actor();
|
||||
/// println!("{:?}", actor_ref);
|
||||
/// ```
|
||||
fn actor(&self) -> &OneOrMany<AnyBase> {
|
||||
fn actor<Kind>(&self) -> Result<&OneOrMany<AnyBase>, CheckError>
|
||||
where
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
let actor = self.actor_unchecked();
|
||||
|
||||
for any_base in actor {
|
||||
let id = any_base.id().ok_or(CheckError)?;
|
||||
self.check_authority(id)?;
|
||||
}
|
||||
|
||||
Ok(actor)
|
||||
}
|
||||
|
||||
/// Fetch the actor for the current activity
|
||||
///
|
||||
/// ```rust
|
||||
/// # use activitystreams::{context, activity::Create};
|
||||
/// # let mut create = Create::new(context(), context());
|
||||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// let actor_ref = create.actor_unchecked();
|
||||
/// println!("{:?}", actor_ref);
|
||||
/// ```
|
||||
fn actor_unchecked(&self) -> &OneOrMany<AnyBase> {
|
||||
self.actor_field_ref()
|
||||
}
|
||||
|
||||
|
@ -439,7 +466,7 @@ pub trait ActorAndObjectRefExt: ActorAndObjectRef {
|
|||
/// # }
|
||||
/// ```
|
||||
fn actor_is(&self, id: &IriString) -> bool {
|
||||
self.actor().is_single_id(id)
|
||||
self.actor_unchecked().is_single_id(id)
|
||||
}
|
||||
|
||||
/// Set the actor for the current activity
|
||||
|
@ -526,7 +553,32 @@ pub trait ActorAndObjectRefExt: ActorAndObjectRef {
|
|||
/// let object_ref = create.object();
|
||||
/// println!("{:?}", object_ref);
|
||||
/// ```
|
||||
fn object(&self) -> &OneOrMany<AnyBase> {
|
||||
fn object<Kind>(&self) -> Result<&OneOrMany<AnyBase>, CheckError>
|
||||
where
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
let object = self.object_unchecked();
|
||||
|
||||
for any_base in object {
|
||||
let id = any_base.id().ok_or(CheckError)?;
|
||||
self.check_authority(id)?;
|
||||
}
|
||||
|
||||
Ok(object)
|
||||
}
|
||||
|
||||
/// Fetch the object for the current activity
|
||||
///
|
||||
/// ```rust
|
||||
/// # use activitystreams::{context, activity::Create};
|
||||
/// # let mut create = Create::new(context(), context());
|
||||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// let object_ref = create.object_unchecked();
|
||||
/// println!("{:?}", object_ref);
|
||||
/// ```
|
||||
fn object_unchecked(&self) -> &OneOrMany<AnyBase> {
|
||||
self.object_field_ref()
|
||||
}
|
||||
|
||||
|
@ -545,7 +597,7 @@ pub trait ActorAndObjectRefExt: ActorAndObjectRef {
|
|||
/// # }
|
||||
/// ```
|
||||
fn object_is(&self, id: &IriString) -> bool {
|
||||
self.object().is_single_id(id)
|
||||
self.object_unchecked().is_single_id(id)
|
||||
}
|
||||
|
||||
/// Set the object for the current activity
|
||||
|
|
242
src/actor.rs
242
src/actor.rs
|
@ -23,8 +23,10 @@
|
|||
//! ```
|
||||
use crate::{
|
||||
base::{AsBase, Base, Extends},
|
||||
checked::CheckError,
|
||||
markers,
|
||||
object::{ApObject, AsApObject, AsObject, Object},
|
||||
prelude::BaseExt,
|
||||
primitives::OneOrMany,
|
||||
unparsed::{Unparsed, UnparsedMut, UnparsedMutExt},
|
||||
};
|
||||
|
@ -60,7 +62,25 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
///
|
||||
/// let inbox_ref = person.inbox();
|
||||
/// ```
|
||||
fn inbox<'a>(&'a self) -> &'a IriString
|
||||
fn inbox<'a, Kind>(&'a self) -> Result<&'a IriString, CheckError>
|
||||
where
|
||||
Inner: 'a,
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
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
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -109,7 +129,26 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
///
|
||||
/// let outbox_ref = person.outbox();
|
||||
/// ```
|
||||
fn outbox<'a>(&'a self) -> Option<&'a IriString>
|
||||
fn outbox<'a, Kind>(&'a self) -> Result<Option<&'a IriString>, CheckError>
|
||||
where
|
||||
Inner: 'a,
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
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
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -175,9 +214,9 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # person.set_outbox(iri!("https://example.com/outbox"));
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(person.outbox().is_some());
|
||||
/// assert!(person.outbox_unchecked().is_some());
|
||||
/// person.delete_outbox();
|
||||
/// assert!(person.outbox().is_none());
|
||||
/// assert!(person.outbox_unchecked().is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -193,11 +232,32 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # let mut person = ApActor::new(context(), Person::new());
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(following) = person.following() {
|
||||
/// if let Ok(following) = person.following() {
|
||||
/// println!("{:?}", following);
|
||||
/// }
|
||||
/// ```
|
||||
fn following<'a>(&'a self) -> Option<&'a IriString>
|
||||
fn following<'a, Kind>(&'a self) -> Result<Option<&'a IriString>, CheckError>
|
||||
where
|
||||
Inner: 'a,
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
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
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -263,9 +323,9 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # person.set_following(iri!("https://example.com/following"));
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(person.following().is_some());
|
||||
/// assert!(person.following_unchecked().is_some());
|
||||
/// person.delete_following();
|
||||
/// assert!(person.following().is_none());
|
||||
/// assert!(person.following_unchecked().is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -281,11 +341,32 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # let mut person = ApActor::new(context(), Person::new());
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(followers) = person.followers() {
|
||||
/// if let Ok(followers) = person.followers() {
|
||||
/// println!("{:?}", followers);
|
||||
/// }
|
||||
/// ```
|
||||
fn followers<'a>(&'a self) -> Option<&'a IriString>
|
||||
fn followers<'a, Kind>(&'a self) -> Result<Option<&'a IriString>, CheckError>
|
||||
where
|
||||
Inner: 'a,
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
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
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -351,9 +432,9 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # person.set_followers(iri!("https://example.com/followers"));
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(person.followers().is_some());
|
||||
/// assert!(person.followers_unchecked().is_some());
|
||||
/// person.delete_followers();
|
||||
/// assert!(person.followers().is_none());
|
||||
/// assert!(person.followers_unchecked().is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -369,11 +450,32 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # let mut person = ApActor::new(context(), Person::new());
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(liked) = person.liked() {
|
||||
/// if let Ok(liked) = person.liked() {
|
||||
/// println!("{:?}", liked);
|
||||
/// }
|
||||
/// ```
|
||||
fn liked<'a>(&'a self) -> Option<&'a IriString>
|
||||
fn liked<'a, Kind>(&'a self) -> Result<Option<&'a IriString>, CheckError>
|
||||
where
|
||||
Inner: 'a,
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
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
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -439,9 +541,9 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # person.set_liked(iri!("https://example.com/liked"));
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(person.liked().is_some());
|
||||
/// assert!(person.liked_unchecked().is_some());
|
||||
/// person.delete_liked();
|
||||
/// assert!(person.liked().is_none());
|
||||
/// assert!(person.liked_unchecked().is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -457,11 +559,38 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # let mut person = ApActor::new(context(), Person::new());
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(streams) = person.streams() {
|
||||
/// if let Ok(streams) = person.streams() {
|
||||
/// println!("{:?}", streams);
|
||||
/// }
|
||||
/// ```
|
||||
fn streams<'a>(&'a self) -> Option<OneOrMany<&'a IriString>>
|
||||
fn streams<'a, Kind>(&'a self) -> Result<Option<OneOrMany<&'a IriString>>, CheckError>
|
||||
where
|
||||
Inner: 'a,
|
||||
Self: BaseExt<Kind>,
|
||||
{
|
||||
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<OneOrMany<&'a IriString>>
|
||||
where
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -581,9 +710,9 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # person.set_stream(iri!("https://example.com/streams"));
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(person.streams().is_some());
|
||||
/// assert!(person.streams_unchecked().is_some());
|
||||
/// person.delete_streams();
|
||||
/// assert!(person.streams().is_none());
|
||||
/// assert!(person.streams_unchecked().is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -662,6 +791,71 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
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, Kind>(&'a self) -> Result<Option<Endpoints<&'a IriString>>, CheckError>
|
||||
where
|
||||
Self: BaseExt<Kind>,
|
||||
Inner: 'a,
|
||||
Kind: 'a,
|
||||
{
|
||||
if let Some(endpoints) = self.endpoints_unchecked() {
|
||||
let authority_opt = self.id_unchecked().and_then(|id| id.authority_components());
|
||||
|
||||
let mut any_failed = false;
|
||||
|
||||
any_failed |= endpoints
|
||||
.proxy_url
|
||||
.map(|u| u.authority_components() != authority_opt)
|
||||
.unwrap_or(false);
|
||||
any_failed |= endpoints
|
||||
.oauth_authorization_endpoint
|
||||
.map(|u| u.authority_components() != authority_opt)
|
||||
.unwrap_or(false);
|
||||
any_failed |= endpoints
|
||||
.oauth_token_endpoint
|
||||
.map(|u| u.authority_components() != authority_opt)
|
||||
.unwrap_or(false);
|
||||
any_failed |= endpoints
|
||||
.provide_client_key
|
||||
.map(|u| u.authority_components() != authority_opt)
|
||||
.unwrap_or(false);
|
||||
any_failed |= endpoints
|
||||
.sign_client_key
|
||||
.map(|u| u.authority_components() != authority_opt)
|
||||
.unwrap_or(false);
|
||||
any_failed |= endpoints
|
||||
.shared_inbox
|
||||
.map(|u| u.authority_components() != authority_opt)
|
||||
.unwrap_or(false);
|
||||
|
||||
if any_failed {
|
||||
return Err(CheckError);
|
||||
}
|
||||
|
||||
return Ok(Some(endpoints));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Fetch the endpoints for the current actor
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -669,11 +863,11 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # let mut person = ApActor::new(context(), Person::new());
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(endpoints) = person.endpoints() {
|
||||
/// if let Some(endpoints) = person.endpoints_unchecked() {
|
||||
/// println!("{:?}", endpoints);
|
||||
/// }
|
||||
/// ```
|
||||
fn endpoints<'a>(&'a self) -> Option<Endpoints<&'a IriString>>
|
||||
fn endpoints_unchecked<'a>(&'a self) -> Option<Endpoints<&'a IriString>>
|
||||
where
|
||||
Inner: 'a,
|
||||
{
|
||||
|
@ -744,9 +938,9 @@ pub trait ApActorExt<Inner>: AsApActor<Inner> {
|
|||
/// # person.set_endpoints(Default::default());
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(person.endpoints().is_some());
|
||||
/// assert!(person.endpoints_unchecked().is_some());
|
||||
/// person.delete_endpoints();
|
||||
/// assert!(person.endpoints().is_none());
|
||||
/// assert!(person.endpoints_unchecked().is_none());
|
||||
/// ```
|
||||
fn delete_endpoints(&mut self) -> &mut Self {
|
||||
self.ap_actor_mut().endpoints = None;
|
||||
|
|
97
src/base.rs
97
src/base.rs
|
@ -28,12 +28,13 @@
|
|||
//! # }
|
||||
//! ```
|
||||
use crate::{
|
||||
checked::{check, CheckError},
|
||||
either::Either,
|
||||
markers,
|
||||
primitives::{AnyString, MimeMediaType, OneOrMany},
|
||||
unparsed::{Unparsed, UnparsedMut},
|
||||
};
|
||||
use iri_string::types::IriString;
|
||||
use iri_string::types::{IriStr, IriString};
|
||||
use mime::Mime;
|
||||
|
||||
/// Implements conversion between `Base<Kind>` and other ActivityStreams objects defined in this
|
||||
|
@ -245,6 +246,24 @@ pub trait BaseExt<Kind>: AsBase<Kind> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Check the authority of a given IRI matches this object's ID
|
||||
///
|
||||
/// ```rust
|
||||
/// # use activitystreams::{base::BaseExt, object::Video, iri};
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let video = Video::new();
|
||||
/// let res = video.check_authority(&iri!("https://example.com"));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
fn check_authority<'a, T: AsRef<IriStr>>(&self, iri: T) -> Result<T, CheckError> {
|
||||
let authority = self
|
||||
.id_unchecked()
|
||||
.and_then(|id| id.authority_components())
|
||||
.ok_or(CheckError)?;
|
||||
check(iri, authority.host(), authority.port())
|
||||
}
|
||||
|
||||
/// Fetch the id for the current object
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -253,11 +272,40 @@ pub trait BaseExt<Kind>: AsBase<Kind> {
|
|||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(id) = video.id() {
|
||||
/// if let Ok(Some(id)) = video.id("exmaple.com", Some("443")) {
|
||||
/// println!("{:?}", id);
|
||||
/// }
|
||||
/// ```
|
||||
fn id<'a>(&'a self) -> Option<&'a IriString>
|
||||
fn id<'a>(&'a self, host: &str, port: Option<&str>) -> Result<Option<&'a IriString>, CheckError>
|
||||
where
|
||||
Kind: 'a,
|
||||
{
|
||||
self.id_unchecked()
|
||||
.and_then(|id| {
|
||||
let authority = id.authority_components()?;
|
||||
|
||||
if authority.host() == host && authority.port() == port {
|
||||
Some(Ok(id))
|
||||
} else {
|
||||
Some(Err(CheckError))
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Fetch the id for the current object
|
||||
///
|
||||
/// ```rust
|
||||
/// # use activitystreams::object::Video;
|
||||
/// # let mut video = Video::new();
|
||||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(id) = video.id_unchecked() {
|
||||
/// println!("{:?}", id);
|
||||
/// }
|
||||
/// ```
|
||||
fn id_unchecked<'a>(&'a self) -> Option<&'a IriString>
|
||||
where
|
||||
Kind: 'a,
|
||||
{
|
||||
|
@ -272,11 +320,44 @@ pub trait BaseExt<Kind>: AsBase<Kind> {
|
|||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(id) = video.id_mut() {
|
||||
/// if let Ok(Some(id)) = video.id_mut("example.com", Some("443")) {
|
||||
/// println!("{:?}", id);
|
||||
/// }
|
||||
/// ```
|
||||
fn id_mut<'a>(&'a mut self) -> Option<&'a mut IriString>
|
||||
fn id_mut<'a>(
|
||||
&'a mut self,
|
||||
host: &str,
|
||||
port: Option<&str>,
|
||||
) -> Result<Option<&'a mut IriString>, CheckError>
|
||||
where
|
||||
Kind: 'a,
|
||||
{
|
||||
self.id_mut_unchecked()
|
||||
.and_then(|id| {
|
||||
let authority = id.authority_components()?;
|
||||
|
||||
if authority.host() == host && authority.port() == port {
|
||||
Some(Ok(id))
|
||||
} else {
|
||||
Some(Err(CheckError))
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Mutably borrow the ID from the current object
|
||||
///
|
||||
/// ```rust
|
||||
/// # use activitystreams::object::Video;
|
||||
/// # let mut video = Video::new();
|
||||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// if let Some(id) = video.id_mut_unchecked() {
|
||||
/// println!("{:?}", id);
|
||||
/// }
|
||||
/// ```
|
||||
fn id_mut_unchecked<'a>(&'a mut self) -> Option<&'a mut IriString>
|
||||
where
|
||||
Kind: 'a,
|
||||
{
|
||||
|
@ -296,7 +377,7 @@ pub trait BaseExt<Kind>: AsBase<Kind> {
|
|||
/// # }
|
||||
/// ```
|
||||
fn is_id(&self, id: &IriString) -> bool {
|
||||
self.id() == Some(id)
|
||||
self.id_unchecked() == Some(id)
|
||||
}
|
||||
|
||||
/// Set the id for the current object
|
||||
|
@ -344,9 +425,9 @@ pub trait BaseExt<Kind>: AsBase<Kind> {
|
|||
/// #
|
||||
/// use activitystreams::prelude::*;
|
||||
///
|
||||
/// assert!(video.id().is_some());
|
||||
/// assert!(video.id_unchecked().is_some());
|
||||
/// video.delete_id();
|
||||
/// assert!(video.id().is_none());
|
||||
/// assert!(video.id_unchecked().is_none());
|
||||
/// ```
|
||||
fn delete_id(&mut self) -> &mut Self {
|
||||
self.base_mut().id = None;
|
||||
|
|
19
src/checked.rs
Normal file
19
src/checked.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use iri_string::types::IriStr;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("IRI failed host and port check")]
|
||||
pub struct CheckError;
|
||||
|
||||
pub(crate) fn check<'a, T: AsRef<IriStr>>(
|
||||
iri: T,
|
||||
host: &str,
|
||||
port: Option<&str>,
|
||||
) -> Result<T, CheckError> {
|
||||
let authority = iri.as_ref().authority_components().ok_or(CheckError)?;
|
||||
|
||||
if authority.host() != host || authority.port() != port {
|
||||
return Err(CheckError);
|
||||
}
|
||||
|
||||
Ok(iri)
|
||||
}
|
|
@ -298,6 +298,7 @@
|
|||
pub mod activity;
|
||||
pub mod actor;
|
||||
pub mod base;
|
||||
pub mod checked;
|
||||
pub mod collection;
|
||||
mod either;
|
||||
pub mod link;
|
||||
|
|
|
@ -362,6 +362,24 @@ impl<T> IntoIterator for OneOrMany<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a OneOrMany<T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a mut OneOrMany<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = IterMut<'a, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Iter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
|
|
Loading…
Reference in a new issue