diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 3575ea1..6832973 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -626,6 +626,8 @@ paths: /api/v1/subscriptions/authorize: get: summary: Get authorization for setting up Ethereum subscription. + security: + - tokenAuth: [] parameters: - name: price in: query @@ -647,6 +649,22 @@ paths: /api/v1/subscriptions/enable: post: summary: Enable subscriptions + security: + - tokenAuth: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + type: + description: Subscription type + type: string + enum: + - ethereum + - monero + required: + - type responses: 200: description: Successful operation diff --git a/src/mastodon_api/subscriptions/types.rs b/src/mastodon_api/subscriptions/types.rs index 375f317..8924dd2 100644 --- a/src/mastodon_api/subscriptions/types.rs +++ b/src/mastodon_api/subscriptions/types.rs @@ -4,3 +4,12 @@ use serde::Deserialize; pub struct SubscriptionQueryParams { pub price: u64, } + +#[derive(Deserialize)] +#[serde(tag = "type")] +pub enum SubscriptionSettings { + #[serde(rename = "ethereum")] + Ethereum, + #[serde(rename = "monero")] + Monero { }, +} diff --git a/src/mastodon_api/subscriptions/views.rs b/src/mastodon_api/subscriptions/views.rs index 64397dd..7164503 100644 --- a/src/mastodon_api/subscriptions/views.rs +++ b/src/mastodon_api/subscriptions/views.rs @@ -13,8 +13,16 @@ use crate::ethereum::subscriptions::{ use crate::mastodon_api::accounts::types::Account; use crate::mastodon_api::oauth::auth::get_current_user; use crate::models::profiles::queries::update_profile; -use crate::models::profiles::types::{PaymentOption, ProfileUpdateData}; -use super::types::SubscriptionQueryParams; +use crate::models::profiles::types::{ + PaymentOption, + PaymentType, + ProfileUpdateData, +}; +use crate::utils::currencies::Currency; +use super::types::{ + SubscriptionQueryParams, + SubscriptionSettings, +}; pub async fn authorize_subscription( auth: BearerAuth, @@ -47,24 +55,40 @@ pub async fn subscriptions_enabled( config: web::Data, db_pool: web::Data, maybe_blockchain: web::Data>, + subscription_settings: web::Json, ) -> Result { let db_client = &**get_database_client(&db_pool).await?; let mut current_user = get_current_user(db_client, auth.token()).await?; - let contract_set = maybe_blockchain.as_ref().as_ref() - .ok_or(HttpError::NotSupported)?; - let wallet_address = current_user - .public_wallet_address(&config.default_currency()) - .ok_or(HttpError::PermissionError)?; - let is_registered = is_registered_recipient(contract_set, &wallet_address) - .await.map_err(|_| HttpError::InternalError)?; - if !is_registered { - return Err(ValidationError("recipient is not registered").into()); - }; - if current_user.profile.payment_options.is_empty() { + let mut maybe_payment_option = None; + match subscription_settings.into_inner() { + SubscriptionSettings::Ethereum => { + let contract_set = maybe_blockchain.as_ref().as_ref() + .ok_or(HttpError::NotSupported)?; + let wallet_address = current_user + .public_wallet_address(&Currency::Ethereum) + .ok_or(HttpError::PermissionError)?; + if !current_user.profile.payment_options + .any(PaymentType::EthereumSubscription) + { + let is_registered = is_registered_recipient( + contract_set, + &wallet_address, + ).await.map_err(|_| HttpError::InternalError)?; + if !is_registered { + return Err(ValidationError("recipient is not registered").into()); + }; + maybe_payment_option = Some(PaymentOption::EthereumSubscription); + }; + }, + SubscriptionSettings::Monero { } => { + todo!(); + }, + }; + if let Some(payment_option) = maybe_payment_option { // Add payment option to profile let mut profile_data = ProfileUpdateData::from(¤t_user.profile); - profile_data.payment_options = vec![PaymentOption::EthereumSubscription]; + profile_data.payment_options.push(payment_option); current_user.profile = update_profile( db_client, ¤t_user.id, diff --git a/src/models/profiles/types.rs b/src/models/profiles/types.rs index 41f884e..0927c22 100644 --- a/src/models/profiles/types.rs +++ b/src/models/profiles/types.rs @@ -42,6 +42,7 @@ impl IdentityProofs { json_from_sql!(IdentityProofs); json_to_sql!(IdentityProofs); +#[derive(PartialEq)] pub enum PaymentType { Link, EthereumSubscription, @@ -81,6 +82,15 @@ pub enum PaymentOption { EthereumSubscription, } +impl PaymentOption { + fn payment_type(&self) -> PaymentType { + match self { + Self::Link(_) => PaymentType::Link, + Self::EthereumSubscription => PaymentType::EthereumSubscription, + } + } +} + // Integer tags are not supported https://github.com/serde-rs/serde/issues/745 // Workaround: https://stackoverflow.com/a/65576570 impl<'de> Deserialize<'de> for PaymentOption { @@ -110,10 +120,7 @@ impl Serialize for PaymentOption { where S: Serializer, { let mut map = serializer.serialize_map(None)?; - let payment_type = match self { - Self::Link(_) => PaymentType::Link, - Self::EthereumSubscription => PaymentType::EthereumSubscription, - }; + let payment_type = self.payment_type(); map.serialize_entry("payment_type", &i16::from(&payment_type))?; match self { @@ -137,6 +144,14 @@ impl PaymentOptions { let Self(payment_options) = self; payment_options.is_empty() } + + /// Returns true if payment option list contains at least one option + /// of the given type. + pub fn any(&self, payment_type: PaymentType) -> bool { + let Self(payment_options) = self; + payment_options.iter() + .any(|option| option.payment_type() == payment_type) + } } json_from_sql!(PaymentOptions);