Base
This commit is contained in:
parent
750d472c37
commit
fd155575d4
@ -0,0 +1,75 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const businessColumns = {
|
||||||
|
street_address: { type: 'TEXT' },
|
||||||
|
address_line_2: { type: 'TEXT' },
|
||||||
|
city: { type: 'TEXT' },
|
||||||
|
state: { type: 'TEXT' },
|
||||||
|
postal_code: { type: 'TEXT' },
|
||||||
|
country: { type: 'TEXT' },
|
||||||
|
website_url: { type: 'TEXT' },
|
||||||
|
business_phone: { type: 'TEXT' },
|
||||||
|
business_email: { type: 'TEXT' },
|
||||||
|
timezone: { type: 'TEXT' },
|
||||||
|
};
|
||||||
|
|
||||||
|
function normalizeColumnDefinition(Sequelize, definition) {
|
||||||
|
const normalized = { ...definition };
|
||||||
|
|
||||||
|
if (definition.type === 'TEXT') {
|
||||||
|
normalized.type = Sequelize.DataTypes.TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addColumnsIfMissing(queryInterface, Sequelize, transaction, tableName, columns) {
|
||||||
|
const table = await queryInterface.describeTable(tableName);
|
||||||
|
|
||||||
|
for (const [columnName, definition] of Object.entries(columns)) {
|
||||||
|
if (!table[columnName]) {
|
||||||
|
await queryInterface.addColumn(
|
||||||
|
tableName,
|
||||||
|
columnName,
|
||||||
|
normalizeColumnDefinition(Sequelize, definition),
|
||||||
|
{ transaction },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeColumnsIfPresent(queryInterface, transaction, tableName, columns) {
|
||||||
|
const table = await queryInterface.describeTable(tableName);
|
||||||
|
|
||||||
|
for (const columnName of Object.keys(columns).reverse()) {
|
||||||
|
if (table[columnName]) {
|
||||||
|
await queryInterface.removeColumn(tableName, columnName, { transaction });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
async up(queryInterface, Sequelize) {
|
||||||
|
const transaction = await queryInterface.sequelize.transaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await addColumnsIfMissing(queryInterface, Sequelize, transaction, 'businesses', businessColumns);
|
||||||
|
await transaction.commit();
|
||||||
|
} catch (error) {
|
||||||
|
await transaction.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async down(queryInterface) {
|
||||||
|
const transaction = await queryInterface.sequelize.transaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await removeColumnsIfPresent(queryInterface, transaction, 'businesses', businessColumns);
|
||||||
|
await transaction.commit();
|
||||||
|
} catch (error) {
|
||||||
|
await transaction.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -15,6 +15,46 @@ name: {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
street_address: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
address_line_2: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
city: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
state: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
postal_code: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
country: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
website_url: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
business_phone: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
business_email: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
|
timezone: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
},
|
||||||
|
|
||||||
google_review_link: {
|
google_review_link: {
|
||||||
type: DataTypes.TEXT,
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|||||||
@ -108,6 +108,21 @@ function normalizeOptionalUrl(value, message) {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeOptionalWebsiteUrl(value) {
|
||||||
|
const normalized = normalizeString(value);
|
||||||
|
|
||||||
|
if (!normalized) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(normalized)
|
||||||
|
? normalized
|
||||||
|
: `https://${normalized}`;
|
||||||
|
|
||||||
|
validateUrl(url, 'Website must be a valid URL.');
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeOptionalDate(value, message) {
|
function normalizeOptionalDate(value, message) {
|
||||||
const normalized = normalizeString(value);
|
const normalized = normalizeString(value);
|
||||||
|
|
||||||
@ -136,11 +151,11 @@ function normalizeDefaultReviewPlatform(value, fallback = 'google') {
|
|||||||
return DEFAULT_REVIEW_PLATFORMS.has(fallback) ? fallback : 'google';
|
return DEFAULT_REVIEW_PLATFORMS.has(fallback) ? fallback : 'google';
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptionalEmail(value) {
|
function normalizeOptionalEmail(value, message = 'Reply-to email must be a valid email address.') {
|
||||||
const normalized = normalizeString(value).toLowerCase();
|
const normalized = normalizeString(value).toLowerCase();
|
||||||
|
|
||||||
if (normalized && !EMAIL_PATTERN.test(normalized)) {
|
if (normalized && !EMAIL_PATTERN.test(normalized)) {
|
||||||
const error = new Error('Reply-to email must be a valid email address.');
|
const error = new Error(message);
|
||||||
error.code = 400;
|
error.code = 400;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -507,6 +522,19 @@ router.put('/growth-tools/business', wrapAsync(async (req, res) => {
|
|||||||
business = await db.businesses.create({
|
business = await db.businesses.create({
|
||||||
name: businessName,
|
name: businessName,
|
||||||
business_type: normalizeBusinessType(body.businessType || body.business_type, 'hybrid'),
|
business_type: normalizeBusinessType(body.businessType || body.business_type, 'hybrid'),
|
||||||
|
street_address: normalizeString(body.streetAddress ?? body.street_address),
|
||||||
|
address_line_2: normalizeString(body.addressLine2 ?? body.address_line_2),
|
||||||
|
city: normalizeString(body.city),
|
||||||
|
state: normalizeString(body.state),
|
||||||
|
postal_code: normalizeString(body.postalCode ?? body.postal_code),
|
||||||
|
country: normalizeString(body.country),
|
||||||
|
website_url: normalizeOptionalWebsiteUrl(body.websiteUrl ?? body.website_url),
|
||||||
|
business_phone: normalizeString(body.businessPhone ?? body.business_phone),
|
||||||
|
business_email: normalizeOptionalEmail(
|
||||||
|
body.businessEmail ?? body.business_email,
|
||||||
|
'Business email must be a valid email address.',
|
||||||
|
),
|
||||||
|
timezone: normalizeString(body.timezone),
|
||||||
automation_mode: 'set_and_forget',
|
automation_mode: 'set_and_forget',
|
||||||
is_active: parseBoolean(body.isActive ?? body.is_active, true),
|
is_active: parseBoolean(body.isActive ?? body.is_active, true),
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
@ -557,6 +585,19 @@ router.put('/growth-tools/business', wrapAsync(async (req, res) => {
|
|||||||
const updatePayload = {
|
const updatePayload = {
|
||||||
name: businessName || business.name,
|
name: businessName || business.name,
|
||||||
business_type: businessType,
|
business_type: businessType,
|
||||||
|
street_address: normalizeString(body.streetAddress ?? body.street_address ?? business.street_address),
|
||||||
|
address_line_2: normalizeString(body.addressLine2 ?? body.address_line_2 ?? business.address_line_2),
|
||||||
|
city: normalizeString(body.city ?? business.city),
|
||||||
|
state: normalizeString(body.state ?? business.state),
|
||||||
|
postal_code: normalizeString(body.postalCode ?? body.postal_code ?? business.postal_code),
|
||||||
|
country: normalizeString(body.country ?? business.country),
|
||||||
|
website_url: normalizeOptionalWebsiteUrl(body.websiteUrl ?? body.website_url ?? business.website_url),
|
||||||
|
business_phone: normalizeString(body.businessPhone ?? body.business_phone ?? business.business_phone),
|
||||||
|
business_email: normalizeOptionalEmail(
|
||||||
|
body.businessEmail ?? body.business_email ?? business.business_email,
|
||||||
|
'Business email must be a valid email address.',
|
||||||
|
),
|
||||||
|
timezone: normalizeString(body.timezone ?? business.timezone),
|
||||||
automation_mode: normalizeString(body.automationMode || body.automation_mode) || 'set_and_forget',
|
automation_mode: normalizeString(body.automationMode || body.automation_mode) || 'set_and_forget',
|
||||||
ownerId,
|
ownerId,
|
||||||
review_destination: reviewDestination,
|
review_destination: reviewDestination,
|
||||||
|
|||||||
@ -1013,6 +1013,16 @@ function serializeBusiness(req, business) {
|
|||||||
return {
|
return {
|
||||||
id: business.id,
|
id: business.id,
|
||||||
name: business.name,
|
name: business.name,
|
||||||
|
street_address: business.street_address || '',
|
||||||
|
address_line_2: business.address_line_2 || '',
|
||||||
|
city: business.city || '',
|
||||||
|
state: business.state || '',
|
||||||
|
postal_code: business.postal_code || '',
|
||||||
|
country: business.country || '',
|
||||||
|
website_url: business.website_url || '',
|
||||||
|
business_phone: business.business_phone || '',
|
||||||
|
business_email: business.business_email || '',
|
||||||
|
timezone: business.timezone || '',
|
||||||
ownerId: business.ownerId || '',
|
ownerId: business.ownerId || '',
|
||||||
is_active: business.is_active !== false,
|
is_active: business.is_active !== false,
|
||||||
stripe_account_reference: business.stripe_account_reference || '',
|
stripe_account_reference: business.stripe_account_reference || '',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user