Attach subscription page link to actor object
This commit is contained in:
parent
1554780b35
commit
33a711b91c
6 changed files with 129 additions and 29 deletions
|
@ -1,11 +1,23 @@
|
|||
use crate::activitypub::vocabulary::{IDENTITY_PROOF, PROPERTY_VALUE};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::activitypub::vocabulary::{
|
||||
IDENTITY_PROOF,
|
||||
LINK,
|
||||
PROPERTY_VALUE,
|
||||
};
|
||||
use crate::errors::ValidationError;
|
||||
use crate::ethereum::identity::{
|
||||
ETHEREUM_EIP191_PROOF,
|
||||
DidPkh,
|
||||
verify_identity_proof,
|
||||
};
|
||||
use crate::models::profiles::types::{ExtraField, IdentityProof};
|
||||
use crate::frontend::get_subscription_page_url;
|
||||
use crate::models::profiles::types::{
|
||||
ExtraField,
|
||||
IdentityProof,
|
||||
PaymentOption,
|
||||
PaymentType,
|
||||
};
|
||||
use super::types::ActorAttachment;
|
||||
|
||||
pub fn attach_identity_proof(
|
||||
|
@ -15,6 +27,7 @@ pub fn attach_identity_proof(
|
|||
object_type: IDENTITY_PROOF.to_string(),
|
||||
name: proof.issuer.to_string(),
|
||||
value: None,
|
||||
href: None,
|
||||
signature_algorithm: Some(proof.proof_type),
|
||||
signature_value: Some(proof.value),
|
||||
}
|
||||
|
@ -49,6 +62,43 @@ pub fn parse_identity_proof(
|
|||
Ok(proof)
|
||||
}
|
||||
|
||||
pub fn attach_payment_option(
|
||||
instance_url: &str,
|
||||
user_id: &Uuid,
|
||||
payment_option: PaymentOption,
|
||||
) -> ActorAttachment {
|
||||
match payment_option.payment_type {
|
||||
PaymentType::Link => unimplemented!(),
|
||||
PaymentType::EthereumSubscription => {
|
||||
let name = format!("{:?}", payment_option.payment_type);
|
||||
let subscription_page_url =
|
||||
get_subscription_page_url(instance_url, user_id);
|
||||
ActorAttachment {
|
||||
object_type: LINK.to_string(),
|
||||
name: name,
|
||||
value: None,
|
||||
href: Some(subscription_page_url),
|
||||
signature_algorithm: None,
|
||||
signature_value: None,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_payment_option(
|
||||
attachment: &ActorAttachment,
|
||||
) -> Result<PaymentOption, ValidationError> {
|
||||
if attachment.object_type != LINK {
|
||||
return Err(ValidationError("invalid attachment type"));
|
||||
};
|
||||
let payment_option = PaymentOption {
|
||||
payment_type: PaymentType::Link,
|
||||
name: Some(attachment.name.clone()),
|
||||
href: attachment.href.clone(),
|
||||
};
|
||||
Ok(payment_option)
|
||||
}
|
||||
|
||||
pub fn attach_extra_field(
|
||||
field: ExtraField,
|
||||
) -> ActorAttachment {
|
||||
|
@ -56,6 +106,7 @@ pub fn attach_extra_field(
|
|||
object_type: PROPERTY_VALUE.to_string(),
|
||||
name: field.name,
|
||||
value: Some(field.value),
|
||||
href: None,
|
||||
signature_algorithm: None,
|
||||
signature_value: None,
|
||||
}
|
||||
|
@ -79,8 +130,11 @@ pub fn parse_extra_field(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::utils::id::new_uuid;
|
||||
use super::*;
|
||||
|
||||
const INSTANCE_URL: &str = "https://example.com";
|
||||
|
||||
#[test]
|
||||
fn test_extra_field() {
|
||||
let field = ExtraField {
|
||||
|
@ -90,8 +144,30 @@ mod tests {
|
|||
};
|
||||
let attachment = attach_extra_field(field.clone());
|
||||
assert_eq!(attachment.object_type, PROPERTY_VALUE);
|
||||
|
||||
let parsed_field = parse_extra_field(&attachment).unwrap();
|
||||
assert_eq!(parsed_field.name, field.name);
|
||||
assert_eq!(parsed_field.value, field.value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_payment_option() {
|
||||
let user_id = new_uuid();
|
||||
let payment_option = PaymentOption::subscription();
|
||||
let subscription_page_url =
|
||||
format!("https://example.com/profile/{}/subscription", user_id);
|
||||
let attachment = attach_payment_option(
|
||||
INSTANCE_URL,
|
||||
&user_id,
|
||||
payment_option,
|
||||
);
|
||||
assert_eq!(attachment.object_type, LINK);
|
||||
assert_eq!(attachment.name, "EthereumSubscription");
|
||||
assert_eq!(attachment.href.as_deref().unwrap(), subscription_page_url);
|
||||
|
||||
let parsed_option = parse_payment_option(&attachment).unwrap();
|
||||
assert!(matches!(parsed_option.payment_type, PaymentType::Link));
|
||||
assert_eq!(parsed_option.name.unwrap(), "EthereumSubscription");
|
||||
assert_eq!(parsed_option.href.unwrap(), subscription_page_url);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,25 @@ use serde_json::{json, Value};
|
|||
use crate::activitypub::{
|
||||
constants::{ACTOR_KEY_SUFFIX, AP_CONTEXT},
|
||||
identifiers::{local_actor_id, LocalActorCollection},
|
||||
vocabulary::{IDENTITY_PROOF, IMAGE, PERSON, PROPERTY_VALUE, SERVICE},
|
||||
vocabulary::{IDENTITY_PROOF, IMAGE, LINK, PERSON, PROPERTY_VALUE, SERVICE},
|
||||
};
|
||||
use crate::config::Instance;
|
||||
use crate::models::profiles::types::{ExtraField, IdentityProof};
|
||||
use crate::errors::ValidationError;
|
||||
use crate::models::profiles::types::{
|
||||
ExtraField,
|
||||
IdentityProof,
|
||||
PaymentOption,
|
||||
};
|
||||
use crate::models::users::types::User;
|
||||
use crate::utils::crypto::{deserialize_private_key, get_public_key_pem};
|
||||
use crate::utils::files::get_file_url;
|
||||
use super::attachments::{
|
||||
attach_extra_field,
|
||||
attach_identity_proof,
|
||||
attach_payment_option,
|
||||
parse_extra_field,
|
||||
parse_identity_proof,
|
||||
parse_payment_option,
|
||||
};
|
||||
|
||||
const W3ID_CONTEXT: &str = "https://w3id.org/security/v1";
|
||||
|
@ -48,6 +55,9 @@ pub struct ActorAttachment {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub value: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub href: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub signature_algorithm: Option<String>,
|
||||
|
||||
|
@ -119,46 +129,49 @@ impl Actor {
|
|||
Ok(actor_address)
|
||||
}
|
||||
|
||||
pub fn parse_attachments(&self) -> (Vec<IdentityProof>, Vec<ExtraField>) {
|
||||
pub fn parse_attachments(&self) -> (
|
||||
Vec<IdentityProof>,
|
||||
Vec<PaymentOption>,
|
||||
Vec<ExtraField>,
|
||||
) {
|
||||
let mut identity_proofs = vec![];
|
||||
let mut payment_options = vec![];
|
||||
let mut extra_fields = vec![];
|
||||
let log_error = |attachment: &ActorAttachment, error| {
|
||||
log::warn!(
|
||||
"ignoring actor attachment of type {}: {}",
|
||||
attachment.object_type,
|
||||
error,
|
||||
);
|
||||
};
|
||||
if let Some(attachments) = &self.attachment {
|
||||
for attachment in attachments {
|
||||
match attachment.object_type.as_str() {
|
||||
IDENTITY_PROOF => {
|
||||
match parse_identity_proof(&self.id, attachment) {
|
||||
Ok(proof) => identity_proofs.push(proof),
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"ignoring actor attachment of type {}: {}",
|
||||
attachment.object_type,
|
||||
error,
|
||||
);
|
||||
},
|
||||
Err(error) => log_error(attachment, error),
|
||||
};
|
||||
},
|
||||
LINK => {
|
||||
match parse_payment_option(attachment) {
|
||||
Ok(option) => payment_options.push(option),
|
||||
Err(error) => log_error(attachment, error),
|
||||
};
|
||||
},
|
||||
PROPERTY_VALUE => {
|
||||
match parse_extra_field(attachment) {
|
||||
Ok(field) => extra_fields.push(field),
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"ignoring actor attachment of type {}: {}",
|
||||
attachment.object_type,
|
||||
error,
|
||||
);
|
||||
},
|
||||
Err(error) => log_error(attachment, error),
|
||||
};
|
||||
},
|
||||
_ => {
|
||||
log::warn!(
|
||||
"ignoring actor attachment of type {}",
|
||||
attachment.object_type,
|
||||
);
|
||||
log_error(attachment, ValidationError("unsupported type"));
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
(identity_proofs, extra_fields)
|
||||
(identity_proofs, payment_options, extra_fields)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,6 +244,14 @@ pub fn get_local_actor(
|
|||
let attachment = attach_identity_proof(proof);
|
||||
attachments.push(attachment);
|
||||
};
|
||||
for payment_option in user.profile.payment_options.clone().into_inner() {
|
||||
let attachment = attach_payment_option(
|
||||
instance_url,
|
||||
&user.id,
|
||||
payment_option,
|
||||
);
|
||||
attachments.push(attachment);
|
||||
};
|
||||
for field in user.profile.extra_fields.clone().into_inner() {
|
||||
let attachment = attach_extra_field(field);
|
||||
attachments.push(attachment);
|
||||
|
|
|
@ -69,7 +69,8 @@ async fn prepare_remote_profile_data(
|
|||
};
|
||||
let avatar = fetch_actor_avatar(&actor, media_dir, None).await;
|
||||
let banner = fetch_actor_banner(&actor, media_dir, None).await;
|
||||
let (identity_proofs, extra_fields) = actor.parse_attachments();
|
||||
let (identity_proofs, payment_options, extra_fields) =
|
||||
actor.parse_attachments();
|
||||
let profile_data = ProfileCreateData {
|
||||
username: actor.preferred_username.clone(),
|
||||
display_name: actor.name.clone(),
|
||||
|
@ -78,7 +79,7 @@ async fn prepare_remote_profile_data(
|
|||
avatar,
|
||||
banner,
|
||||
identity_proofs,
|
||||
payment_options: vec![],
|
||||
payment_options,
|
||||
extra_fields,
|
||||
actor_json: Some(actor),
|
||||
};
|
||||
|
|
|
@ -56,7 +56,8 @@ pub async fn update_remote_profile(
|
|||
};
|
||||
let avatar = fetch_actor_avatar(&actor, media_dir, profile.avatar_file_name).await;
|
||||
let banner = fetch_actor_banner(&actor, media_dir, profile.banner_file_name).await;
|
||||
let (identity_proofs, extra_fields) = actor.parse_attachments();
|
||||
let (identity_proofs, payment_options, extra_fields) =
|
||||
actor.parse_attachments();
|
||||
let mut profile_data = ProfileUpdateData {
|
||||
display_name: actor.name.clone(),
|
||||
bio: actor.summary.clone(),
|
||||
|
@ -64,7 +65,7 @@ pub async fn update_remote_profile(
|
|||
avatar,
|
||||
banner,
|
||||
identity_proofs,
|
||||
payment_options: vec![],
|
||||
payment_options,
|
||||
extra_fields,
|
||||
actor_json: Some(actor),
|
||||
};
|
||||
|
|
|
@ -34,4 +34,5 @@ pub const ORDERED_COLLECTION_PAGE: &str = "OrderedCollectionPage";
|
|||
// Misc
|
||||
pub const HASHTAG: &str = "Hashtag";
|
||||
pub const IDENTITY_PROOF: &str = "IdentityProof";
|
||||
pub const LINK: &str = "Link";
|
||||
pub const PROPERTY_VALUE: &str = "PropertyValue";
|
||||
|
|
|
@ -34,7 +34,7 @@ impl From<&EventType> for i16 {
|
|||
EventType::Mention => 5,
|
||||
EventType::Repost => 6,
|
||||
EventType::Subscription => 7,
|
||||
EventType::SubscriptionStart => panic!("not supported"),
|
||||
EventType::SubscriptionStart => unimplemented!("not supported"),
|
||||
EventType::SubscriptionExpiration => 9,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue