feat(router): added retrieval flow for connector file uploads and added support for stripe connector (#990)

This commit is contained in:
Sai Harsha Vardhan
2023-05-09 20:10:54 +05:30
committed by GitHub
parent d6e71b959d
commit 38aa9eab3f
16 changed files with 388 additions and 66 deletions

View File

@ -313,3 +313,25 @@ pub enum Country {
Zambia, Zambia,
Zimbabwe, Zimbabwe,
} }
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Default,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumString,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum FileUploadProvider {
#[default]
Router,
Stripe,
Checkout,
}

View File

@ -118,6 +118,7 @@ impl api::ConnectorAccessToken for Checkout {}
impl api::AcceptDispute for Checkout {} impl api::AcceptDispute for Checkout {}
impl api::PaymentToken for Checkout {} impl api::PaymentToken for Checkout {}
impl api::Dispute for Checkout {} impl api::Dispute for Checkout {}
impl api::RetrieveFile for Checkout {}
impl api::DefendDispute for Checkout {} impl api::DefendDispute for Checkout {}
impl impl
@ -773,6 +774,12 @@ impl
impl api::UploadFile for Checkout {} impl api::UploadFile for Checkout {}
impl
ConnectorIntegration<api::Retrieve, types::RetrieveFileRequestData, types::RetrieveFileResponse>
for Checkout
{
}
#[async_trait::async_trait] #[async_trait::async_trait]
impl api::FileUpload for Checkout { impl api::FileUpload for Checkout {
fn validate_file_upload( fn validate_file_upload(

View File

@ -1199,6 +1199,98 @@ impl
} }
} }
impl api::RetrieveFile for Stripe {}
impl
services::ConnectorIntegration<
api::Retrieve,
types::RetrieveFileRequestData,
types::RetrieveFileResponse,
> for Stripe
{
fn get_headers(
&self,
req: &types::RouterData<
api::Retrieve,
types::RetrieveFileRequestData,
types::RetrieveFileResponse,
>,
_connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
self.get_auth_header(&req.connector_auth_type)
}
fn get_url(
&self,
req: &types::RetrieveFileRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!(
"{}v1/files/{}/contents",
connectors.stripe.base_url_file_upload, req.request.provider_file_id
))
}
fn build_request(
&self,
req: &types::RetrieveFileRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Get)
.url(&types::RetrieveFileType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::RetrieveFileType::get_headers(self, req, connectors)?)
.build(),
))
}
#[instrument(skip_all)]
fn handle_response(
&self,
data: &types::RetrieveFileRouterData,
res: types::Response,
) -> CustomResult<
types::RouterData<
api::Retrieve,
types::RetrieveFileRequestData,
types::RetrieveFileResponse,
>,
errors::ConnectorError,
> {
let response = res.response;
Ok(types::RetrieveFileRouterData {
response: Ok(types::RetrieveFileResponse {
file_data: response.to_vec(),
}),
..data.clone()
})
}
fn get_error_response(
&self,
res: types::Response,
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
let response: stripe::ErrorResponse = res
.response
.parse_struct("ErrorResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
Ok(types::ErrorResponse {
status_code: res.status_code,
code: response
.error
.code
.unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
message: response
.error
.message
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
reason: None,
})
}
}
impl api::SubmitEvidence for Stripe {} impl api::SubmitEvidence for Stripe {}
impl impl

View File

