@contrail/flexplm 1.7.1-alpha.e5225c7 → 1.7.2-alpha.c5613fa
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.
|
@@ -183,9 +183,12 @@ class BaseEntityProcessor {
|
|
|
183
183
|
return undefined;
|
|
184
184
|
}
|
|
185
185
|
const entityReference = identityEntity.entityReference;
|
|
186
|
+
if (typeof entityReference !== 'string' || !entityReference.includes(':')) {
|
|
187
|
+
throw new Error(`Invalid identity entityReference: ${String(entityReference)}`);
|
|
188
|
+
}
|
|
186
189
|
const firstColonIndex = entityReference.indexOf(':');
|
|
187
|
-
if (firstColonIndex ===
|
|
188
|
-
throw new Error('Invalid entityReference: ' + entityReference);
|
|
190
|
+
if (firstColonIndex === 0 || firstColonIndex === entityReference.length - 1) {
|
|
191
|
+
throw new Error('Invalid identity entityReference: ' + entityReference);
|
|
189
192
|
}
|
|
190
193
|
const entityName = entityReference.slice(0, firstColonIndex);
|
|
191
194
|
const id = entityReference.slice(firstColonIndex + 1);
|
|
@@ -623,7 +623,25 @@ describe('BaseEntityProcessor', () => {
|
|
|
623
623
|
poolKey: 'item',
|
|
624
624
|
propertyName: 'itemNumber',
|
|
625
625
|
propertyValue: '12345'
|
|
626
|
-
})).rejects.toThrow('Invalid entityReference: item1');
|
|
626
|
+
})).rejects.toThrow('Invalid identity entityReference: item1');
|
|
627
|
+
expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
|
|
628
|
+
});
|
|
629
|
+
it('should throw error when entityReference is not a string', async () => {
|
|
630
|
+
mockEntitiesGet.mockResolvedValue([{ entityReference: 12345 }]);
|
|
631
|
+
await expect(btep.getEntityUsingIdentityService({
|
|
632
|
+
poolKey: 'item',
|
|
633
|
+
propertyName: 'itemNumber',
|
|
634
|
+
propertyValue: '12345'
|
|
635
|
+
})).rejects.toThrow('Invalid identity entityReference: 12345');
|
|
636
|
+
expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
|
|
637
|
+
});
|
|
638
|
+
it('should throw error when entityReference is undefined', async () => {
|
|
639
|
+
mockEntitiesGet.mockResolvedValue([{}]);
|
|
640
|
+
await expect(btep.getEntityUsingIdentityService({
|
|
641
|
+
poolKey: 'item',
|
|
642
|
+
propertyName: 'itemNumber',
|
|
643
|
+
propertyValue: '12345'
|
|
644
|
+
})).rejects.toThrow('Invalid identity entityReference: undefined');
|
|
627
645
|
expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
|
|
628
646
|
});
|
|
629
647
|
it('should throw error when entityReference starts with a colon (missing entityName)', async () => {
|
|
@@ -632,7 +650,7 @@ describe('BaseEntityProcessor', () => {
|
|
|
632
650
|
poolKey: 'item',
|
|
633
651
|
propertyName: 'itemNumber',
|
|
634
652
|
propertyValue: '12345'
|
|
635
|
-
})).rejects.toThrow('Invalid entityReference: :1');
|
|
653
|
+
})).rejects.toThrow('Invalid identity entityReference: :1');
|
|
636
654
|
expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
|
|
637
655
|
});
|
|
638
656
|
it('should throw error when entityReference ends with a colon (missing id)', async () => {
|
|
@@ -641,7 +659,7 @@ describe('BaseEntityProcessor', () => {
|
|
|
641
659
|
poolKey: 'item',
|
|
642
660
|
propertyName: 'itemNumber',
|
|
643
661
|
propertyValue: '12345'
|
|
644
|
-
})).rejects.toThrow('Invalid entityReference: item:');
|
|
662
|
+
})).rejects.toThrow('Invalid identity entityReference: item:');
|
|
645
663
|
expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
|
|
646
664
|
});
|
|
647
665
|
});
|
|
@@ -9,6 +9,7 @@ export declare class ThumbnailUtil {
|
|
|
9
9
|
/** The max_thumbnail_size is for limiting the size of the thumbnail being sent to FlexPLM. It is used when checking the size of the auto generated thumbnails (smallViewable, tinyViewable, etc.). */
|
|
10
10
|
private max_thumbnail_size;
|
|
11
11
|
private entities;
|
|
12
|
+
static THUMBNAIL: string;
|
|
12
13
|
static NEW_THUMBNAIL_ID: string;
|
|
13
14
|
static EXISTING_THUMBNAIL_ID: string;
|
|
14
15
|
static REMOVE_THUMBNAIL: string;
|
|
@@ -136,9 +136,10 @@ class ThumbnailUtil {
|
|
|
136
136
|
const eventData = event.data || {};
|
|
137
137
|
const newThumbnailId = eventData[ThumbnailUtil.NEW_THUMBNAIL_ID];
|
|
138
138
|
const existingThumbnailId = eventData[ThumbnailUtil.EXISTING_THUMBNAIL_ID];
|
|
139
|
-
const
|
|
139
|
+
const iteratedThumbnailId = eventData[ThumbnailUtil.THUMBNAIL];
|
|
140
|
+
const thumbnailUrl = iteratedThumbnailId || newThumbnailId || existingThumbnailId;
|
|
140
141
|
// Case 1: REMOVE_THUMBNAIL
|
|
141
|
-
if (
|
|
142
|
+
if (thumbnailUrl === ThumbnailUtil.REMOVE_THUMBNAIL) {
|
|
142
143
|
if (primaryViewableId) {
|
|
143
144
|
await this.entities.delete({ entityName: 'content', id: primaryViewableId });
|
|
144
145
|
}
|
|
@@ -236,6 +237,8 @@ class ThumbnailUtil {
|
|
|
236
237
|
}
|
|
237
238
|
}
|
|
238
239
|
exports.ThumbnailUtil = ThumbnailUtil;
|
|
240
|
+
// Adding Thumbnail property
|
|
241
|
+
ThumbnailUtil.THUMBNAIL = 'THUMBNAIL';
|
|
239
242
|
ThumbnailUtil.NEW_THUMBNAIL_ID = 'NEW_THUMBNAIL_ID';
|
|
240
243
|
ThumbnailUtil.EXISTING_THUMBNAIL_ID = 'EXISTING_THUMBNAIL_ID';
|
|
241
244
|
ThumbnailUtil.REMOVE_THUMBNAIL = 'REMOVE_THUMBNAIL';
|
|
@@ -437,4 +437,94 @@ describe('ThumbnailUtil Tests', () => {
|
|
|
437
437
|
expect(mockEntitiesDelete).not.toHaveBeenCalled();
|
|
438
438
|
});
|
|
439
439
|
});
|
|
440
|
+
describe('ThumbnailUtil - iteratedThumbnailId (THUMBNAIL key)', () => {
|
|
441
|
+
const config = {};
|
|
442
|
+
let tu;
|
|
443
|
+
beforeEach(() => {
|
|
444
|
+
jest.clearAllMocks();
|
|
445
|
+
tu = new thumbnail_util_1.ThumbnailUtil(config);
|
|
446
|
+
mockEntitiesGet.mockImplementation((opts) => {
|
|
447
|
+
if (opts.entityName === 'content-custom-size')
|
|
448
|
+
return Promise.resolve([]);
|
|
449
|
+
return Promise.resolve({});
|
|
450
|
+
});
|
|
451
|
+
mockEntitiesUpdate.mockImplementation((opts) => Promise.resolve({ id: opts.id }));
|
|
452
|
+
mockEntitiesDelete.mockImplementation((opts) => Promise.resolve({ id: opts.id }));
|
|
453
|
+
});
|
|
454
|
+
it('does not break when THUMBNAIL value is not available in the event', async () => {
|
|
455
|
+
// No THUMBNAIL key (and no other thumbnail keys) -> iteratedThumbnailId is undefined
|
|
456
|
+
const event = { data: {} };
|
|
457
|
+
let result;
|
|
458
|
+
await expect((async () => {
|
|
459
|
+
result = await tu.syncThumbnailToVibeIQ({ entityId: 'entity1', event, entityName: 'color' });
|
|
460
|
+
})()).resolves.not.toThrow();
|
|
461
|
+
// Falls through to the "no thumbnail URL" early return
|
|
462
|
+
expect(result).toBeUndefined();
|
|
463
|
+
expect(mockContentCreate).not.toHaveBeenCalled();
|
|
464
|
+
expect(mockEntitiesUpdate).not.toHaveBeenCalled();
|
|
465
|
+
expect(mockEntitiesDelete).not.toHaveBeenCalled();
|
|
466
|
+
});
|
|
467
|
+
it('does not break when THUMBNAIL key is present but explicitly empty/falsy', async () => {
|
|
468
|
+
// THUMBNAIL present but falsy -> iteratedThumbnailId is falsy, no crash
|
|
469
|
+
const event = { data: { [thumbnail_util_1.ThumbnailUtil.THUMBNAIL]: '' } };
|
|
470
|
+
let result;
|
|
471
|
+
await expect((async () => {
|
|
472
|
+
result = await tu.syncThumbnailToVibeIQ({ entityId: 'entity1', event, entityName: 'item' });
|
|
473
|
+
})()).resolves.not.toThrow();
|
|
474
|
+
expect(result).toBeUndefined();
|
|
475
|
+
expect(mockContentCreate).not.toHaveBeenCalled();
|
|
476
|
+
expect(mockEntitiesUpdate).not.toHaveBeenCalled();
|
|
477
|
+
expect(mockEntitiesDelete).not.toHaveBeenCalled();
|
|
478
|
+
});
|
|
479
|
+
it('syncs using iteratedThumbnailId when a THUMBNAIL value is available (no existing primaryViewable)', async () => {
|
|
480
|
+
const mockResponse = {
|
|
481
|
+
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(8)),
|
|
482
|
+
headers: { get: jest.fn().mockReturnValue('image/png') },
|
|
483
|
+
};
|
|
484
|
+
mockGetRequest.mockResolvedValue(mockResponse);
|
|
485
|
+
const createdContent = {
|
|
486
|
+
id: 'iteratedContent1',
|
|
487
|
+
contentType: 'image/png',
|
|
488
|
+
fileName: 'iterated.png',
|
|
489
|
+
primaryFileUrl: 'https://files/primary.png',
|
|
490
|
+
largeViewableUrl: 'https://files/large.png',
|
|
491
|
+
mediumLargeViewableUrl: null,
|
|
492
|
+
mediumViewableUrl: null,
|
|
493
|
+
smallViewableUrl: null,
|
|
494
|
+
tinyViewableUrl: null,
|
|
495
|
+
};
|
|
496
|
+
mockContentCreate.mockResolvedValue(createdContent);
|
|
497
|
+
const thumbnailUrl = '/rest/thumbnail/iterated.png';
|
|
498
|
+
const event = { data: { [thumbnail_util_1.ThumbnailUtil.THUMBNAIL]: thumbnailUrl } };
|
|
499
|
+
await tu.syncThumbnailToVibeIQ({ entityId: 'entity1', event, entityName: 'color' });
|
|
500
|
+
// Uses the THUMBNAIL value to fetch + create the content
|
|
501
|
+
expect(mockGetRequest).toHaveBeenCalledWith({
|
|
502
|
+
urlPath: thumbnailUrl,
|
|
503
|
+
includeUrlContext: false,
|
|
504
|
+
returnFullResponse: true,
|
|
505
|
+
});
|
|
506
|
+
expect(mockContentCreate).toHaveBeenCalledWith(expect.objectContaining({
|
|
507
|
+
fileName: 'iterated.png',
|
|
508
|
+
contentType: 'image/png',
|
|
509
|
+
contentHolderReference: 'color:entity1',
|
|
510
|
+
}));
|
|
511
|
+
// Stamps the content with the THUMBNAIL url
|
|
512
|
+
expect(mockEntitiesUpdate).toHaveBeenCalledWith(expect.objectContaining({
|
|
513
|
+
entityName: 'content',
|
|
514
|
+
id: 'iteratedContent1',
|
|
515
|
+
object: { flexplmThumbnailUrl: thumbnailUrl },
|
|
516
|
+
}));
|
|
517
|
+
// Updates the main entity
|
|
518
|
+
expect(mockEntitiesUpdate).toHaveBeenCalledWith(expect.objectContaining({ entityName: 'color', id: 'entity1' }));
|
|
519
|
+
});
|
|
520
|
+
it('REMOVE_THUMBNAIL via the THUMBNAIL key deletes content and clears the entity', async () => {
|
|
521
|
+
const event = { data: { [thumbnail_util_1.ThumbnailUtil.THUMBNAIL]: thumbnail_util_1.ThumbnailUtil.REMOVE_THUMBNAIL } };
|
|
522
|
+
await tu.syncThumbnailToVibeIQ({ entityId: 'entity1', primaryViewableId: 'pv1', event, entityName: 'color' });
|
|
523
|
+
// Resolves REMOVE_THUMBNAIL from the THUMBNAIL key and removes the existing content
|
|
524
|
+
expect(mockEntitiesDelete).toHaveBeenCalledWith({ entityName: 'content', id: 'pv1' });
|
|
525
|
+
expect(mockEntitiesUpdate).toHaveBeenCalledWith(expect.objectContaining({ entityName: 'color', id: 'entity1' }));
|
|
526
|
+
// Does not create replacement content
|
|
527
|
+
expect(mockContentCreate).not.toHaveBeenCalled();
|
|
528
|
+
});
|
|
529
|
+
});
|
|
440
530
|
});
|