refac: customer address db alter for gdpr compliance (#105)

This commit is contained in:
Manoj Ghorela
2022-12-12 00:19:33 +05:30
committed by GitHub
parent 585858ed6e
commit affa9fc35a
18 changed files with 76 additions and 60 deletions

View File

@ -2,7 +2,6 @@ use std::{convert::From, default::Default};
use masking::{Secret, WithType};
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::{pii::Email, types::api};
@ -39,7 +38,6 @@ pub(crate) struct CustomerUpdateRequest {
pub(crate) struct CreateCustomerResponse {
id: String,
object: String,
address: Option<Secret<serde_json::Value>>,
created: u64,
description: Option<String>,
email: Option<Secret<String, Email>>,
@ -65,16 +63,6 @@ impl From<CreateCustomerRequest> for api::CustomerRequest {
phone: req.phone,
email: req.email,
description: req.invoice_prefix,
address: req.address.map(|addr| {
Secret::new(json!({
"city": addr.city,
"country": addr.country,
"line1": addr.line1,
"line2": addr.line2,
"postal_code": addr.postal_code,
"state": addr.state
}))
}),
..Default::default()
}
}
@ -87,17 +75,6 @@ impl From<CustomerUpdateRequest> for api::CustomerRequest {
phone: req.phone,
email: req.email,
description: req.description,
address: req.address.map(|addr| {
Secret::new(json!({
"city": addr.city,
"country": addr.country,
"line1": addr.line1,
"line2": addr.line2,
"postal_code": addr.postal_code,
"state": addr.state
}))
}),
metadata: req
.metadata
.map(|v| serde_json::from_str(&v).ok())
@ -112,7 +89,6 @@ impl From<api::CustomerResponse> for CreateCustomerResponse {
Self {
id: cust.customer_id,
object: "customer".to_owned(),
address: cust.address,
created: cust.created_at.assume_utc().unix_timestamp() as u64,
description: cust.description,
email: cust.email,

View File

@ -27,7 +27,6 @@ pub async fn create_customer(
phone: customer_data.phone,
description: customer_data.description,
phone_country_code: customer_data.phone_country_code,
address: customer_data.address,
metadata: customer_data.metadata,
};
@ -92,7 +91,6 @@ pub async fn update_customer(
email: update_customer.email,
phone: update_customer.phone,
phone_country_code: update_customer.phone_country_code,
address: update_customer.address,
metadata: update_customer.metadata,
description: update_customer.description,
},

View File

@ -36,6 +36,8 @@ pub async fn get_address_for_payment_request(
db: &dyn StorageInterface,
req_address: Option<&api::Address>,
address_id: Option<&str>,
merchant_id: &str,
customer_id: &Option<String>,
) -> CustomResult<Option<storage::Address>, errors::ApiErrorResponse> {
// TODO: Refactor this function for more readability (TryFrom)
Ok(match req_address {
@ -50,6 +52,10 @@ pub async fn get_address_for_payment_request(
),
None => {
// generate a new address here
let customer_id = customer_id
.as_deref()
.get_required_value("customer_id")
.change_context(errors::ApiErrorResponse::CustomerNotFound)?;
Some(
db.insert_address(storage::AddressNew {
city: address.address.as_ref().and_then(|a| a.city.clone()),
@ -66,6 +72,8 @@ pub async fn get_address_for_payment_request(
.phone
.as_ref()
.and_then(|a| a.country_code.clone()),
customer_id: customer_id.to_string(),
merchant_id: merchant_id.to_string(),
..storage::AddressNew::default()
})
.await

View File

@ -101,6 +101,8 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
db,
None,
payment_intent.shipping_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;
@ -108,6 +110,8 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
db,
None,
payment_intent.billing_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;

View File

@ -109,12 +109,16 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
db,
request.shipping.as_ref(),
payment_intent.shipping_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;
let billing_address = helpers::get_address_for_payment_request(
db,
request.billing.as_ref(),
payment_intent.billing_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;

View File

@ -61,11 +61,23 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
helpers::get_token_pm_type_mandate_details(state, request, mandate_type, merchant_id)
.await?;
let shipping_address =
helpers::get_address_for_payment_request(db, request.shipping.as_ref(), None).await?;
let shipping_address = helpers::get_address_for_payment_request(
db,
request.shipping.as_ref(),
None,
merchant_id,
&request.customer_id,
)
.await?;
let billing_address =
helpers::get_address_for_payment_request(db, request.billing.as_ref(), None).await?;
let billing_address = helpers::get_address_for_payment_request(
db,
request.billing.as_ref(),
None,
merchant_id,
&request.customer_id,
)
.await?;
let browser_info = request
.browser_info

View File

@ -82,6 +82,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
db,
None,
payment_intent.shipping_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;
@ -89,6 +91,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
db,
None,
payment_intent.billing_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;

View File

@ -72,12 +72,16 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
db,
None,
payment_intent.shipping_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;
let billing_address = helpers::get_address_for_payment_request(
db,
None,
payment_intent.billing_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;

View File

@ -96,12 +96,16 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
db,
request.shipping.as_ref(),
payment_intent.shipping_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;
let billing_address = helpers::get_address_for_payment_request(
db,
request.billing.as_ref(),
payment_intent.billing_address_id.as_deref(),
merchant_id,
&payment_intent.customer_id,
)
.await?;

View File

@ -136,7 +136,6 @@ impl CustomerInterface for MockDb {
phone: customer_data.phone,
phone_country_code: customer_data.phone_country_code,
description: customer_data.description,
address: customer_data.address,
created_at: common_utils::date_time::now(),
metadata: customer_data.metadata,
};

View File

@ -20,6 +20,8 @@ diesel::table! {
country_code -> Nullable<Varchar>,
created_at -> Timestamp,
modified_at -> Timestamp,
customer_id -> Varchar,
merchant_id -> Varchar,
}
}
@ -65,7 +67,6 @@ diesel::table! {
phone -> Nullable<Varchar>,
phone_country_code -> Nullable<Varchar>,
description -> Nullable<Varchar>,
address -> Nullable<Json>,
created_at -> Timestamp,
metadata -> Nullable<Json>,
}

View File

@ -21,7 +21,6 @@ pub struct CustomerRequest {
pub phone: Option<Secret<String>>,
pub description: Option<String>,
pub phone_country_code: Option<String>,
pub address: Option<Secret<serde_json::Value>>,
pub metadata: Option<serde_json::Value>,
}
@ -35,14 +34,6 @@ impl CustomerRequest {
expected_format: "valid email address".to_string(),
})?;
self.address
.as_ref()
.validate_opt(|addr| utils::validate_address(addr.peek()))
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
field_name: "address".to_string(),
expected_format: "valid address".to_string(),
})?;
Ok(self)
}
}
@ -55,7 +46,6 @@ pub struct CustomerResponse {
pub phone: Option<Secret<String>>,
pub phone_country_code: Option<String>,
pub description: Option<String>,
pub address: Option<Secret<serde_json::Value>>,
#[serde(with = "custom_serde::iso8601")]
pub created_at: time::PrimitiveDateTime,
pub metadata: Option<serde_json::Value>,
@ -70,7 +60,6 @@ impl From<storage::Customer> for CustomerResponse {
phone: cust.phone,
phone_country_code: cust.phone_country_code,
description: cust.description,
address: cust.address,
created_at: cust.created_at,
metadata: cust.metadata,
}

View File

@ -22,6 +22,8 @@ pub struct AddressNew {
pub last_name: Option<Secret<String>>,
pub phone_number: Option<Secret<String>>,
pub country_code: Option<String>,
pub customer_id: String,
pub merchant_id: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, Identifiable, Queryable)]
@ -48,6 +50,8 @@ pub struct Address {
#[serde(skip_serializing)]
#[serde(with = "custom_serde::iso8601")]
pub modified_at: PrimitiveDateTime,
pub customer_id: String,
pub merchant_id: String,
}
#[derive(Debug)]
@ -177,6 +181,8 @@ impl Default for AddressNew {
last_name: None,
phone_number: None,
country_code: None,
customer_id: String::default(),
merchant_id: String::default(),
}
}
}

View File

@ -16,7 +16,6 @@ pub struct CustomerNew {
pub phone: Option<Secret<String>>,
pub description: Option<String>,
pub phone_country_code: Option<String>,
pub address: Option<Secret<serde_json::Value>>,
pub metadata: Option<serde_json::Value>,
}
@ -31,7 +30,6 @@ pub struct Customer {
pub phone: Option<Secret<String>>,
pub phone_country_code: Option<String>,
pub description: Option<String>,
pub address: Option<Secret<serde_json::Value>>,
pub created_at: PrimitiveDateTime,
pub metadata: Option<serde_json::Value>,
}
@ -44,7 +42,6 @@ pub enum CustomerUpdate {
phone: Option<Secret<String>>,
description: Option<String>,
phone_country_code: Option<String>,
address: Option<Secret<serde_json::Value>>,
metadata: Option<serde_json::Value>,
},
}
@ -57,7 +54,6 @@ pub(super) struct CustomerUpdateInternal {
phone: Option<Secret<String>>,
description: Option<String>,
phone_country_code: Option<String>,
address: Option<Secret<serde_json::Value>>,
metadata: Option<serde_json::Value>,
}
@ -70,7 +66,6 @@ impl From<CustomerUpdate> for CustomerUpdateInternal {
phone,
description,
phone_country_code,
address,
metadata,
} => Self {
name,
@ -78,7 +73,6 @@ impl From<CustomerUpdate> for CustomerUpdateInternal {
phone,
description,
phone_country_code,
address,
metadata,
},
}

View File

@ -12,7 +12,7 @@ pub(crate) use common_utils::{
use nanoid::nanoid;
pub(crate) use self::{
ext_traits::{validate_address, OptionExt, ValidateCall},
ext_traits::{OptionExt, ValidateCall},
fp_utils::when,
};
use crate::consts;

View File

@ -1,9 +1,8 @@
use common_utils::ext_traits::ValueExt;
use error_stack::{report, IntoReport, Report, ResultExt};
use error_stack::{IntoReport, Report, ResultExt};
use crate::{
core::errors::{self, ApiErrorResponse, CustomResult, RouterResult},
types::api::AddressDetails,
utils::when,
};
@ -129,11 +128,11 @@ where
}
}
pub fn validate_address(address: &serde_json::Value) -> CustomResult<(), errors::ValidationError> {
if let Err(err) = serde_json::from_value::<AddressDetails>(address.clone()) {
return Err(report!(errors::ValidationError::InvalidValue {
message: format!("Invalid address: {err}")
}));
}
Ok(())
}
// pub fn validate_address(address: &serde_json::Value) -> CustomResult<(), errors::ValidationError> {
// if let Err(err) = serde_json::from_value::<AddressDetails>(address.clone()) {
// return Err(report!(errors::ValidationError::InvalidValue {
// message: format!("Invalid address: {err}")
// }));
// }
// Ok(())
// }

View File

@ -0,0 +1,6 @@
-- This file should undo anything in `up.sql`
ALTER TABLE address
DROP COLUMN customer_id,
DROP COLUMN merchant_id;
ALTER TABLE customers ADD COLUMN address JSON;

View File

@ -0,0 +1,8 @@
-- Your SQL goes here
ALTER TABLE address
ADD COLUMN customer_id VARCHAR(255) NOT NULL,
ADD COLUMN merchant_id VARCHAR(255) NOT NULL;
CREATE INDEX address_customer_id_merchant_id_index ON address (customer_id, merchant_id);
ALTER TABLE customers DROP COLUMN address;