@ -3,7 +3,7 @@ use common_utils::errors::CustomResult;
use crate::{ use crate::{
core::{errors, files::helpers::retrieve_file_and_provider_file_id_from_file_id}, core::{errors, files::helpers::retrieve_file_and_provider_file_id_from_file_id},
routes::AppState, routes::AppState,
types::SubmitEvidenceRequestData, types::{api, SubmitEvidenceRequestData},
}; };
pub async fn get_evidence_request_data( pub async fn get_evidence_request_data(
@ -17,6 +17,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.cancellation_policy, evidence_request.cancellation_policy,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (customer_communication, customer_communication_provider_file_id) = let (customer_communication, customer_communication_provider_file_id) =
@ -24,6 +25,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.customer_communication, evidence_request.customer_communication,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (customer_signature, customer_signature_provider_file_id) = let (customer_signature, customer_signature_provider_file_id) =
@ -31,12 +33,14 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.customer_signature, evidence_request.customer_signature,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (receipt, receipt_provider_file_id) = retrieve_file_and_provider_file_id_from_file_id( let (receipt, receipt_provider_file_id) = retrieve_file_and_provider_file_id_from_file_id(
state, state,
evidence_request.receipt, evidence_request.receipt,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (refund_policy, refund_policy_provider_file_id) = let (refund_policy, refund_policy_provider_file_id) =
@ -44,6 +48,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.refund_policy, evidence_request.refund_policy,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (service_documentation, service_documentation_provider_file_id) = let (service_documentation, service_documentation_provider_file_id) =
@ -51,6 +56,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.service_documentation, evidence_request.service_documentation,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (shipping_documentation, shipping_documentation_provider_file_id) = let (shipping_documentation, shipping_documentation_provider_file_id) =
@ -58,6 +64,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.shipping_documentation, evidence_request.shipping_documentation,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let ( let (
@ -67,6 +74,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.invoice_showing_distinct_transactions, evidence_request.invoice_showing_distinct_transactions,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (recurring_transaction_agreement, recurring_transaction_agreement_provider_file_id) = let (recurring_transaction_agreement, recurring_transaction_agreement_provider_file_id) =
@ -74,6 +82,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.recurring_transaction_agreement, evidence_request.recurring_transaction_agreement,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
let (uncategorized_file, uncategorized_file_provider_file_id) = let (uncategorized_file, uncategorized_file_provider_file_id) =
@ -81,6 +90,7 @@ pub async fn get_evidence_request_data(
state, state,
evidence_request.uncategorized_file, evidence_request.uncategorized_file,
merchant_account, merchant_account,
api::FileDataRequired::NotRequired,
) )
.await?; .await?;
Ok(SubmitEvidenceRequestData { Ok(SubmitEvidenceRequestData {

View File

@ -13,7 +13,7 @@ use crate::{
consts, consts,
routes::AppState, routes::AppState,
services::{self, ApplicationResponse}, services::{self, ApplicationResponse},
types::{api, storage, transformers::ForeignInto}, types::{api, storage},
}; };
pub async fn files_create_core( pub async fn files_create_core(
@ -37,6 +37,7 @@ pub async fn files_create_core(
provider_file_id: None, provider_file_id: None,
file_upload_provider: None, file_upload_provider: None,
available: false, available: false,
connector_label: None,
}; };
let file_metadata_object = state let file_metadata_object = state
.store .store
@ -44,8 +45,8 @@ pub async fn files_create_core(
.await .await
.change_context(errors::ApiErrorResponse::InternalServerError) .change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to insert file_metadata")?; .attach_printable("Unable to insert file_metadata")?;
let (provider_file_id, file_upload_provider) = let (provider_file_id, file_upload_provider, connector_label) =
helpers::upload_and_get_provider_provider_file_id( helpers::upload_and_get_provider_provider_file_id_connector_label(
state, state,
&merchant_account, &merchant_account,
&create_file_request, &create_file_request,
@ -55,8 +56,9 @@ pub async fn files_create_core(
//Update file metadata //Update file metadata
let update_file_metadata = storage_models::file::FileMetadataUpdate::Update { let update_file_metadata = storage_models::file::FileMetadataUpdate::Update {
provider_file_id: Some(provider_file_id), provider_file_id: Some(provider_file_id),
file_upload_provider: Some(file_upload_provider.foreign_into()), file_upload_provider: Some(file_upload_provider),
available: true, available: true,
connector_label,
}; };
state state
.store .store
@ -102,6 +104,7 @@ pub async fn files_retrieve_core(
state, state,
Some(req.file_id), Some(req.file_id),
&merchant_account, &merchant_account,
api::FileDataRequired::Required,
) )
.await?; .await?;
let content_type = file_metadata_object let content_type = file_metadata_object

View File

@ -6,11 +6,13 @@ use futures::TryStreamExt;
use crate::{ use crate::{
core::{ core::{
errors::{self, StorageErrorExt}, errors::{self, StorageErrorExt},
files, payments, utils, files,
payments::{self, helpers as payments_helpers},
utils,
}, },
routes::AppState, routes::AppState,
services, services,
types::{self, api, storage}, types::{self, api, storage, transformers::ForeignTryFrom},
}; };
pub async fn read_string(field: &mut Field) -> Option<String> { pub async fn read_string(field: &mut Field) -> Option<String> {
@ -144,10 +146,66 @@ pub async fn delete_file_using_file_id(
} }
} }
pub async fn retrieve_file_from_connector(
state: &AppState,
file_metadata: storage_models::file::FileMetadata,
merchant_account: &storage_models::merchant_account::MerchantAccount,
) -> CustomResult<Vec<u8>, errors::ApiErrorResponse> {
let connector = &types::Connector::foreign_try_from(
file_metadata
.file_upload_provider
.ok_or(errors::ApiErrorResponse::InternalServerError)
.into_report()
.attach_printable("Missing file upload provider")?,
)?
.to_string();
let connector_data = api::ConnectorData::get_connector_by_name(
&state.conf.connectors,
connector,
api::GetToken::Connector,
)?;
let connector_integration: services::BoxedConnectorIntegration<
'_,
api::Retrieve,
types::RetrieveFileRequestData,
types::RetrieveFileResponse,
> = connector_data.connector.get_connector_integration();
let router_data = utils::construct_retrieve_file_router_data(
state,
merchant_account,
&file_metadata,
connector,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed constructing the retrieve file router data")?;
let response = services::execute_connector_processing_step(
state,
connector_integration,
&router_data,
payments::CallConnectorAction::Trigger,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed while calling retrieve file connector api")?;
let retrieve_file_response =
response
.response
.map_err(|err| errors::ApiErrorResponse::ExternalConnectorError {
code: err.code,
message: err.message,
connector: connector.to_string(),
status_code: err.status_code,
reason: err.reason,
})?;
Ok(retrieve_file_response.file_data)
}
pub async fn retrieve_file_and_provider_file_id_from_file_id( pub async fn retrieve_file_and_provider_file_id_from_file_id(
state: &AppState, state: &AppState,
file_id: Option<String>, file_id: Option<String>,
merchant_account: &storage_models::merchant_account::MerchantAccount, merchant_account: &storage_models::merchant_account::MerchantAccount,
is_connector_file_data_required: api::FileDataRequired,
) -> CustomResult<(Option<Vec<u8>>, Option<String>), errors::ApiErrorResponse> { ) -> CustomResult<(Option<Vec<u8>>, Option<String>), errors::ApiErrorResponse> {
match file_id { match file_id {
None => Ok((None, None)), None => Ok((None, None)),
@ -159,10 +217,13 @@ pub async fn retrieve_file_and_provider_file_id_from_file_id(
.change_context(errors::ApiErrorResponse::FileNotFound)?; .change_context(errors::ApiErrorResponse::FileNotFound)?;
let (provider, provider_file_id) = match ( let (provider, provider_file_id) = match (
file_metadata_object.file_upload_provider, file_metadata_object.file_upload_provider,
file_metadata_object.provider_file_id, file_metadata_object.provider_file_id.clone(),
file_metadata_object.available,
) { ) {
(Some(provider), Some(provider_file_id)) => (provider, provider_file_id), (Some(provider), Some(provider_file_id), true) => (provider, provider_file_id),
_ => Err(errors::ApiErrorResponse::FileNotFound)?, _ => Err(errors::ApiErrorResponse::FileNotAvailable)
.into_report()
.attach_printable("File not available")?,
}; };
match provider { match provider {
storage_models::enums::FileUploadProvider::Router => Ok(( storage_models::enums::FileUploadProvider::Router => Ok((
@ -176,20 +237,39 @@ pub async fn retrieve_file_and_provider_file_id_from_file_id(
), ),
Some(provider_file_id), Some(provider_file_id),
)), )),
//TODO: Handle Retrieve for other providers _ => {
_ => Ok((None, Some(provider_file_id))), let connector_file_data = match is_connector_file_data_required {
api::FileDataRequired::Required => Some(
retrieve_file_from_connector(
state,
file_metadata_object,
merchant_account,
)
.await?,
),
api::FileDataRequired::NotRequired => None,
};
Ok((connector_file_data, Some(provider_file_id)))
}
} }
} }
} }
} }
//Upload file to connector if it supports / store it in S3 and return file_upload_provider, provider_file_id accordingly //Upload file to connector if it supports / store it in S3 and return file_upload_provider, provider_file_id accordingly
pub async fn upload_and_get_provider_provider_file_id( pub async fn upload_and_get_provider_provider_file_id_connector_label(
state: &AppState, state: &AppState,
merchant_account: &storage::merchant_account::MerchantAccount, merchant_account: &storage::merchant_account::MerchantAccount,
create_file_request: &api::CreateFileRequest, create_file_request: &api::CreateFileRequest,
file_key: String, file_key: String,
) -> CustomResult<(String, api::FileUploadProvider), errors::ApiErrorResponse> { ) -> CustomResult<
(
String,
api_models::enums::FileUploadProvider,
Option<String>,
),
errors::ApiErrorResponse,
> {
match create_file_request.purpose { match create_file_request.purpose {
api::FilePurpose::DisputeEvidence => { api::FilePurpose::DisputeEvidence => {
let dispute_id = create_file_request let dispute_id = create_file_request
@ -225,6 +305,12 @@ pub async fn upload_and_get_provider_provider_file_id(
) )
.await .await
.change_context(errors::ApiErrorResponse::PaymentNotFound)?; .change_context(errors::ApiErrorResponse::PaymentNotFound)?;
let connector_label = payments_helpers::get_connector_label(
payment_intent.business_country,
&payment_intent.business_label,
payment_attempt.business_sub_label.as_ref(),
&dispute.connector,
);
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
'_, '_,
api::Upload, api::Upload,
@ -239,6 +325,7 @@ pub async fn upload_and_get_provider_provider_file_id(
create_file_request, create_file_request,
&dispute.connector, &dispute.connector,
file_key, file_key,
connector_label.clone(),
) )
.await .await
.change_context(errors::ApiErrorResponse::InternalServerError) .change_context(errors::ApiErrorResponse::InternalServerError)
@ -263,7 +350,10 @@ pub async fn upload_and_get_provider_provider_file_id(
})?; })?;
Ok(( Ok((
upload_file_response.provider_file_id, upload_file_response.provider_file_id,
api::FileUploadProvider::try_from(&connector_data.connector_name)?, api_models::enums::FileUploadProvider::foreign_try_from(
&connector_data.connector_name,
)?,
Some(connector_label),
)) ))
} else { } else {
upload_file( upload_file(
@ -273,7 +363,11 @@ pub async fn upload_and_get_provider_provider_file_id(
create_file_request.file.clone(), create_file_request.file.clone(),
) )
.await?; .await?;
Ok((file_key, api::FileUploadProvider::Router)) Ok((
file_key,
api_models::enums::FileUploadProvider::Router,
None,
))
} }
} }
} }

View File

@ -324,6 +324,14 @@ macro_rules! default_imp_for_file_upload{
types::UploadFileResponse, types::UploadFileResponse,
> for $path::$connector > for $path::$connector
{} {}
impl api::RetrieveFile for $path::$connector {}
impl
services::ConnectorIntegration<
api::Retrieve,
types::RetrieveFileRequestData,
types::RetrieveFileResponse,
> for $path::$connector
{}
)* )*
}; };
} }

View File

@ -2,7 +2,7 @@ use std::marker::PhantomData;
use api_models::enums::{DisputeStage, DisputeStatus}; use api_models::enums::{DisputeStage, DisputeStatus};
use common_utils::errors::CustomResult; use common_utils::errors::CustomResult;
use error_stack::ResultExt; use error_stack::{IntoReport, ResultExt};
use router_env::{instrument, tracing}; use router_env::{instrument, tracing};
use super::payments::{helpers, PaymentAddress}; use super::payments::{helpers, PaymentAddress};
@ -343,6 +343,7 @@ pub async fn construct_submit_evidence_router_data<'a>(
} }
#[instrument(skip_all)] #[instrument(skip_all)]
#[allow(clippy::too_many_arguments)]
pub async fn construct_upload_file_router_data<'a>( pub async fn construct_upload_file_router_data<'a>(
state: &'a AppState, state: &'a AppState,
payment_intent: &'a storage::PaymentIntent, payment_intent: &'a storage::PaymentIntent,
@ -351,13 +352,8 @@ pub async fn construct_upload_file_router_data<'a>(
create_file_request: &types::api::CreateFileRequest, create_file_request: &types::api::CreateFileRequest,
connector_id: &str, connector_id: &str,
file_key: String, file_key: String,
connector_label: String,
) -> RouterResult<types::UploadFileRouterData> { ) -> RouterResult<types::UploadFileRouterData> {
let connector_label = helpers::get_connector_label(
payment_intent.business_country,
&payment_intent.business_label,
payment_attempt.business_sub_label.as_ref(),
connector_id,
);
let merchant_connector_account = helpers::get_merchant_connector_account( let merchant_connector_account = helpers::get_merchant_connector_account(
state, state,
merchant_account.merchant_id.as_str(), merchant_account.merchant_id.as_str(),
@ -465,3 +461,62 @@ pub async fn construct_defend_dispute_router_data<'a>(
}; };
Ok(router_data) Ok(router_data)
} }
#[instrument(skip_all)]
pub async fn construct_retrieve_file_router_data<'a>(
state: &'a AppState,
merchant_account: &storage::MerchantAccount,
file_metadata: &storage_models::file::FileMetadata,
connector_id: &str,
) -> RouterResult<types::RetrieveFileRouterData> {
let connector_label = file_metadata
.connector_label
.clone()
.ok_or(errors::ApiErrorResponse::InternalServerError)
.into_report()
.attach_printable("Missing connector label")?;
let merchant_connector_account = helpers::get_merchant_connector_account(
state,
merchant_account.merchant_id.as_str(),
&connector_label,
None,
)
.await?;
let auth_type: types::ConnectorAuthType = merchant_connector_account
.get_connector_account_details()
.parse_value("ConnectorAuthType")
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let router_data = types::RouterData {
flow: PhantomData,
merchant_id: merchant_account.merchant_id.clone(),
connector: connector_id.to_string(),
customer_id: None,
connector_customer: None,
payment_id: "irrelevant_payment_id_in_dispute_flow".to_string(),
attempt_id: "irrelevant_attempt_id_in_dispute_flow".to_string(),
status: storage_models::enums::AttemptStatus::default(),
payment_method: storage_models::enums::PaymentMethod::default(),
connector_auth_type: auth_type,
description: None,
return_url: None,
payment_method_id: None,
address: PaymentAddress::default(),
auth_type: storage_models::enums::AuthenticationType::default(),
connector_meta_data: merchant_connector_account.get_metadata(),
amount_captured: None,
request: types::RetrieveFileRequestData {
provider_file_id: file_metadata
.provider_file_id
.clone()
.ok_or(errors::ApiErrorResponse::InternalServerError)
.into_report()
.attach_printable("Missing provider file id")?,
},
response: Err(types::ErrorResponse::default()),
access_token: None,
session_token: None,
reference_id: None,
payment_method_token: None,
};
Ok(router_data)
}

