@contentstack/cli-variants 2.0.0-beta.11 → 2.0.0-beta.12
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/lib/export/attributes.js +1 -1
- package/lib/export/audiences.js +1 -1
- package/lib/export/events.js +1 -1
- package/lib/export/experiences.js +1 -1
- package/lib/export/projects.js +1 -1
- package/lib/export/variant-entries.js +1 -1
- package/lib/import/audiences.js +8 -3
- package/lib/types/export-config.d.ts +0 -1
- package/package.json +3 -3
- package/src/export/attributes.ts +0 -1
- package/src/export/audiences.ts +0 -1
- package/src/export/events.ts +0 -1
- package/src/export/experiences.ts +0 -1
- package/src/export/projects.ts +0 -1
- package/src/export/variant-entries.ts +0 -1
- package/src/import/audiences.ts +6 -0
- package/src/types/export-config.ts +0 -1
- package/test/unit/export/variant-entries.test.ts +13 -0
- package/test/unit/import/audiences.test.ts +118 -0
- package/test/unit/mock/contents/mapper/personalize/attributes/uid-mapping.json +1 -0
- package/test/unit/mock/contents/mapper/personalize/audiences/uid-mapping.json +1 -0
- package/test/unit/mock/contents/personalize/audiences/audiences.json +44 -0
package/lib/export/attributes.js
CHANGED
|
@@ -27,7 +27,7 @@ class ExportAttributes extends utils_1.PersonalizationAdapter {
|
|
|
27
27
|
this.exportConfig = exportConfig;
|
|
28
28
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
29
29
|
this.attributesConfig = exportConfig.modules.attributes;
|
|
30
|
-
this.attributesFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(
|
|
30
|
+
this.attributesFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.personalizeConfig.dirName), (0, cli_utilities_1.sanitizePath)(this.attributesConfig.dirName));
|
|
31
31
|
this.attributes = [];
|
|
32
32
|
this.exportConfig.context.module = constants_1.MODULE_CONTEXTS.ATTRIBUTES;
|
|
33
33
|
}
|
package/lib/export/audiences.js
CHANGED
|
@@ -27,7 +27,7 @@ class ExportAudiences extends utils_1.PersonalizationAdapter {
|
|
|
27
27
|
this.exportConfig = exportConfig;
|
|
28
28
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
29
29
|
this.audiencesConfig = exportConfig.modules.audiences;
|
|
30
|
-
this.audiencesFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(
|
|
30
|
+
this.audiencesFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.personalizeConfig.dirName), (0, cli_utilities_1.sanitizePath)(this.audiencesConfig.dirName));
|
|
31
31
|
this.audiences = [];
|
|
32
32
|
this.exportConfig.context.module = constants_1.MODULE_CONTEXTS.AUDIENCES;
|
|
33
33
|
}
|
package/lib/export/events.js
CHANGED
|
@@ -27,7 +27,7 @@ class ExportEvents extends utils_1.PersonalizationAdapter {
|
|
|
27
27
|
this.exportConfig = exportConfig;
|
|
28
28
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
29
29
|
this.eventsConfig = exportConfig.modules.events;
|
|
30
|
-
this.eventsFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(
|
|
30
|
+
this.eventsFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.personalizeConfig.dirName), (0, cli_utilities_1.sanitizePath)(this.eventsConfig.dirName));
|
|
31
31
|
this.events = [];
|
|
32
32
|
this.exportConfig.context.module = constants_1.MODULE_CONTEXTS.EVENTS;
|
|
33
33
|
}
|
|
@@ -59,7 +59,7 @@ class ExportExperiences extends utils_1.PersonalizationAdapter {
|
|
|
59
59
|
});
|
|
60
60
|
this.exportConfig = exportConfig;
|
|
61
61
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
62
|
-
this.experiencesFolderPath = path.resolve((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(
|
|
62
|
+
this.experiencesFolderPath = path.resolve((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.personalizeConfig.dirName), 'experiences');
|
|
63
63
|
this.exportConfig.context.module = constants_1.MODULE_CONTEXTS.EXPERIENCES;
|
|
64
64
|
}
|
|
65
65
|
start() {
|
package/lib/export/projects.js
CHANGED
|
@@ -22,7 +22,7 @@ class ExportProjects extends utils_1.PersonalizationAdapter {
|
|
|
22
22
|
});
|
|
23
23
|
this.exportConfig = exportConfig;
|
|
24
24
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
25
|
-
this.projectsFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(
|
|
25
|
+
this.projectsFolderPath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.personalizeConfig.dirName), 'projects');
|
|
26
26
|
this.projectsData = [];
|
|
27
27
|
this.exportConfig.context.module = constants_1.MODULE_CONTEXTS.PROJECTS;
|
|
28
28
|
}
|
|
@@ -68,7 +68,7 @@ class VariantEntries extends variant_api_adapter_1.default {
|
|
|
68
68
|
this.processInitialized = false;
|
|
69
69
|
this.totalVariantCount = 0;
|
|
70
70
|
this.processedVariantCount = 0;
|
|
71
|
-
this.entriesDirPath = (0, path_1.resolve)((0, cli_utilities_1.sanitizePath)(config.exportDir), (0, cli_utilities_1.sanitizePath)(config.
|
|
71
|
+
this.entriesDirPath = (0, path_1.resolve)((0, cli_utilities_1.sanitizePath)(config.exportDir), (0, cli_utilities_1.sanitizePath)(config.modules.entries.dirName));
|
|
72
72
|
if (this.config && this.config.context) {
|
|
73
73
|
this.config.context.module = 'variant-entries';
|
|
74
74
|
}
|
package/lib/import/audiences.js
CHANGED
|
@@ -39,7 +39,7 @@ class Audiences extends utils_1.PersonalizationAdapter {
|
|
|
39
39
|
*/
|
|
40
40
|
import() {
|
|
41
41
|
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
-
var _a, _b;
|
|
42
|
+
var _a, _b, _c;
|
|
43
43
|
try {
|
|
44
44
|
cli_utilities_1.log.debug('Starting audiences import...', this.config.context);
|
|
45
45
|
const [canImport, audiencesCount] = yield this.analyzeAudiences();
|
|
@@ -73,9 +73,14 @@ class Audiences extends utils_1.PersonalizationAdapter {
|
|
|
73
73
|
progress.updateStatus(constants_1.IMPORT_PROCESS_STATUS[constants_1.PROCESS_NAMES.AUDIENCES].CREATING);
|
|
74
74
|
}
|
|
75
75
|
cli_utilities_1.log.debug(`Processing audience: ${name} (${uid})`, this.config.context);
|
|
76
|
+
// Skip Lytics audiences - they cannot be created via API (synced from Lytics)
|
|
77
|
+
if (((_a = audience.source) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === 'LYTICS') {
|
|
78
|
+
cli_utilities_1.log.debug(`Skipping Lytics audience: ${name} (${uid})`, this.config.context);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
76
81
|
try {
|
|
77
82
|
//check whether reference attributes exists or not
|
|
78
|
-
if ((
|
|
83
|
+
if ((_b = definition.rules) === null || _b === void 0 ? void 0 : _b.length) {
|
|
79
84
|
cli_utilities_1.log.debug(`Processing ${definition.rules.length} definition rules for audience: ${name}`, this.config.context);
|
|
80
85
|
definition.rules = (0, utils_1.lookUpAttributes)(definition.rules, attributesUid);
|
|
81
86
|
cli_utilities_1.log.debug(`Processed definition rules, remaining rules: ${definition.rules.length}`, this.config.context);
|
|
@@ -87,7 +92,7 @@ class Audiences extends utils_1.PersonalizationAdapter {
|
|
|
87
92
|
const audienceRes = yield this.createAudience({ definition, name, description });
|
|
88
93
|
//map old audience uid to new audience uid
|
|
89
94
|
//mapper file is used to check whether audience created or not before creating experience
|
|
90
|
-
this.audiencesUidMapper[uid] = (
|
|
95
|
+
this.audiencesUidMapper[uid] = (_c = audienceRes === null || audienceRes === void 0 ? void 0 : audienceRes.uid) !== null && _c !== void 0 ? _c : '';
|
|
91
96
|
this.updateProgress(true, `audience: ${name}`, undefined, constants_1.PROCESS_NAMES.AUDIENCES);
|
|
92
97
|
cli_utilities_1.log.debug(`Created audience: ${uid} -> ${audienceRes === null || audienceRes === void 0 ? void 0 : audienceRes.uid}`, this.config.context);
|
|
93
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-variants",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.12",
|
|
4
4
|
"description": "Variants plugin",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"typescript": "^5.8.3"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@contentstack/cli-utilities": "~2.0.0-beta.
|
|
31
|
+
"@contentstack/cli-utilities": "~2.0.0-beta.7",
|
|
32
32
|
"@oclif/core": "^4.3.0",
|
|
33
33
|
"@oclif/plugin-help": "^6.2.28",
|
|
34
|
-
"lodash": "^4.
|
|
34
|
+
"lodash": "^4.18.1",
|
|
35
35
|
"mkdirp": "^1.0.4",
|
|
36
36
|
"winston": "^3.17.0"
|
|
37
37
|
}
|
package/src/export/attributes.ts
CHANGED
|
@@ -23,7 +23,6 @@ export default class ExportAttributes extends PersonalizationAdapter<ExportConfi
|
|
|
23
23
|
this.attributesConfig = exportConfig.modules.attributes;
|
|
24
24
|
this.attributesFolderPath = pResolve(
|
|
25
25
|
sanitizePath(exportConfig.exportDir),
|
|
26
|
-
sanitizePath(exportConfig.branchName || ''),
|
|
27
26
|
sanitizePath(this.personalizeConfig.dirName),
|
|
28
27
|
sanitizePath(this.attributesConfig.dirName),
|
|
29
28
|
);
|
package/src/export/audiences.ts
CHANGED
|
@@ -23,7 +23,6 @@ export default class ExportAudiences extends PersonalizationAdapter<ExportConfig
|
|
|
23
23
|
this.audiencesConfig = exportConfig.modules.audiences;
|
|
24
24
|
this.audiencesFolderPath = pResolve(
|
|
25
25
|
sanitizePath(exportConfig.exportDir),
|
|
26
|
-
sanitizePath(exportConfig.branchName || ''),
|
|
27
26
|
sanitizePath(this.personalizeConfig.dirName),
|
|
28
27
|
sanitizePath(this.audiencesConfig.dirName),
|
|
29
28
|
);
|
package/src/export/events.ts
CHANGED
|
@@ -23,7 +23,6 @@ export default class ExportEvents extends PersonalizationAdapter<ExportConfig> {
|
|
|
23
23
|
this.eventsConfig = exportConfig.modules.events;
|
|
24
24
|
this.eventsFolderPath = pResolve(
|
|
25
25
|
sanitizePath(exportConfig.exportDir),
|
|
26
|
-
sanitizePath(exportConfig.branchName || ''),
|
|
27
26
|
sanitizePath(this.personalizeConfig.dirName),
|
|
28
27
|
sanitizePath(this.eventsConfig.dirName),
|
|
29
28
|
);
|
|
@@ -23,7 +23,6 @@ export default class ExportExperiences extends PersonalizationAdapter<ExportConf
|
|
|
23
23
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
24
24
|
this.experiencesFolderPath = path.resolve(
|
|
25
25
|
sanitizePath(exportConfig.exportDir),
|
|
26
|
-
sanitizePath(exportConfig.branchName || ''),
|
|
27
26
|
sanitizePath(this.personalizeConfig.dirName),
|
|
28
27
|
'experiences',
|
|
29
28
|
);
|
package/src/export/projects.ts
CHANGED
|
@@ -20,7 +20,6 @@ export default class ExportProjects extends PersonalizationAdapter<ExportConfig>
|
|
|
20
20
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
21
21
|
this.projectsFolderPath = pResolve(
|
|
22
22
|
sanitizePath(exportConfig.exportDir),
|
|
23
|
-
sanitizePath(exportConfig.branchName || ''),
|
|
24
23
|
sanitizePath(this.personalizeConfig.dirName),
|
|
25
24
|
'projects',
|
|
26
25
|
);
|
|
@@ -32,7 +32,6 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Exp
|
|
|
32
32
|
super(Object.assign(config, conf));
|
|
33
33
|
this.entriesDirPath = resolve(
|
|
34
34
|
sanitizePath(config.exportDir),
|
|
35
|
-
sanitizePath(config.branchName || ''),
|
|
36
35
|
sanitizePath(config.modules.entries.dirName),
|
|
37
36
|
);
|
|
38
37
|
if (this.config && this.config.context) {
|
package/src/import/audiences.ts
CHANGED
|
@@ -89,6 +89,12 @@ export default class Audiences extends PersonalizationAdapter<ImportConfig> {
|
|
|
89
89
|
}
|
|
90
90
|
log.debug(`Processing audience: ${name} (${uid})`, this.config.context);
|
|
91
91
|
|
|
92
|
+
// Skip Lytics audiences - they cannot be created via API (synced from Lytics)
|
|
93
|
+
if (audience.source?.toUpperCase() === 'LYTICS') {
|
|
94
|
+
log.debug(`Skipping Lytics audience: ${name} (${uid})`, this.config.context);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
92
98
|
try {
|
|
93
99
|
//check whether reference attributes exists or not
|
|
94
100
|
if (definition.rules?.length) {
|
|
@@ -24,6 +24,19 @@ describe('Variant Entries Export', () => {
|
|
|
24
24
|
config = exportConf as unknown as ExportConfig;
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
+
describe('path construction', () => {
|
|
28
|
+
test.it('should use exportDir as base path (no branch segment in path)', () => {
|
|
29
|
+
const configWithExportDir = {
|
|
30
|
+
...config,
|
|
31
|
+
exportDir: '/base/export',
|
|
32
|
+
branchName: 'dev',
|
|
33
|
+
} as ExportConfig;
|
|
34
|
+
const instance = new Export.VariantEntries(configWithExportDir);
|
|
35
|
+
expect(instance.entriesDirPath).to.not.include('dev');
|
|
36
|
+
expect(instance.entriesDirPath).to.include('entries');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
27
40
|
describe('exportVariantEntry method', () => {
|
|
28
41
|
test
|
|
29
42
|
.stub(VariantHttpClient.prototype, 'variantEntries', async () => {})
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { expect } from '@oclif/test';
|
|
2
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
3
|
+
import { fancy } from '@contentstack/cli-dev-dependencies';
|
|
4
|
+
|
|
5
|
+
import importConf from '../mock/import-config.json';
|
|
6
|
+
import { Import, ImportConfig } from '../../../src';
|
|
7
|
+
|
|
8
|
+
describe('Audiences Import', () => {
|
|
9
|
+
let config: ImportConfig;
|
|
10
|
+
let createAudienceCalls: Array<{ name: string }> = [];
|
|
11
|
+
|
|
12
|
+
const test = fancy.stdout({ print: process.env.PRINT === 'true' || false });
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
config = cloneDeep(importConf) as unknown as ImportConfig;
|
|
16
|
+
createAudienceCalls = [];
|
|
17
|
+
// Audiences uses modules.personalize and region - add them for tests
|
|
18
|
+
config.modules.personalize = {
|
|
19
|
+
...(config.modules as any).personalization,
|
|
20
|
+
dirName: 'personalize',
|
|
21
|
+
baseURL: {
|
|
22
|
+
na: 'https://personalization.na-api.contentstack.com',
|
|
23
|
+
eu: 'https://personalization.eu-api.contentstack.com',
|
|
24
|
+
},
|
|
25
|
+
} as any;
|
|
26
|
+
config.region = { name: 'eu' } as any;
|
|
27
|
+
config.context = config.context || {};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('import method - Lytics audience skip', () => {
|
|
31
|
+
test
|
|
32
|
+
.stub(Import.Audiences.prototype, 'init', async () => {})
|
|
33
|
+
.stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => {
|
|
34
|
+
createAudienceCalls.push({ name: payload.name });
|
|
35
|
+
return { uid: `new-${payload.name.replace(/\s/g, '-')}`, name: payload.name };
|
|
36
|
+
}) as any)
|
|
37
|
+
.it('should skip Lytics audiences and not call createAudience for them', async () => {
|
|
38
|
+
const audiencesInstance = new Import.Audiences(config);
|
|
39
|
+
await audiencesInstance.import();
|
|
40
|
+
|
|
41
|
+
const lyticsNames = createAudienceCalls.filter(
|
|
42
|
+
(c) => c.name === 'Lytics Audience' || c.name === 'Lytics Lowercase',
|
|
43
|
+
);
|
|
44
|
+
expect(lyticsNames.length).to.equal(0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test
|
|
48
|
+
.stub(Import.Audiences.prototype, 'init', async () => {})
|
|
49
|
+
.stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => {
|
|
50
|
+
createAudienceCalls.push({ name: payload.name });
|
|
51
|
+
return { uid: `new-${payload.name.replace(/\s/g, '-')}`, name: payload.name };
|
|
52
|
+
}) as any)
|
|
53
|
+
.it('should process audiences with undefined source', async () => {
|
|
54
|
+
const audiencesInstance = new Import.Audiences(config);
|
|
55
|
+
await audiencesInstance.import();
|
|
56
|
+
|
|
57
|
+
const noSourceCall = createAudienceCalls.find((c) => c.name === 'No Source Audience');
|
|
58
|
+
expect(noSourceCall).to.not.be.undefined;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test
|
|
62
|
+
.stub(Import.Audiences.prototype, 'init', async () => {})
|
|
63
|
+
.stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => {
|
|
64
|
+
createAudienceCalls.push({ name: payload.name });
|
|
65
|
+
return { uid: `new-${payload.name.replace(/\s/g, '-')}`, name: payload.name };
|
|
66
|
+
}) as any)
|
|
67
|
+
.it('should skip audience with source "lytics" (lowercase)', async () => {
|
|
68
|
+
const audiencesInstance = new Import.Audiences(config);
|
|
69
|
+
await audiencesInstance.import();
|
|
70
|
+
|
|
71
|
+
const lyticsLowercaseCall = createAudienceCalls.find((c) => c.name === 'Lytics Lowercase');
|
|
72
|
+
expect(lyticsLowercaseCall).to.be.undefined;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test
|
|
76
|
+
.stub(Import.Audiences.prototype, 'init', async () => {})
|
|
77
|
+
.stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => {
|
|
78
|
+
createAudienceCalls.push({ name: payload.name });
|
|
79
|
+
return { uid: `new-uid-${payload.name}`, name: payload.name };
|
|
80
|
+
}) as any)
|
|
81
|
+
.it('should call createAudience only for non-Lytics audiences', async () => {
|
|
82
|
+
const audiencesInstance = new Import.Audiences(config);
|
|
83
|
+
await audiencesInstance.import();
|
|
84
|
+
|
|
85
|
+
// 4 audiences in mock: 2 Lytics (skip), 2 non-Lytics (Contentstack Test, No Source)
|
|
86
|
+
expect(createAudienceCalls.length).to.equal(2);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test
|
|
90
|
+
.stub(Import.Audiences.prototype, 'init', async () => {})
|
|
91
|
+
.stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => {
|
|
92
|
+
createAudienceCalls.push({ name: payload.name });
|
|
93
|
+
return { uid: 'new-contentstack-uid', name: payload.name };
|
|
94
|
+
}) as any)
|
|
95
|
+
.it('should not add Lytics audiences to audiencesUidMapper', async () => {
|
|
96
|
+
const audiencesInstance = new Import.Audiences(config);
|
|
97
|
+
await audiencesInstance.import();
|
|
98
|
+
|
|
99
|
+
const mapper = (audiencesInstance as any).audiencesUidMapper;
|
|
100
|
+
expect(mapper['lytics-audience-001']).to.be.undefined;
|
|
101
|
+
expect(mapper['lytics-lowercase-001']).to.be.undefined;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test
|
|
105
|
+
.stub(Import.Audiences.prototype, 'init', async () => {})
|
|
106
|
+
.stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => {
|
|
107
|
+
createAudienceCalls.push({ name: payload.name });
|
|
108
|
+
return { uid: 'new-contentstack-uid', name: payload.name };
|
|
109
|
+
}) as any)
|
|
110
|
+
.it('should add Contentstack audiences to audiencesUidMapper', async () => {
|
|
111
|
+
const audiencesInstance = new Import.Audiences(config);
|
|
112
|
+
await audiencesInstance.import();
|
|
113
|
+
|
|
114
|
+
const mapper = (audiencesInstance as any).audiencesUidMapper;
|
|
115
|
+
expect(mapper['contentstack-audience-001']).to.equal('new-contentstack-uid');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"contentstack-audience-001":"new-contentstack-uid","no-source-audience-001":"new-contentstack-uid"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"uid": "contentstack-audience-001",
|
|
4
|
+
"name": "Contentstack Test Audience",
|
|
5
|
+
"description": "Audience with rules",
|
|
6
|
+
"definition": {
|
|
7
|
+
"__type": "RuleCombination",
|
|
8
|
+
"combinationType": "AND",
|
|
9
|
+
"rules": [
|
|
10
|
+
{
|
|
11
|
+
"__type": "Rule",
|
|
12
|
+
"attribute": { "__type": "PresetAttributeReference", "ref": "DEVICE_TYPE" },
|
|
13
|
+
"attributeMatchOptions": { "__type": "StringMatchOptions", "value": "MOBILE" },
|
|
14
|
+
"attributeMatchCondition": "STRING_EQUALS",
|
|
15
|
+
"invertCondition": false
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"uid": "lytics-audience-001",
|
|
22
|
+
"name": "Lytics Audience",
|
|
23
|
+
"description": "From Lytics",
|
|
24
|
+
"slug": "lytics_audience",
|
|
25
|
+
"source": "LYTICS"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"uid": "lytics-lowercase-001",
|
|
29
|
+
"name": "Lytics Lowercase",
|
|
30
|
+
"description": "source is lowercase",
|
|
31
|
+
"slug": "lytics_lowercase",
|
|
32
|
+
"source": "lytics"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"uid": "no-source-audience-001",
|
|
36
|
+
"name": "No Source Audience",
|
|
37
|
+
"description": "Audience without source field",
|
|
38
|
+
"definition": {
|
|
39
|
+
"__type": "RuleCombination",
|
|
40
|
+
"combinationType": "AND",
|
|
41
|
+
"rules": []
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
]
|