377 lines
11 KiB
JavaScript
377 lines
11 KiB
JavaScript
import config from '../../config.js';
|
|
import { marketplaceModel } from '../../database/schemas/sales/marketplace.schema.js';
|
|
import log4js from 'log4js';
|
|
import mongoose from 'mongoose';
|
|
import {
|
|
deleteObject,
|
|
listObjects,
|
|
getObject,
|
|
editObject,
|
|
newObject,
|
|
listObjectsByProperties,
|
|
getModelStats,
|
|
getModelHistory,
|
|
searchObjects
|
|
} from '../../database/database.js';
|
|
import * as marketplaceIntegration from '../../integrations/marketplaceworker.js';
|
|
const logger = log4js.getLogger('Marketplaces');
|
|
logger.level = config.server.logLevel;
|
|
|
|
export const listMarketplacesRouteHandler = async (
|
|
req,
|
|
res,
|
|
page = 1,
|
|
limit = 25,
|
|
property = '',
|
|
filter = {},
|
|
search = '',
|
|
sort = '',
|
|
order = 'ascend'
|
|
) => {
|
|
const result = await listObjects({
|
|
model: marketplaceModel,
|
|
page,
|
|
limit,
|
|
property,
|
|
filter,
|
|
search,
|
|
sort,
|
|
order,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error listing marketplaces.');
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`List of marketplaces (Page ${page}, Limit ${limit}). Count: ${result.length}.`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const listMarketplacesByPropertiesRouteHandler = async (
|
|
req,
|
|
res,
|
|
properties = '',
|
|
filter = {},
|
|
masterFilter = {}
|
|
) => {
|
|
const result = await listObjectsByProperties({
|
|
model: marketplaceModel,
|
|
properties,
|
|
filter,
|
|
masterFilter,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error listing marketplaces.');
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`List of marketplaces. Count: ${result.length}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const searchMarketplacesRouteHandler = async (req, res, search) => {
|
|
const result = await searchObjects({
|
|
model: marketplaceModel,
|
|
search,
|
|
});
|
|
res.send(result);
|
|
};
|
|
|
|
export const getMarketplaceRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const result = await getObject({
|
|
model: marketplaceModel,
|
|
id,
|
|
});
|
|
if (result?.error) {
|
|
logger.warn(`Marketplace not found with supplied id.`);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.debug(`Retrieved marketplace with ID: ${id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const editMarketplaceRouteHandler = async (req, res) => {
|
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
|
|
|
logger.trace(`Marketplace with ID: ${id}`);
|
|
|
|
const updateData = {
|
|
updatedAt: new Date(),
|
|
name: req.body.name,
|
|
provider: req.body.provider,
|
|
active: req.body.active,
|
|
config: req.body.config || {},
|
|
};
|
|
const result = await editObject({
|
|
model: marketplaceModel,
|
|
id,
|
|
updateData,
|
|
user: req.user,
|
|
});
|
|
|
|
if (result.error) {
|
|
logger.error('Error editing marketplace:', result.error);
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`Edited marketplace with ID: ${id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const newMarketplaceRouteHandler = async (req, res) => {
|
|
const newData = {
|
|
updatedAt: new Date(),
|
|
name: req.body.name,
|
|
provider: req.body.provider,
|
|
active: req.body.active !== false,
|
|
connected: req.body.connected === true,
|
|
state: req.body.state || { type: req.body.active ? 'disconnected' : 'inactive' },
|
|
config: req.body.config || {},
|
|
};
|
|
const result = await newObject({
|
|
model: marketplaceModel,
|
|
newData,
|
|
user: req.user,
|
|
});
|
|
if (result.error) {
|
|
logger.error('No marketplace created:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
|
|
logger.debug(`New marketplace with ID: ${result._id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const deleteMarketplaceRouteHandler = async (req, res) => {
|
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
|
|
|
logger.trace(`Marketplace with ID: ${id}`);
|
|
|
|
const result = await deleteObject({
|
|
model: marketplaceModel,
|
|
id,
|
|
user: req.user,
|
|
});
|
|
if (result.error) {
|
|
logger.error('No marketplace deleted:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
|
|
logger.debug(`Deleted marketplace with ID: ${result._id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getMarketplaceStatsRouteHandler = async (req, res) => {
|
|
const result = await getModelStats({ model: marketplaceModel });
|
|
if (result?.error) {
|
|
logger.error('Error fetching marketplace stats:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.trace('Marketplace stats:', result);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getMarketplaceHistoryRouteHandler = async (req, res) => {
|
|
const from = req.query.from;
|
|
const to = req.query.to;
|
|
const result = await getModelHistory({ model: marketplaceModel, from, to });
|
|
if (result?.error) {
|
|
logger.error('Error fetching marketplace history:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.trace('Marketplace history:', result);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getMarketplaceAuthUrlRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const marketplace = await getObject({ model: marketplaceModel, id });
|
|
if (marketplace?.error) {
|
|
logger.warn('Marketplace not found for authorization URL request.');
|
|
return res.status(marketplace.code).send(marketplace);
|
|
}
|
|
|
|
if (!marketplaceIntegration.hasIntegration(marketplace.provider)) {
|
|
return res.status(400).send({
|
|
error: `No integration available for provider: ${marketplace.provider}`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
if (!marketplaceIntegration.canAuthorize(marketplace)) {
|
|
return res.status(400).send({
|
|
error: `Provider ${marketplace.provider} does not support marketplace authorization.`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
try {
|
|
const url = marketplaceIntegration.getAuthorizationUrl(marketplace, {
|
|
state: req.query.state,
|
|
});
|
|
|
|
res.send({ success: true, url });
|
|
} catch (err) {
|
|
logger.error('Error generating marketplace authorization URL:', err.message);
|
|
res.status(400).send({ error: err.message, code: 400 });
|
|
}
|
|
};
|
|
|
|
export const exchangeMarketplaceAuthCodeRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const { code, state } = req.body;
|
|
|
|
const marketplace = await getObject({ model: marketplaceModel, id });
|
|
if (marketplace?.error) {
|
|
logger.warn('Marketplace not found for authorization exchange.');
|
|
return res.status(marketplace.code).send(marketplace);
|
|
}
|
|
|
|
if (!marketplaceIntegration.hasIntegration(marketplace.provider)) {
|
|
return res.status(400).send({
|
|
error: `No integration available for provider: ${marketplace.provider}`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
try {
|
|
const result = await marketplaceIntegration.exchangeAuthorizationCode(marketplace, req.user, {
|
|
code,
|
|
state,
|
|
});
|
|
|
|
logger.info(`Marketplace authorization completed for ${marketplace.name}`);
|
|
res.send({ success: true, ...result });
|
|
} catch (err) {
|
|
logger.error('Error exchanging marketplace authorization code:', err.message);
|
|
res.status(400).send({ error: err.message, code: 400 });
|
|
}
|
|
};
|
|
|
|
export const refreshMarketplaceAuthRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const marketplace = await getObject({ model: marketplaceModel, id });
|
|
if (marketplace?.error) {
|
|
logger.warn('Marketplace not found for token refresh.');
|
|
return res.status(marketplace.code).send(marketplace);
|
|
}
|
|
|
|
if (!marketplaceIntegration.hasIntegration(marketplace.provider)) {
|
|
return res.status(400).send({
|
|
error: `No integration available for provider: ${marketplace.provider}`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
try {
|
|
const result = await marketplaceIntegration.refreshMarketplaceAuth(marketplace, req.user);
|
|
logger.info(`Marketplace token refreshed for ${marketplace.name}`);
|
|
res.send({ success: true, ...result });
|
|
} catch (err) {
|
|
logger.error('Error refreshing marketplace token:', err.message);
|
|
res.status(400).send({ error: err.message, code: 400 });
|
|
}
|
|
};
|
|
|
|
export const syncMarketplaceItemsRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
|
|
const marketplace = await getObject({ model: marketplaceModel, id });
|
|
if (marketplace?.error) {
|
|
logger.warn('Marketplace not found for sync.');
|
|
return res.status(marketplace.code).send(marketplace);
|
|
}
|
|
|
|
if (!marketplace.active) {
|
|
return res.status(400).send({ error: 'Marketplace is not active.', code: 400 });
|
|
}
|
|
|
|
if (!marketplaceIntegration.hasIntegration(marketplace.provider)) {
|
|
return res.status(400).send({
|
|
error: `No integration available for provider: ${marketplace.provider}`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
marketplaceIntegration.syncItems(marketplace, req.user);
|
|
logger.info(`Item sync initiated in background for marketplace ${marketplace.name}`);
|
|
res.send({ success: true, message: 'Item sync started' });
|
|
};
|
|
|
|
export const syncMarketplaceOrdersRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const { startTime, endTime } = req.query;
|
|
|
|
const marketplace = await getObject({ model: marketplaceModel, id });
|
|
if (marketplace?.error) {
|
|
logger.warn('Marketplace not found for order sync.');
|
|
return res.status(marketplace.code).send(marketplace);
|
|
}
|
|
|
|
if (!marketplace.active) {
|
|
return res.status(400).send({ error: 'Marketplace is not active.', code: 400 });
|
|
}
|
|
|
|
if (!marketplaceIntegration.hasIntegration(marketplace.provider)) {
|
|
return res.status(400).send({
|
|
error: `No integration available for provider: ${marketplace.provider}`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
marketplaceIntegration.syncOrders(marketplace, req.user, {
|
|
startTime: startTime ? parseInt(startTime) : undefined,
|
|
endTime: endTime ? parseInt(endTime) : undefined,
|
|
});
|
|
|
|
logger.info(`Order sync initiated in background for marketplace ${marketplace.name}`);
|
|
res.send({ success: true, message: 'Order sync started' });
|
|
};
|
|
|
|
export const marketplaceWebhookRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
|
|
const marketplace = await getObject({ model: marketplaceModel, id });
|
|
if (marketplace?.error) {
|
|
logger.warn('Marketplace not found for webhook.');
|
|
return res.status(404).send({ error: 'Marketplace not found.', code: 404 });
|
|
}
|
|
|
|
if (!marketplaceIntegration.hasIntegration(marketplace.provider)) {
|
|
return res.status(400).send({
|
|
error: `No integration available for provider: ${marketplace.provider}`,
|
|
code: 400,
|
|
});
|
|
}
|
|
|
|
const signature =
|
|
req.headers['x-tts-signature'] ||
|
|
req.headers['x-ebay-signature'] ||
|
|
req.headers['x-signature'] ||
|
|
'';
|
|
const rawBody = JSON.stringify(req.body);
|
|
|
|
if (signature && marketplaceIntegration.canVerifyWebhookSignature(marketplace)) {
|
|
const valid = marketplaceIntegration.verifyWebhookSignature(marketplace, rawBody, signature);
|
|
if (!valid) {
|
|
logger.warn(`Invalid webhook signature for marketplace ${marketplace.name}`);
|
|
return res.status(401).send({ error: 'Invalid signature.', code: 401 });
|
|
}
|
|
}
|
|
|
|
try {
|
|
const result = await marketplaceIntegration.handleWebhook(marketplace, req.body);
|
|
logger.info(`Webhook processed for marketplace ${marketplace.name}: ${result.action}`);
|
|
res.send({ success: true, ...result });
|
|
} catch (err) {
|
|
logger.error('Error processing marketplace webhook:', err.message);
|
|
res.status(500).send({ error: err.message, code: 500 });
|
|
}
|
|
};
|