@unchainedshop/platform 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/bulk-importer/createBulkImporter.d.ts +4 -0
- package/lib/bulk-importer/createBulkImporter.js +102 -0
- package/lib/bulk-importer/createBulkImporter.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/create.d.ts +11 -0
- package/lib/bulk-importer/handlers/assortment/create.js +59 -0
- package/lib/bulk-importer/handlers/assortment/create.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/index.d.ts +3 -0
- package/lib/bulk-importer/handlers/assortment/index.js +4 -0
- package/lib/bulk-importer/handlers/assortment/index.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/remove.d.ts +9 -0
- package/lib/bulk-importer/handlers/assortment/remove.js +13 -0
- package/lib/bulk-importer/handlers/assortment/remove.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/update.d.ts +10 -0
- package/lib/bulk-importer/handlers/assortment/update.js +61 -0
- package/lib/bulk-importer/handlers/assortment/update.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js +30 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.js +9 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js +29 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js +32 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertMedia.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertMedia.js +67 -0
- package/lib/bulk-importer/handlers/assortment/upsertMedia.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/create.d.ts +11 -0
- package/lib/bulk-importer/handlers/filter/create.js +42 -0
- package/lib/bulk-importer/handlers/filter/create.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/index.d.ts +3 -0
- package/lib/bulk-importer/handlers/filter/index.js +4 -0
- package/lib/bulk-importer/handlers/filter/index.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/remove.d.ts +9 -0
- package/lib/bulk-importer/handlers/filter/remove.js +14 -0
- package/lib/bulk-importer/handlers/filter/remove.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/update.d.ts +10 -0
- package/lib/bulk-importer/handlers/filter/update.js +34 -0
- package/lib/bulk-importer/handlers/filter/update.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterContent.d.ts +13 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterContent.js +6 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterContent.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.d.ts +5 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.js +8 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.js.map +1 -0
- package/lib/bulk-importer/handlers/product/create.d.ts +11 -0
- package/lib/bulk-importer/handlers/product/create.js +51 -0
- package/lib/bulk-importer/handlers/product/create.js.map +1 -0
- package/lib/bulk-importer/handlers/product/index.d.ts +3 -0
- package/lib/bulk-importer/handlers/product/index.js +4 -0
- package/lib/bulk-importer/handlers/product/index.js.map +1 -0
- package/lib/bulk-importer/handlers/product/remove.d.ts +9 -0
- package/lib/bulk-importer/handlers/product/remove.js +14 -0
- package/lib/bulk-importer/handlers/product/remove.js.map +1 -0
- package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.d.ts +2 -0
- package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +13 -0
- package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js.map +1 -0
- package/lib/bulk-importer/handlers/product/update.d.ts +10 -0
- package/lib/bulk-importer/handlers/product/update.js +48 -0
- package/lib/bulk-importer/handlers/product/update.js.map +1 -0
- package/lib/bulk-importer/handlers/product/upsertMedia.d.ts +6 -0
- package/lib/bulk-importer/handlers/product/upsertMedia.js +69 -0
- package/lib/bulk-importer/handlers/product/upsertMedia.js.map +1 -0
- package/lib/bulk-importer/handlers/product/upsertProductContent.d.ts +6 -0
- package/lib/bulk-importer/handlers/product/upsertProductContent.js +9 -0
- package/lib/bulk-importer/handlers/product/upsertProductContent.js.map +1 -0
- package/lib/bulk-importer/handlers/product/upsertVariations.d.ts +6 -0
- package/lib/bulk-importer/handlers/product/upsertVariations.js +39 -0
- package/lib/bulk-importer/handlers/product/upsertVariations.js.map +1 -0
- package/lib/context/index.d.ts +2 -0
- package/lib/context/index.js +3 -0
- package/lib/context/index.js.map +1 -0
- package/lib/context/setAccessToken.d.ts +3 -0
- package/lib/context/setAccessToken.js +10 -0
- package/lib/context/setAccessToken.js.map +1 -0
- package/lib/context/withAccessToken.d.ts +2 -0
- package/lib/context/withAccessToken.js +33 -0
- package/lib/context/withAccessToken.js.map +1 -0
- package/lib/migrations/createMigrationRunner.d.ts +14 -0
- package/lib/migrations/createMigrationRunner.js +49 -0
- package/lib/migrations/createMigrationRunner.js.map +1 -0
- package/lib/migrations/migrationRepository.d.ts +3 -0
- package/lib/migrations/migrationRepository.js +16 -0
- package/lib/migrations/migrationRepository.js.map +1 -0
- package/lib/migrations/runMigrations.d.ts +7 -0
- package/lib/migrations/runMigrations.js +47 -0
- package/lib/migrations/runMigrations.js.map +1 -0
- package/lib/platform-index.d.ts +2 -0
- package/lib/platform-index.js +3 -0
- package/lib/platform-index.js.map +1 -0
- package/lib/setup/generateEventTypeDefs.d.ts +1 -0
- package/lib/setup/generateEventTypeDefs.js +9 -0
- package/lib/setup/generateEventTypeDefs.js.map +1 -0
- package/lib/setup/generateRoleActionTypeDefs.d.ts +1 -0
- package/lib/setup/generateRoleActionTypeDefs.js +9 -0
- package/lib/setup/generateRoleActionTypeDefs.js.map +1 -0
- package/lib/setup/generateWorkTypeDefs.d.ts +1 -0
- package/lib/setup/generateWorkTypeDefs.js +11 -0
- package/lib/setup/generateWorkTypeDefs.js.map +1 -0
- package/lib/setup/setupAccounts.d.ts +2 -0
- package/lib/setup/setupAccounts.js +91 -0
- package/lib/setup/setupAccounts.js.map +1 -0
- package/lib/setup/setupAutoScheduling.d.ts +1 -0
- package/lib/setup/setupAutoScheduling.js +5 -0
- package/lib/setup/setupAutoScheduling.js.map +1 -0
- package/lib/setup/setupCarts.d.ts +3 -0
- package/lib/setup/setupCarts.js +14 -0
- package/lib/setup/setupCarts.js.map +1 -0
- package/lib/setup/setupTemplates.d.ts +1 -0
- package/lib/setup/setupTemplates.js +17 -0
- package/lib/setup/setupTemplates.js.map +1 -0
- package/lib/setup/setupWorkqueue.d.ts +6 -0
- package/lib/setup/setupWorkqueue.js +11 -0
- package/lib/setup/setupWorkqueue.js.map +1 -0
- package/lib/startPlatform.d.ts +8 -0
- package/lib/startPlatform.js +105 -0
- package/lib/startPlatform.js.map +1 -0
- package/lib/templates/resolveAccountActionTemplate.d.ts +2 -0
- package/lib/templates/resolveAccountActionTemplate.js +131 -0
- package/lib/templates/resolveAccountActionTemplate.js.map +1 -0
- package/lib/templates/resolveEnrollmentStatusTemplate.d.ts +2 -0
- package/lib/templates/resolveEnrollmentStatusTemplate.js +34 -0
- package/lib/templates/resolveEnrollmentStatusTemplate.js.map +1 -0
- package/lib/templates/resolveForwardDeliveryTemplate.d.ts +2 -0
- package/lib/templates/resolveForwardDeliveryTemplate.js +114 -0
- package/lib/templates/resolveForwardDeliveryTemplate.js.map +1 -0
- package/lib/templates/resolveOrderConfirmationTemplate.d.ts +2 -0
- package/lib/templates/resolveOrderConfirmationTemplate.js +111 -0
- package/lib/templates/resolveOrderConfirmationTemplate.js.map +1 -0
- package/lib/templates/resolveOrderRejectionTemplate.d.ts +2 -0
- package/lib/templates/resolveOrderRejectionTemplate.js +77 -0
- package/lib/templates/resolveOrderRejectionTemplate.js.map +1 -0
- package/lib/templates/resolveQuotationStatusTemplate.d.ts +2 -0
- package/lib/templates/resolveQuotationStatusTemplate.js +40 -0
- package/lib/templates/resolveQuotationStatusTemplate.js.map +1 -0
- package/lib/templates/utils/getOrderAttachmentsData.d.ts +8 -0
- package/lib/templates/utils/getOrderAttachmentsData.js +28 -0
- package/lib/templates/utils/getOrderAttachmentsData.js.map +1 -0
- package/lib/templates/utils/getOrderPositionsData.d.ts +6 -0
- package/lib/templates/utils/getOrderPositionsData.js +32 -0
- package/lib/templates/utils/getOrderPositionsData.js.map +1 -0
- package/package.json +58 -0
- package/src/bulk-importer/createBulkImporter.ts +120 -0
- package/src/bulk-importer/handlers/assortment/create.ts +86 -0
- package/src/bulk-importer/handlers/assortment/index.js +3 -0
- package/src/bulk-importer/handlers/assortment/remove.ts +15 -0
- package/src/bulk-importer/handlers/assortment/update.ts +85 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentChildren.ts +51 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentContent.ts +20 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentFilters.ts +39 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentProducts.ts +55 -0
- package/src/bulk-importer/handlers/assortment/upsertMedia.ts +99 -0
- package/src/bulk-importer/handlers/filter/create.ts +62 -0
- package/src/bulk-importer/handlers/filter/index.js +3 -0
- package/src/bulk-importer/handlers/filter/remove.ts +16 -0
- package/src/bulk-importer/handlers/filter/update.ts +49 -0
- package/src/bulk-importer/handlers/filter/upsertFilterContent.ts +17 -0
- package/src/bulk-importer/handlers/filter/upsertFilterOptionContent.ts +21 -0
- package/src/bulk-importer/handlers/product/create.ts +73 -0
- package/src/bulk-importer/handlers/product/index.js +3 -0
- package/src/bulk-importer/handlers/product/remove.ts +17 -0
- package/src/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +19 -0
- package/src/bulk-importer/handlers/product/update.ts +65 -0
- package/src/bulk-importer/handlers/product/upsertMedia.ts +97 -0
- package/src/bulk-importer/handlers/product/upsertProductContent.ts +23 -0
- package/src/bulk-importer/handlers/product/upsertVariations.ts +77 -0
- package/src/context/index.ts +2 -0
- package/src/context/setAccessToken.ts +15 -0
- package/src/context/withAccessToken.ts +34 -0
- package/src/migrations/createMigrationRunner.js +61 -0
- package/src/migrations/migrationRepository.ts +18 -0
- package/src/migrations/runMigrations.ts +64 -0
- package/src/platform-index.ts +2 -0
- package/src/setup/generateEventTypeDefs.js +9 -0
- package/src/setup/generateRoleActionTypeDefs.js +9 -0
- package/src/setup/generateWorkTypeDefs.js +11 -0
- package/src/setup/setupAccounts.ts +129 -0
- package/src/setup/setupAutoScheduling.ts +5 -0
- package/src/setup/setupCarts.ts +27 -0
- package/src/setup/setupTemplates.ts +17 -0
- package/src/setup/setupWorkqueue.ts +17 -0
- package/src/startPlatform.ts +145 -0
- package/src/templates/resolveAccountActionTemplate.ts +144 -0
- package/src/templates/resolveEnrollmentStatusTemplate.ts +43 -0
- package/src/templates/resolveForwardDeliveryTemplate.ts +128 -0
- package/src/templates/resolveOrderConfirmationTemplate.ts +133 -0
- package/src/templates/resolveOrderRejectionTemplate.ts +85 -0
- package/src/templates/resolveQuotationStatusTemplate.ts +54 -0
- package/src/templates/utils/getOrderAttachmentsData.ts +47 -0
- package/src/templates/utils/getOrderPositionsData.ts +49 -0
- package/tsconfig.build.json +26 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import upsertFilterContent from './upsertFilterContent';
|
|
3
|
+
import upsertFilterOptionContent from './upsertFilterOptionContent';
|
|
4
|
+
|
|
5
|
+
export default async function createFilter(
|
|
6
|
+
payload: any,
|
|
7
|
+
{ logger, authorId, createShouldUpsertIfIDExists },
|
|
8
|
+
unchainedAPI: Context,
|
|
9
|
+
) {
|
|
10
|
+
const { modules } = unchainedAPI;
|
|
11
|
+
const { specification, _id } = payload;
|
|
12
|
+
|
|
13
|
+
if (!specification) throw new Error(`Specification is required when creating new filter ${_id}`);
|
|
14
|
+
|
|
15
|
+
const { content, options, ...filterData } = specification;
|
|
16
|
+
|
|
17
|
+
if (!content) throw new Error(`Localizable content is required when creating new filter${_id}`);
|
|
18
|
+
|
|
19
|
+
logger.debug('create filter object', specification);
|
|
20
|
+
let filter;
|
|
21
|
+
try {
|
|
22
|
+
filter = await unchainedAPI.modules.filters.create(
|
|
23
|
+
{
|
|
24
|
+
...filterData,
|
|
25
|
+
_id,
|
|
26
|
+
options: options?.map((option) => option.value) || [],
|
|
27
|
+
authorId,
|
|
28
|
+
},
|
|
29
|
+
unchainedAPI,
|
|
30
|
+
{ skipInvalidation: true },
|
|
31
|
+
unchainedAPI.userId,
|
|
32
|
+
);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
if (!createShouldUpsertIfIDExists) throw e;
|
|
35
|
+
|
|
36
|
+
logger.debug('entity already exists, falling back to update', specification);
|
|
37
|
+
filter = await modules.filters.update(
|
|
38
|
+
_id,
|
|
39
|
+
{
|
|
40
|
+
...filterData,
|
|
41
|
+
options: options?.map((option) => option.value) || [],
|
|
42
|
+
authorId,
|
|
43
|
+
},
|
|
44
|
+
unchainedAPI,
|
|
45
|
+
{ skipInvalidation: true },
|
|
46
|
+
unchainedAPI.userId,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
logger.debug('create localized content for filter', content);
|
|
51
|
+
await upsertFilterContent({ content, filter, authorId }, unchainedAPI);
|
|
52
|
+
|
|
53
|
+
logger.debug('create localized content for filter options', content);
|
|
54
|
+
await upsertFilterOptionContent({ options, filter }, unchainedAPI);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
entity: 'FILTER',
|
|
58
|
+
operation: 'create',
|
|
59
|
+
_id,
|
|
60
|
+
success: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
|
|
3
|
+
export default async function removeFilter(payload: any, { logger }, unchainedAPI: Context) {
|
|
4
|
+
const { modules, userId } = unchainedAPI;
|
|
5
|
+
const { _id } = payload;
|
|
6
|
+
logger.debug('remove filter');
|
|
7
|
+
await modules.assortments.filters.deleteMany({ filterId: _id }, userId);
|
|
8
|
+
await modules.filters.delete(_id);
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
entity: 'FILTER',
|
|
12
|
+
operation: 'remove',
|
|
13
|
+
_id,
|
|
14
|
+
success: true,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import upsertFilterContent from './upsertFilterContent';
|
|
3
|
+
import upsertFilterOptionContent from './upsertFilterOptionContent';
|
|
4
|
+
|
|
5
|
+
export default async function updateFilter(
|
|
6
|
+
payload: any,
|
|
7
|
+
{ authorId, logger }: { authorId: string; logger: any },
|
|
8
|
+
unchainedAPI: Context,
|
|
9
|
+
) {
|
|
10
|
+
const { modules } = unchainedAPI;
|
|
11
|
+
const { specification, _id } = payload;
|
|
12
|
+
|
|
13
|
+
if (!specification) throw new Error('Specification is required when creating a new filter');
|
|
14
|
+
|
|
15
|
+
logger.debug('update filter object', specification);
|
|
16
|
+
const { content, options, ...filterData } = specification;
|
|
17
|
+
const filter = await modules.filters.update(
|
|
18
|
+
_id,
|
|
19
|
+
{
|
|
20
|
+
...filterData,
|
|
21
|
+
options: options?.map((option) => option.value) || [],
|
|
22
|
+
authorId,
|
|
23
|
+
},
|
|
24
|
+
unchainedAPI,
|
|
25
|
+
{ skipInvalidation: true },
|
|
26
|
+
unchainedAPI.userId,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (content || options) {
|
|
30
|
+
if (!filter) throw new Error(`Can't update non-existing filter ${_id}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (content) {
|
|
34
|
+
logger.debug('replace localized content for filter', content);
|
|
35
|
+
await upsertFilterContent({ content, filter, authorId }, unchainedAPI);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (options) {
|
|
39
|
+
logger.debug('replace localized content for filter options', content);
|
|
40
|
+
await upsertFilterOptionContent({ options, filter }, unchainedAPI);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
entity: 'FILTER',
|
|
45
|
+
operation: 'update',
|
|
46
|
+
_id,
|
|
47
|
+
success: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import { FilterText } from '@unchainedshop/types/filters';
|
|
3
|
+
|
|
4
|
+
export default async function upsertFilterContent({ content, filter, authorId }, unchainedAPI: Context) {
|
|
5
|
+
return Promise.all(
|
|
6
|
+
Object.entries(content).map(
|
|
7
|
+
async ([locale, { authorId: tAuthorId, ...localizedData }]: [string, FilterText]) => {
|
|
8
|
+
return unchainedAPI.modules.filters.texts.upsertLocalizedText(
|
|
9
|
+
{ filterId: filter._id },
|
|
10
|
+
locale,
|
|
11
|
+
localizedData,
|
|
12
|
+
tAuthorId || authorId || unchainedAPI.userId,
|
|
13
|
+
);
|
|
14
|
+
},
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import { FilterText } from '@unchainedshop/types/filters';
|
|
3
|
+
|
|
4
|
+
export default async function upsertFilterOptionContent({ options, filter }, unchainedAPI: Context) {
|
|
5
|
+
return Promise.all(
|
|
6
|
+
(options || []).map(async ({ content: optionContent, value: optionValue }) => {
|
|
7
|
+
await Promise.all(
|
|
8
|
+
Object.entries(optionContent).map(
|
|
9
|
+
async ([locale, { authorId, ...localizedData }]: [string, FilterText]) => {
|
|
10
|
+
return unchainedAPI.modules.filters.texts.upsertLocalizedText(
|
|
11
|
+
{ filterId: filter._id, filterOptionValue: optionValue },
|
|
12
|
+
locale,
|
|
13
|
+
localizedData,
|
|
14
|
+
authorId || unchainedAPI.userId,
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
),
|
|
18
|
+
);
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import upsertVariations from './upsertVariations';
|
|
3
|
+
import upsertMedia from './upsertMedia';
|
|
4
|
+
import upsertProductContent from './upsertProductContent';
|
|
5
|
+
import transformSpecificationToProductStructure from './transformSpecificationToProductStructure';
|
|
6
|
+
|
|
7
|
+
export default async function createProduct(
|
|
8
|
+
payload: any,
|
|
9
|
+
{ logger, authorId, createShouldUpsertIfIDExists },
|
|
10
|
+
unchainedAPI: Context,
|
|
11
|
+
) {
|
|
12
|
+
const { modules, userId } = unchainedAPI;
|
|
13
|
+
const { specification, media, variations, _id } = payload;
|
|
14
|
+
|
|
15
|
+
if (!specification) throw new Error(`Specification is required when creating new product ${_id}`);
|
|
16
|
+
|
|
17
|
+
if (!specification.content) throw new Error(`Content is required when creating new product ${_id}`);
|
|
18
|
+
|
|
19
|
+
const productData = transformSpecificationToProductStructure(specification);
|
|
20
|
+
logger.debug('create product object', productData);
|
|
21
|
+
try {
|
|
22
|
+
await modules.products.create(
|
|
23
|
+
{
|
|
24
|
+
...productData,
|
|
25
|
+
_id,
|
|
26
|
+
authorId,
|
|
27
|
+
},
|
|
28
|
+
userId,
|
|
29
|
+
);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
if (!createShouldUpsertIfIDExists) throw e;
|
|
32
|
+
|
|
33
|
+
logger.debug('entity already exists, falling back to update', specification);
|
|
34
|
+
await modules.products.update(
|
|
35
|
+
_id,
|
|
36
|
+
{
|
|
37
|
+
...productData,
|
|
38
|
+
authorId,
|
|
39
|
+
},
|
|
40
|
+
userId,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
logger.debug('create localized content for product', specification.content);
|
|
45
|
+
await upsertProductContent(
|
|
46
|
+
{
|
|
47
|
+
content: specification.content,
|
|
48
|
+
productId: _id,
|
|
49
|
+
authorId,
|
|
50
|
+
},
|
|
51
|
+
unchainedAPI,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
logger.debug('create product variations', variations);
|
|
55
|
+
await upsertVariations(
|
|
56
|
+
{
|
|
57
|
+
variations: variations || [],
|
|
58
|
+
productId: _id,
|
|
59
|
+
authorId,
|
|
60
|
+
},
|
|
61
|
+
unchainedAPI,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
logger.debug('create product media', media);
|
|
65
|
+
await upsertMedia({ media: media || [], productId: _id, authorId }, unchainedAPI);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
entity: 'PRODUCT',
|
|
69
|
+
operation: 'create',
|
|
70
|
+
_id,
|
|
71
|
+
success: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
|
|
3
|
+
export default async function removeProduct(payload: any, { logger }, unchainedAPI: Context) {
|
|
4
|
+
const { modules, userId } = unchainedAPI;
|
|
5
|
+
const { _id } = payload;
|
|
6
|
+
logger.debug('remove product');
|
|
7
|
+
|
|
8
|
+
// Use service services.product.removeProduct
|
|
9
|
+
await modules.products.delete(_id, userId);
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
entity: 'PRODUCT',
|
|
13
|
+
operation: 'remove',
|
|
14
|
+
_id,
|
|
15
|
+
success: true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default (specification) => {
|
|
2
|
+
const {
|
|
3
|
+
variationResolvers: assignments,
|
|
4
|
+
content, // eslint-disable-line
|
|
5
|
+
warehousing: warehousingEmbeddedSupply,
|
|
6
|
+
...productData
|
|
7
|
+
} = specification;
|
|
8
|
+
|
|
9
|
+
const { dimensions: supply, ...warehousing } = warehousingEmbeddedSupply || {};
|
|
10
|
+
|
|
11
|
+
const proxy = assignments ? { assignments } : undefined;
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
...productData,
|
|
15
|
+
warehousing,
|
|
16
|
+
supply,
|
|
17
|
+
proxy,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import upsertVariations from './upsertVariations';
|
|
3
|
+
import upsertMedia from './upsertMedia';
|
|
4
|
+
import upsertProductContent from './upsertProductContent';
|
|
5
|
+
import transformSpecificationToProductStructure from './transformSpecificationToProductStructure';
|
|
6
|
+
|
|
7
|
+
export default async function createProduct(payload: any, { logger, authorId }, unchainedAPI: Context) {
|
|
8
|
+
const { modules, userId } = unchainedAPI;
|
|
9
|
+
const { specification, media, variations, _id } = payload;
|
|
10
|
+
|
|
11
|
+
if (specification) {
|
|
12
|
+
const productData = transformSpecificationToProductStructure(specification);
|
|
13
|
+
logger.debug('update product object', productData);
|
|
14
|
+
await modules.products.update(
|
|
15
|
+
_id,
|
|
16
|
+
{
|
|
17
|
+
...productData,
|
|
18
|
+
authorId,
|
|
19
|
+
},
|
|
20
|
+
userId,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (specification.content) {
|
|
24
|
+
logger.debug('replace localized content for product', specification.content);
|
|
25
|
+
await upsertProductContent(
|
|
26
|
+
{
|
|
27
|
+
content: specification.content,
|
|
28
|
+
productId: _id,
|
|
29
|
+
authorId,
|
|
30
|
+
},
|
|
31
|
+
unchainedAPI,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (variations || media) {
|
|
37
|
+
if (!(await modules.products.productExists({ productId: _id }))) {
|
|
38
|
+
throw new Error(`Can't update non-existing product ${_id}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (variations) {
|
|
43
|
+
logger.debug('replace variations', variations);
|
|
44
|
+
await upsertVariations(
|
|
45
|
+
{
|
|
46
|
+
variations: variations || [],
|
|
47
|
+
productId: _id,
|
|
48
|
+
authorId,
|
|
49
|
+
},
|
|
50
|
+
unchainedAPI,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (media) {
|
|
55
|
+
logger.debug('replace product media', media);
|
|
56
|
+
await upsertMedia({ media, productId: _id, authorId }, unchainedAPI);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
entity: 'PRODUCT',
|
|
61
|
+
operation: 'update',
|
|
62
|
+
_id,
|
|
63
|
+
success: true,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import { File } from '@unchainedshop/types/files';
|
|
3
|
+
import { ProductMedia, ProductMediaText } from '@unchainedshop/types/products.media';
|
|
4
|
+
|
|
5
|
+
const upsertAsset = async (
|
|
6
|
+
asset: File & { fileName: string; headers?: Record<string, unknown> },
|
|
7
|
+
unchainedAPI: Context,
|
|
8
|
+
) => {
|
|
9
|
+
const { modules, services, userId } = unchainedAPI;
|
|
10
|
+
const { _id, fileName, url, meta, headers, ...assetData } = asset;
|
|
11
|
+
const fileId = _id;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (_id && (await modules.files.findFile({ fileId }))) throw new Error('Media already exists');
|
|
15
|
+
|
|
16
|
+
const assetObject = await services.files.uploadFileFromURL(
|
|
17
|
+
{
|
|
18
|
+
directoryName: 'product-media',
|
|
19
|
+
fileInput: {
|
|
20
|
+
fileLink: url,
|
|
21
|
+
fileName,
|
|
22
|
+
headers,
|
|
23
|
+
},
|
|
24
|
+
meta: { ...meta, fileId },
|
|
25
|
+
userId,
|
|
26
|
+
},
|
|
27
|
+
unchainedAPI,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (!assetObject) throw new Error('Media not created');
|
|
31
|
+
return assetObject;
|
|
32
|
+
} catch (e) {
|
|
33
|
+
if (fileId) {
|
|
34
|
+
await modules.files.update(fileId, { meta: { ...meta, fileId }, ...assetData }, userId);
|
|
35
|
+
const file = await modules.files.findFile({ fileId });
|
|
36
|
+
return file;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const upsertProductMedia = async (productMedia: ProductMedia, { modules, userId }: Context) => {
|
|
43
|
+
try {
|
|
44
|
+
const productMediaObj = await modules.products.media.create(productMedia, userId);
|
|
45
|
+
return productMediaObj;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
const { _id, ...productMediaData } = productMedia;
|
|
48
|
+
const productMediaId = _id;
|
|
49
|
+
return modules.products.media.update(productMediaId, productMediaData);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default async function upsertMedia({ media, authorId, productId }, unchainedAPI: Context) {
|
|
54
|
+
const { modules, userId } = unchainedAPI;
|
|
55
|
+
|
|
56
|
+
const productMediaObjects = await Promise.all(
|
|
57
|
+
media.map(async ({ asset, content, ...mediaData }) => {
|
|
58
|
+
const file = await upsertAsset(
|
|
59
|
+
{ meta: { ...(asset.meta || {}), productId }, ...asset },
|
|
60
|
+
unchainedAPI,
|
|
61
|
+
);
|
|
62
|
+
if (!file) throw new Error(`Unable to create binary ${asset._id}`);
|
|
63
|
+
const fileId = file._id;
|
|
64
|
+
const productMedia = await upsertProductMedia(
|
|
65
|
+
{
|
|
66
|
+
authorId,
|
|
67
|
+
...mediaData,
|
|
68
|
+
productId,
|
|
69
|
+
mediaId: file._id,
|
|
70
|
+
} as ProductMedia,
|
|
71
|
+
unchainedAPI,
|
|
72
|
+
);
|
|
73
|
+
if (!productMedia) throw new Error(`Unable to create product media object for file ${fileId}`);
|
|
74
|
+
|
|
75
|
+
if (content) {
|
|
76
|
+
await Promise.all(
|
|
77
|
+
Object.entries(content).map(
|
|
78
|
+
async ([locale, { authorId: tAuthorId, ...localizedData }]: [string, ProductMediaText]) => {
|
|
79
|
+
return modules.products.media.texts.upsertLocalizedText(
|
|
80
|
+
productMedia._id,
|
|
81
|
+
locale,
|
|
82
|
+
localizedData,
|
|
83
|
+
tAuthorId || authorId || userId,
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return productMedia;
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
await modules.products.media.deleteMediaFiles({
|
|
94
|
+
productId,
|
|
95
|
+
excludedProductMediaIds: productMediaObjects.map((obj) => obj._id),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import { ProductText } from '@unchainedshop/types/products';
|
|
3
|
+
|
|
4
|
+
export default async function upsertProductContent(
|
|
5
|
+
{ productId, content, authorId },
|
|
6
|
+
{ modules, userId }: Context,
|
|
7
|
+
) {
|
|
8
|
+
const product = await modules.products.findProduct({ productId });
|
|
9
|
+
if (!product) throw new Error(`Can't update content of non-existing product ${productId}`);
|
|
10
|
+
|
|
11
|
+
await Promise.all(
|
|
12
|
+
Object.entries(content).map(
|
|
13
|
+
async ([locale, { authorId: tAuthorId, ...localizedData }]: [string, ProductText]) => {
|
|
14
|
+
return modules.products.texts.upsertLocalizedText(
|
|
15
|
+
productId,
|
|
16
|
+
locale,
|
|
17
|
+
localizedData,
|
|
18
|
+
tAuthorId || authorId || userId,
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
),
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
import { ProductVariation, ProductVariationText } from '@unchainedshop/types/products.variations';
|
|
3
|
+
|
|
4
|
+
const upsert = async (productVariation: ProductVariation, unchainedAPI: Context) => {
|
|
5
|
+
const { modules, userId } = unchainedAPI;
|
|
6
|
+
try {
|
|
7
|
+
return modules.products.variations.create(productVariation, userId);
|
|
8
|
+
} catch (e) {
|
|
9
|
+
return modules.products.variations.update(productVariation._id, productVariation);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default async function upsertVariations(
|
|
14
|
+
{ variations, authorId, productId },
|
|
15
|
+
unchainedAPI: Context,
|
|
16
|
+
) {
|
|
17
|
+
const { modules, userId } = unchainedAPI;
|
|
18
|
+
|
|
19
|
+
const productVariationObjects = await Promise.all(
|
|
20
|
+
variations.map(async ({ content, options, ...variationsRest }) => {
|
|
21
|
+
const variation = await upsert(
|
|
22
|
+
{
|
|
23
|
+
authorId,
|
|
24
|
+
...variationsRest,
|
|
25
|
+
options: options.map((option) => option.value),
|
|
26
|
+
productId,
|
|
27
|
+
},
|
|
28
|
+
unchainedAPI,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
await Promise.all(
|
|
32
|
+
options.map(async ({ content: optionContent, value: optionValue }) => {
|
|
33
|
+
await Promise.all(
|
|
34
|
+
Object.entries(optionContent).map(
|
|
35
|
+
async ([locale, { authorId: tAuthorId, ...localizedData }]: [
|
|
36
|
+
string,
|
|
37
|
+
ProductVariationText,
|
|
38
|
+
]) => {
|
|
39
|
+
return modules.products.variations.texts.upsertLocalizedText(
|
|
40
|
+
{
|
|
41
|
+
productVariationId: variation._id,
|
|
42
|
+
productVariationOptionValue: optionValue,
|
|
43
|
+
},
|
|
44
|
+
locale,
|
|
45
|
+
localizedData,
|
|
46
|
+
tAuthorId || authorId || userId,
|
|
47
|
+
);
|
|
48
|
+
},
|
|
49
|
+
),
|
|
50
|
+
);
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
53
|
+
await Promise.all(
|
|
54
|
+
Object.entries(content).map(
|
|
55
|
+
async ([locale, { authorId: tAuthorId, ...localizedData }]: [
|
|
56
|
+
string,
|
|
57
|
+
ProductVariationText,
|
|
58
|
+
]) => {
|
|
59
|
+
return modules.products.variations.texts.upsertLocalizedText(
|
|
60
|
+
{
|
|
61
|
+
productVariationId: variation._id,
|
|
62
|
+
},
|
|
63
|
+
locale,
|
|
64
|
+
localizedData,
|
|
65
|
+
tAuthorId || authorId || userId,
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
return variation;
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
await modules.products.variations.deleteVariations({
|
|
74
|
+
productId,
|
|
75
|
+
excludedProductVariationIds: productVariationObjects.map((obj) => obj._id),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Context } from '@unchainedshop/types/api';
|
|
2
|
+
|
|
3
|
+
export default async (unchainedAPI: Context, username: string, secret: string) => {
|
|
4
|
+
await unchainedAPI.modules.users.updateUser(
|
|
5
|
+
{ username },
|
|
6
|
+
{
|
|
7
|
+
$set: {
|
|
8
|
+
'services.token': {
|
|
9
|
+
secret,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
{},
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
+
|
|
3
|
+
const logger = createLogger('unchained:platform');
|
|
4
|
+
|
|
5
|
+
const contextIdentity = (params) => params;
|
|
6
|
+
|
|
7
|
+
export default (fn = contextIdentity) => {
|
|
8
|
+
return async (params, unchainedContextFn) => {
|
|
9
|
+
const unchainedContext = await unchainedContextFn(params);
|
|
10
|
+
const newContext = {
|
|
11
|
+
userId: unchainedContext.userId,
|
|
12
|
+
user: unchainedContext.user,
|
|
13
|
+
};
|
|
14
|
+
if (!unchainedContext.userId && params.req.headers.authorization) {
|
|
15
|
+
const [type, userToken] = params.req.headers.authorization.split(' ');
|
|
16
|
+
if (type === 'Bearer' && userToken) {
|
|
17
|
+
const [username, secret] = userToken.split(':');
|
|
18
|
+
const user = await unchainedContext.modules.users.findUser({
|
|
19
|
+
username,
|
|
20
|
+
});
|
|
21
|
+
if (secret && user?.services.token?.secret === secret) {
|
|
22
|
+
newContext.userId = user._id;
|
|
23
|
+
newContext.user = user;
|
|
24
|
+
} else {
|
|
25
|
+
logger.warn('Token login failed');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return fn({
|
|
30
|
+
...unchainedContext,
|
|
31
|
+
...newContext,
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
class MigrationError extends Error {
|
|
2
|
+
constructor(migrationId = null, ...params) {
|
|
3
|
+
// Pass remaining arguments (including vendor specific ones) to parent constructor
|
|
4
|
+
super(...params);
|
|
5
|
+
|
|
6
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
7
|
+
if (Error.captureStackTrace) {
|
|
8
|
+
Error.captureStackTrace(this, MigrationError);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.name = 'MigrationError';
|
|
12
|
+
this.migrationId = migrationId;
|
|
13
|
+
this.date = new Date();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const createMigrationRunner = ({
|
|
18
|
+
currentId,
|
|
19
|
+
logger = console,
|
|
20
|
+
migrationRepository,
|
|
21
|
+
onMigrationComplete,
|
|
22
|
+
unchainedAPI,
|
|
23
|
+
}) => ({
|
|
24
|
+
operationFactory(action) {
|
|
25
|
+
const migrationContext = { logger, unchainedAPI };
|
|
26
|
+
|
|
27
|
+
return (migration) => async () => {
|
|
28
|
+
try {
|
|
29
|
+
await migration[action](migrationContext);
|
|
30
|
+
await onMigrationComplete(migration.id, action);
|
|
31
|
+
return migration.id;
|
|
32
|
+
} catch (e) {
|
|
33
|
+
throw new MigrationError(migration.id, e.message);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
isIdAfterCurrentId({ id }) {
|
|
38
|
+
return id > currentId;
|
|
39
|
+
},
|
|
40
|
+
migrateToLatest() {
|
|
41
|
+
return migrationRepository
|
|
42
|
+
.allMigrations()
|
|
43
|
+
.filter(this.isIdAfterCurrentId)
|
|
44
|
+
.map(this.operationFactory('up'));
|
|
45
|
+
},
|
|
46
|
+
async run() {
|
|
47
|
+
try {
|
|
48
|
+
const migrations = this.migrateToLatest();
|
|
49
|
+
|
|
50
|
+
const mostRecentId = await migrations.reduce(
|
|
51
|
+
(idPromise, migration) => Promise.resolve(idPromise).then(migration),
|
|
52
|
+
currentId,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return [mostRecentId, migrations.length];
|
|
56
|
+
} catch (e) {
|
|
57
|
+
logger.error(e.name, e);
|
|
58
|
+
return [e.migrationId, null];
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
});
|