use actix_web::{web, HttpResponse, Scope}; use actix_web_httpauth::extractors::bearer::BearerAuth; use crate::activitypub::builders::update_person::prepare_update_person; use crate::config::Config; use crate::database::{Pool, get_database_client}; use crate::errors::{HttpError, ValidationError}; use crate::ethereum::contracts::ContractSet; use crate::ethereum::subscriptions::{ create_subscription_signature, is_registered_recipient, }; 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; pub async fn authorize_subscription( auth: BearerAuth, config: web::Data, db_pool: web::Data, query_params: web::Query, ) -> Result { let db_client = &**get_database_client(&db_pool).await?; let current_user = get_current_user(db_client, auth.token()).await?; let ethereum_config = config.blockchain.as_ref() .ok_or(HttpError::NotSupported)? .ethereum_config() .ok_or(HttpError::NotSupported)?; // The user must have a public wallet address, // because subscribers should be able // to verify that payments are actually sent to the recipient. let wallet_address = current_user .public_wallet_address(&config.default_currency()) .ok_or(HttpError::PermissionError)?; let signature = create_subscription_signature( ethereum_config, &wallet_address, query_params.price, ).map_err(|_| HttpError::InternalError)?; Ok(HttpResponse::Ok().json(signature)) } pub async fn subscriptions_enabled( auth: BearerAuth, config: web::Data, db_pool: web::Data, maybe_blockchain: web::Data>, ) -> 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() { // Add payment option to profile let mut profile_data = ProfileUpdateData::from(¤t_user.profile); profile_data.payment_options = vec![PaymentOption::EthereumSubscription]; current_user.profile = update_profile( db_client, ¤t_user.id, profile_data, ).await?; // Federate prepare_update_person(db_client, config.instance(), ¤t_user) .await?.spawn_deliver(); }; let account = Account::from_user(current_user, &config.instance_url()); Ok(HttpResponse::Ok().json(account)) } pub fn subscription_api_scope() -> Scope { web::scope("/api/v1/subscriptions") .route("/authorize", web::get().to(authorize_subscription)) .route("/enable", web::post().to(subscriptions_enabled)) }