fix: do not allow duplicate organization name (#5919)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Hrithikesh
2024-09-20 13:09:38 +05:30
committed by GitHub
parent a94cf25bb6
commit c8f7232a30
13 changed files with 98 additions and 31 deletions

View File

@ -32,7 +32,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/OrganizationRequest" "$ref": "#/components/schemas/OrganizationCreateRequest"
}, },
"examples": { "examples": {
"Create an organization with organization_name": { "Create an organization with organization_name": {
@ -129,7 +129,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/OrganizationRequest" "$ref": "#/components/schemas/OrganizationUpdateRequest"
}, },
"examples": { "examples": {
"Update organization_name of the organization": { "Update organization_name of the organization": {
@ -10116,12 +10116,14 @@
"confirm" "confirm"
] ]
}, },
"OrganizationRequest": { "OrganizationCreateRequest": {
"type": "object", "type": "object",
"required": [
"organization_name"
],
"properties": { "properties": {
"organization_name": { "organization_name": {
"type": "string", "type": "string"
"nullable": true
}, },
"organization_details": { "organization_details": {
"type": "object", "type": "object",
@ -10131,7 +10133,8 @@
"type": "object", "type": "object",
"nullable": true "nullable": true
} }
} },
"additionalProperties": false
}, },
"OrganizationResponse": { "OrganizationResponse": {
"type": "object", "type": "object",
@ -10169,6 +10172,24 @@
} }
} }
}, },
"OrganizationUpdateRequest": {
"type": "object",
"properties": {
"organization_name": {
"type": "string",
"nullable": true
},
"organization_details": {
"type": "object",
"nullable": true
},
"metadata": {
"type": "object",
"nullable": true
}
},
"additionalProperties": false
},
"OutgoingWebhook": { "OutgoingWebhook": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@ -1121,7 +1121,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/OrganizationRequest" "$ref": "#/components/schemas/OrganizationCreateRequest"
}, },
"examples": { "examples": {
"Create an organization with organization_name": { "Create an organization with organization_name": {
@ -1218,7 +1218,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/OrganizationRequest" "$ref": "#/components/schemas/OrganizationUpdateRequest"
}, },
"examples": { "examples": {
"Update organization_name of the organization": { "Update organization_name of the organization": {
@ -13913,12 +13913,14 @@
} }
} }
}, },
"OrganizationRequest": { "OrganizationCreateRequest": {
"type": "object", "type": "object",
"required": [
"organization_name"
],
"properties": { "properties": {
"organization_name": { "organization_name": {
"type": "string", "type": "string"
"nullable": true
}, },
"organization_details": { "organization_details": {
"type": "object", "type": "object",
@ -13928,7 +13930,8 @@
"type": "object", "type": "object",
"nullable": true "nullable": true
} }
} },
"additionalProperties": false
}, },
"OrganizationResponse": { "OrganizationResponse": {
"type": "object", "type": "object",
@ -13966,6 +13969,24 @@
} }
} }
}, },
"OrganizationUpdateRequest": {
"type": "object",
"properties": {
"organization_name": {
"type": "string",
"nullable": true
},
"organization_details": {
"type": "object",
"nullable": true
},
"metadata": {
"type": "object",
"nullable": true
}
},
"additionalProperties": false
},
"OutgoingWebhook": { "OutgoingWebhook": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@ -32,7 +32,9 @@ use crate::{
disputes::*, disputes::*,
files::*, files::*,
mandates::*, mandates::*,
organization::{OrganizationId, OrganizationRequest, OrganizationResponse}, organization::{
OrganizationCreateRequest, OrganizationId, OrganizationResponse, OrganizationUpdateRequest,
},
payment_methods::*, payment_methods::*,
payments::*, payments::*,
user::{UserKeyTransferRequest, UserTransferKeyResponse}, user::{UserKeyTransferRequest, UserTransferKeyResponse},
@ -129,7 +131,8 @@ impl_api_event_type!(
DisputeFiltersResponse, DisputeFiltersResponse,
GetDisputeMetricRequest, GetDisputeMetricRequest,
OrganizationResponse, OrganizationResponse,
OrganizationRequest, OrganizationCreateRequest,
OrganizationUpdateRequest,
OrganizationId, OrganizationId,
CustomerListRequest CustomerListRequest
) )

View File

@ -20,7 +20,18 @@ pub struct OrganizationId {
} }
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)] #[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
pub struct OrganizationRequest { #[serde(deny_unknown_fields)]
pub struct OrganizationCreateRequest {
pub organization_name: String,
#[schema(value_type = Option<Object>)]
pub organization_details: Option<pii::SecretSerdeValue>,
#[schema(value_type = Option<Object>)]
pub metadata: Option<pii::SecretSerdeValue>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct OrganizationUpdateRequest {
pub organization_name: Option<String>, pub organization_name: Option<String>,
#[schema(value_type = Option<Object>)] #[schema(value_type = Option<Object>)]
pub organization_details: Option<pii::SecretSerdeValue>, pub organization_details: Option<pii::SecretSerdeValue>,

View File

@ -202,7 +202,8 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::refunds::RefundResponse, api_models::refunds::RefundResponse,
api_models::refunds::RefundStatus, api_models::refunds::RefundStatus,
api_models::refunds::RefundUpdateRequest, api_models::refunds::RefundUpdateRequest,
api_models::organization::OrganizationRequest, api_models::organization::OrganizationCreateRequest,
api_models::organization::OrganizationUpdateRequest,
api_models::organization::OrganizationResponse, api_models::organization::OrganizationResponse,
api_models::admin::MerchantAccountCreate, api_models::admin::MerchantAccountCreate,
api_models::admin::MerchantAccountUpdate, api_models::admin::MerchantAccountUpdate,

View File

@ -127,7 +127,8 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::refunds::RefundResponse, api_models::refunds::RefundResponse,
api_models::refunds::RefundStatus, api_models::refunds::RefundStatus,
api_models::refunds::RefundUpdateRequest, api_models::refunds::RefundUpdateRequest,
api_models::organization::OrganizationRequest, api_models::organization::OrganizationCreateRequest,
api_models::organization::OrganizationUpdateRequest,
api_models::organization::OrganizationResponse, api_models::organization::OrganizationResponse,
api_models::admin::MerchantAccountCreate, api_models::admin::MerchantAccountCreate,
api_models::admin::MerchantAccountUpdate, api_models::admin::MerchantAccountUpdate,

View File

@ -6,7 +6,7 @@
post, post,
path = "/organization", path = "/organization",
request_body( request_body(
content = OrganizationRequest, content = OrganizationCreateRequest,
examples( examples(
( (
"Create an organization with organization_name" = ( "Create an organization with organization_name" = (
@ -51,7 +51,7 @@ pub async fn organization_retrieve() {}
put, put,
path = "/organization/{organization_id}", path = "/organization/{organization_id}",
request_body( request_body(
content = OrganizationRequest, content = OrganizationUpdateRequest,
examples( examples(
( (
"Update organization_name of the organization" = ( "Update organization_name of the organization" = (
@ -79,7 +79,7 @@ pub async fn organization_update() {}
post, post,
path = "/v2/organization", path = "/v2/organization",
request_body( request_body(
content = OrganizationRequest, content = OrganizationCreateRequest,
examples( examples(
( (
"Create an organization with organization_name" = ( "Create an organization with organization_name" = (
@ -124,7 +124,7 @@ pub async fn organization_retrieve() {}
put, put,
path = "/v2/organization/{organization_id}", path = "/v2/organization/{organization_id}",
request_body( request_body(
content = OrganizationRequest, content = OrganizationUpdateRequest,
examples( examples(
( (
"Update organization_name of the organization" = ( "Update organization_name of the organization" = (

View File

@ -114,14 +114,16 @@ fn add_publishable_key_to_decision_service(
#[cfg(feature = "olap")] #[cfg(feature = "olap")]
pub async fn create_organization( pub async fn create_organization(
state: SessionState, state: SessionState,
req: api::OrganizationRequest, req: api::OrganizationCreateRequest,
) -> RouterResponse<api::OrganizationResponse> { ) -> RouterResponse<api::OrganizationResponse> {
let db_organization = ForeignFrom::foreign_from(req); let db_organization = ForeignFrom::foreign_from(req);
state state
.store .store
.insert_organization(db_organization) .insert_organization(db_organization)
.await .await
.to_duplicate_response(errors::ApiErrorResponse::InternalServerError) .to_duplicate_response(errors::ApiErrorResponse::GenericDuplicateError {
message: "Organization with the given organization_name already exists".to_string(),
})
.attach_printable("Error when creating organization") .attach_printable("Error when creating organization")
.map(ForeignFrom::foreign_from) .map(ForeignFrom::foreign_from)
.map(service_api::ApplicationResponse::Json) .map(service_api::ApplicationResponse::Json)
@ -131,7 +133,7 @@ pub async fn create_organization(
pub async fn update_organization( pub async fn update_organization(
state: SessionState, state: SessionState,
org_id: api::OrganizationId, org_id: api::OrganizationId,
req: api::OrganizationRequest, req: api::OrganizationUpdateRequest,
) -> RouterResponse<api::OrganizationResponse> { ) -> RouterResponse<api::OrganizationResponse> {
let organization_update = diesel_models::organization::OrganizationUpdate::Update { let organization_update = diesel_models::organization::OrganizationUpdate::Update {
organization_name: req.organization_name, organization_name: req.organization_name,

View File

@ -14,7 +14,7 @@ use crate::{
pub async fn organization_create( pub async fn organization_create(
state: web::Data<AppState>, state: web::Data<AppState>,
req: HttpRequest, req: HttpRequest,
json_payload: web::Json<admin::OrganizationRequest>, json_payload: web::Json<admin::OrganizationCreateRequest>,
) -> HttpResponse { ) -> HttpResponse {
let flow = Flow::OrganizationCreate; let flow = Flow::OrganizationCreate;
Box::pin(api::server_wrap( Box::pin(api::server_wrap(
@ -35,7 +35,7 @@ pub async fn organization_update(
state: web::Data<AppState>, state: web::Data<AppState>,
req: HttpRequest, req: HttpRequest,
org_id: web::Path<common_utils::id_type::OrganizationId>, org_id: web::Path<common_utils::id_type::OrganizationId>,
json_payload: web::Json<admin::OrganizationRequest>, json_payload: web::Json<admin::OrganizationUpdateRequest>,
) -> HttpResponse { ) -> HttpResponse {
let flow = Flow::OrganizationUpdate; let flow = Flow::OrganizationUpdate;
let organization_id = org_id.into_inner(); let organization_id = org_id.into_inner();

View File

@ -11,7 +11,9 @@ pub use api_models::{
ProfileCreate, ProfileResponse, ProfileUpdate, ToggleAllKVRequest, ToggleAllKVResponse, ProfileCreate, ProfileResponse, ProfileUpdate, ToggleAllKVRequest, ToggleAllKVResponse,
ToggleKVRequest, ToggleKVResponse, WebhookDetails, ToggleKVRequest, ToggleKVResponse, WebhookDetails,
}, },
organization::{OrganizationId, OrganizationRequest, OrganizationResponse}, organization::{
OrganizationCreateRequest, OrganizationId, OrganizationResponse, OrganizationUpdateRequest,
},
}; };
use common_utils::ext_traits::ValueExt; use common_utils::ext_traits::ValueExt;
use diesel_models::organization::OrganizationBridge; use diesel_models::organization::OrganizationBridge;

View File

@ -1561,17 +1561,17 @@ impl ForeignFrom<api_models::organization::OrganizationNew>
} }
} }
impl ForeignFrom<api_models::organization::OrganizationRequest> impl ForeignFrom<api_models::organization::OrganizationCreateRequest>
for diesel_models::organization::OrganizationNew for diesel_models::organization::OrganizationNew
{ {
fn foreign_from(item: api_models::organization::OrganizationRequest) -> Self { fn foreign_from(item: api_models::organization::OrganizationCreateRequest) -> Self {
let org_new = api_models::organization::OrganizationNew::new(None); let org_new = api_models::organization::OrganizationNew::new(None);
let api_models::organization::OrganizationRequest { let api_models::organization::OrganizationCreateRequest {
organization_name, organization_name,
organization_details, organization_details,
metadata, metadata,
} = item; } = item;
let mut org_new_db = Self::new(org_new.org_id, organization_name); let mut org_new_db = Self::new(org_new.org_id, Some(organization_name));
org_new_db.organization_details = organization_details; org_new_db.organization_details = organization_details;
org_new_db.metadata = metadata; org_new_db.metadata = metadata;
org_new_db org_new_db

View File

@ -8,6 +8,8 @@ ALTER TABLE ORGANIZATION DROP CONSTRAINT organization_pkey_id;
ALTER TABLE ORGANIZATION ALTER TABLE ORGANIZATION
ADD CONSTRAINT organization_pkey PRIMARY KEY (org_id); ADD CONSTRAINT organization_pkey PRIMARY KEY (org_id);
ALTER TABLE organization DROP CONSTRAINT organization_organization_name_key;
-- back fill -- back fill
UPDATE ORGANIZATION UPDATE ORGANIZATION
SET org_name = organization_name SET org_name = organization_name

View File

@ -16,6 +16,9 @@ ALTER TABLE ORGANIZATION DROP CONSTRAINT organization_pkey;
ALTER TABLE ORGANIZATION ALTER TABLE ORGANIZATION
ADD CONSTRAINT organization_pkey_id PRIMARY KEY (id); ADD CONSTRAINT organization_pkey_id PRIMARY KEY (id);
ALTER TABLE ORGANIZATION
ADD CONSTRAINT organization_organization_name_key UNIQUE (organization_name);
------------------------ Merchant Account ----------------------- ------------------------ Merchant Account -----------------------
-- The new primary key for v2 merchant account will be `id` -- The new primary key for v2 merchant account will be `id`
ALTER TABLE merchant_account DROP CONSTRAINT merchant_account_pkey; ALTER TABLE merchant_account DROP CONSTRAINT merchant_account_pkey;