View File

@ -136,6 +136,12 @@ pub type SubmitEvidenceType = dyn services::ConnectorIntegration<
pub type UploadFileType = pub type UploadFileType =
dyn services::ConnectorIntegration<api::Upload, UploadFileRequestData, UploadFileResponse>; dyn services::ConnectorIntegration<api::Upload, UploadFileRequestData, UploadFileResponse>;
pub type RetrieveFileType = dyn services::ConnectorIntegration<
api::Retrieve,
RetrieveFileRequestData,
RetrieveFileResponse,
>;
pub type DefendDisputeType = dyn services::ConnectorIntegration< pub type DefendDisputeType = dyn services::ConnectorIntegration<
api::Defend, api::Defend,
DefendDisputeRequestData, DefendDisputeRequestData,
@ -152,6 +158,9 @@ pub type SubmitEvidenceRouterData =
pub type UploadFileRouterData = RouterData<api::Upload, UploadFileRequestData, UploadFileResponse>; pub type UploadFileRouterData = RouterData<api::Upload, UploadFileRequestData, UploadFileResponse>;
pub type RetrieveFileRouterData =
RouterData<api::Retrieve, RetrieveFileRequestData, RetrieveFileResponse>;
pub type DefendDisputeRouterData = pub type DefendDisputeRouterData =
RouterData<api::Defend, DefendDisputeRequestData, DefendDisputeResponse>; RouterData<api::Defend, DefendDisputeRequestData, DefendDisputeResponse>;
@ -516,6 +525,16 @@ pub struct UploadFileResponse {
pub provider_file_id: String, pub provider_file_id: String,
} }
#[derive(Clone, Debug)]
pub struct RetrieveFileRequestData {
pub provider_file_id: String,
}
#[derive(Clone, Debug)]
pub struct RetrieveFileResponse {
pub file_data: Vec<u8>,
}
#[derive(Debug, Clone, Default, serde::Deserialize, serde::Serialize)] #[derive(Debug, Clone, Default, serde::Deserialize, serde::Serialize)]
pub struct ConnectorResponse { pub struct ConnectorResponse {
pub merchant_id: String, pub merchant_id: String,

View File

@ -1,23 +1,41 @@
use api_models::enums::FileUploadProvider;
use masking::{Deserialize, Serialize}; use masking::{Deserialize, Serialize};
use super::ConnectorCommon; use super::ConnectorCommon;
use crate::{core::errors, services, types}; use crate::{
core::errors,
services,
types::{self, transformers::ForeignTryFrom},
};
#[derive(Default, Debug, Deserialize, Serialize)] #[derive(Default, Debug, Deserialize, Serialize)]
pub struct FileId { pub struct FileId {
pub file_id: String, pub file_id: String,
} }
#[derive(Debug, Clone, frunk::LabelledGeneric)] #[derive(Debug)]
pub enum FileUploadProvider { pub enum FileDataRequired {
Router, Required,
Stripe, NotRequired,
Checkout,
} }
impl TryFrom<&types::Connector> for FileUploadProvider { impl ForeignTryFrom<FileUploadProvider> for types::Connector {
type Error = error_stack::Report<errors::ApiErrorResponse>; type Error = error_stack::Report<errors::ApiErrorResponse>;
fn try_from(item: &types::Connector) -> Result<Self, Self::Error> { fn foreign_try_from(item: FileUploadProvider) -> Result<Self, Self::Error> {
match item {
FileUploadProvider::Stripe => Ok(Self::Stripe),
FileUploadProvider::Checkout => Ok(Self::Checkout),
FileUploadProvider::Router => Err(errors::ApiErrorResponse::NotSupported {
message: "File upload provider is not a connector".to_owned(),
}
.into()),
}
}
}
impl ForeignTryFrom<&types::Connector> for FileUploadProvider {
type Error = error_stack::Report<errors::ApiErrorResponse>;
fn foreign_try_from(item: &types::Connector) -> Result<Self, Self::Error> {
match *item { match *item {
types::Connector::Stripe => Ok(Self::Stripe), types::Connector::Stripe => Ok(Self::Stripe),
types::Connector::Checkout => Ok(Self::Checkout), types::Connector::Checkout => Ok(Self::Checkout),
@ -54,7 +72,19 @@ pub trait UploadFile:
{ {
} }
pub trait FileUpload: ConnectorCommon + Sync + UploadFile { #[derive(Debug, Clone)]
pub struct Retrieve;
pub trait RetrieveFile:
services::ConnectorIntegration<
Retrieve,
types::RetrieveFileRequestData,
types::RetrieveFileResponse,
>
{
}
pub trait FileUpload: ConnectorCommon + Sync + UploadFile + RetrieveFile {
fn validate_file_upload( fn validate_file_upload(
&self, &self,
_purpose: FilePurpose, _purpose: FilePurpose,

View File

@ -457,12 +457,6 @@ impl ForeignFrom<storage_enums::DisputeStatus> for api_enums::DisputeStatus {
} }
} }
impl ForeignFrom<api_types::FileUploadProvider> for storage_enums::FileUploadProvider {
fn foreign_from(provider: api_types::FileUploadProvider) -> Self {
frunk::labelled_convert_from(provider)
}
}
impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for storage_enums::DisputeStatus { impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for storage_enums::DisputeStatus {
type Error = errors::ValidationError; type Error = errors::ValidationError;

View File

@ -796,26 +796,3 @@ pub enum DisputeStatus {
DisputeWon, DisputeWon,
DisputeLost, DisputeLost,
} }
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Default,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumString,
frunk::LabelledGeneric,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum FileUploadProvider {
#[default]
Router,
Stripe,
Checkout,
}

View File

@ -2,7 +2,7 @@ use common_utils::custom_serde;
use diesel::{AsChangeset, Identifiable, Insertable, Queryable}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
use masking::{Deserialize, Serialize}; use masking::{Deserialize, Serialize};
use crate::{enums as storage_enums, schema::file_metadata}; use crate::schema::file_metadata;
#[derive(Clone, Debug, Deserialize, Insertable, Serialize, router_derive::DebugAsDisplay)] #[derive(Clone, Debug, Deserialize, Insertable, Serialize, router_derive::DebugAsDisplay)]
#[diesel(table_name = file_metadata)] #[diesel(table_name = file_metadata)]
@ -14,8 +14,9 @@ pub struct FileMetadataNew {
pub file_size: i32, pub file_size: i32,
pub file_type: String, pub file_type: String,
pub provider_file_id: Option<String>, pub provider_file_id: Option<String>,
pub file_upload_provider: Option<storage_enums::FileUploadProvider>, pub file_upload_provider: Option<common_enums::FileUploadProvider>,
pub available: bool, pub available: bool,
pub connector_label: Option<String>,
} }
#[derive(Clone, Debug, Deserialize, Serialize, Identifiable, Queryable)] #[derive(Clone, Debug, Deserialize, Serialize, Identifiable, Queryable)]
@ -28,18 +29,20 @@ pub struct FileMetadata {
pub file_size: i32, pub file_size: i32,
pub file_type: String, pub file_type: String,
pub provider_file_id: Option<String>, pub provider_file_id: Option<String>,
pub file_upload_provider: Option<storage_enums::FileUploadProvider>, pub file_upload_provider: Option<common_enums::FileUploadProvider>,
pub available: bool, pub available: bool,
#[serde(with = "custom_serde::iso8601")] #[serde(with = "custom_serde::iso8601")]
pub created_at: time::PrimitiveDateTime, pub created_at: time::PrimitiveDateTime,
pub connector_label: Option<String>,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum FileMetadataUpdate { pub enum FileMetadataUpdate {
Update { Update {
provider_file_id: Option<String>, provider_file_id: Option<String>,
file_upload_provider: Option<storage_enums::FileUploadProvider>, file_upload_provider: Option<common_enums::FileUploadProvider>,
available: bool, available: bool,
connector_label: Option<String>,
}, },
} }
@ -47,8 +50,9 @@ pub enum FileMetadataUpdate {
#[diesel(table_name = file_metadata)] #[diesel(table_name = file_metadata)]
pub struct FileMetadataUpdateInternal { pub struct FileMetadataUpdateInternal {
provider_file_id: Option<String>, provider_file_id: Option<String>,
file_upload_provider: Option<storage_enums::FileUploadProvider>, file_upload_provider: Option<common_enums::FileUploadProvider>,
available: bool, available: bool,
connector_label: Option<String>,
} }
impl From<FileMetadataUpdate> for FileMetadataUpdateInternal { impl From<FileMetadataUpdate> for FileMetadataUpdateInternal {
@ -58,10 +62,12 @@ impl From<FileMetadataUpdate> for FileMetadataUpdateInternal {
provider_file_id, provider_file_id,
file_upload_provider, file_upload_provider,
available, available,
connector_label,
} => Self { } => Self {
provider_file_id, provider_file_id,
file_upload_provider, file_upload_provider,
available, available,
connector_label,
}, },
} }
} }

View File

@ -169,6 +169,7 @@ diesel::table! {
file_upload_provider -> Nullable<Varchar>, file_upload_provider -> Nullable<Varchar>,
available -> Bool, available -> Bool,
created_at -> Timestamp, created_at -> Timestamp,
connector_label -> Nullable<Varchar>,
} }
} }

View File

@ -0,0 +1 @@
ALTER TABLE file_metadata DROP COLUMN connector_label;

View File

@ -0,0 +1,3 @@
-- Your SQL goes here
ALTER TABLE file_metadata
ADD COLUMN connector_label VARCHAR(255);