Skip to content

Commit f082c4a

Browse files
feat: exposing structured metadata rules api
1 parent 966b0f5 commit f082c4a

File tree

4 files changed

+214
-10
lines changed

4 files changed

+214
-10
lines changed

lib/api.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,23 @@ exports.reorder_metadata_fields = function reorder_metadata_fields(order_by, dir
616616
const params = { order_by, direction };
617617
return call_api("put", ["metadata_fields", "order"], params, callback, options);
618618
};
619+
620+
exports.list_metadata_rules = function list_metadata_rules(callback, options = {}) {
621+
return call_api('get', ['metadata_rules'], {}, callback, options);
622+
};
623+
624+
exports.add_metadata_rule = function add_metadata_rule(metadata_rule, callback, options = {}) {
625+
options.content_type = 'json';
626+
const params = pickOnlyExistingValues(metadata_rule, 'metadata_field_id', 'condition', 'result', 'name');
627+
return call_api('post', ['metadata_rules'], params, callback, options);
628+
};
629+
630+
exports.update_metadata_rule = function update_metadata_rule(field_external_id, updated_metadata_rule, callback, options = {}) {
631+
options.content_type = 'json';
632+
const params = pickOnlyExistingValues(updated_metadata_rule, 'metadata_field_id', 'condition', 'result', 'name', 'state');
633+
return call_api('put', ['metadata_rules', field_external_id], params, callback, options);
634+
};
635+
636+
exports.delete_metadata_rule = function delete_metadata_rule(field_external_id, callback, options = {}) {
637+
return call_api('delete', ['metadata_rules', field_external_id], {}, callback, options);
638+
};

lib/v2/api.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,9 @@ v1_adapters(exports, api, {
6464
delete_datasource_entries: 2,
6565
restore_metadata_field_datasource: 2,
6666
order_metadata_field_datasource: 3,
67-
reorder_metadata_fields: 2
67+
reorder_metadata_fields: 2,
68+
list_metadata_rules: 1,
69+
add_metadata_rule: 1,
70+
delete_metadata_rule: 1,
71+
update_metadata_rule: 2
6872
});

test/integration/api/admin/structured_metadata_spec.js

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const assert = require('assert');
12
const Q = require('q');
23
const sinon = require('sinon');
34
const cloudinary = require("../../../../cloudinary");
@@ -96,14 +97,16 @@ describe("structured metadata api", function () {
9697
// Create the metadata fields required for the tests
9798
return Q.allSettled(
9899
metadata_fields_to_create.map(field => createMetadataFieldForTest(field))
99-
).finally(function () {});
100+
).finally(function () {
101+
});
100102
});
101103

102104
after(function () {
103105
// Delete all metadata fields created during testing
104106
return Q.allSettled(
105107
metadata_fields_external_ids.map(field => api.delete_metadata_field(field))
106-
).finally(function () {});
108+
).finally(function () {
109+
});
107110
});
108111

109112
describe("list_metadata_fields", function () {
@@ -123,7 +126,7 @@ describe("structured metadata api", function () {
123126
it("should return metadata field by external id", function () {
124127
return api.metadata_field_by_field_id(EXTERNAL_ID_GENERAL)
125128
.then((result) => {
126-
expect([result, { label: EXTERNAL_ID_GENERAL }]).to.beAMetadataField();
129+
expect([result, {label: EXTERNAL_ID_GENERAL}]).to.beAMetadataField();
127130
});
128131
});
129132
});
@@ -174,7 +177,10 @@ describe("structured metadata api", function () {
174177
expect(result).to.beAMetadataField();
175178
return api.metadata_field_by_field_id(EXTERNAL_ID_DATE);
176179
}).then((result) => {
177-
expect([result, { ...metadata, mandatory: false }]).to.beAMetadataField();
180+
expect([result, {
181+
...metadata,
182+
mandatory: false
183+
}]).to.beAMetadataField();
178184
});
179185
});
180186
it("should create enum metadata field", function () {
@@ -195,7 +201,7 @@ describe("structured metadata api", function () {
195201
sinon.assert.calledWith(writeSpy, sinon.match(helper.apiJsonParamMatcher('external_id', EXTERNAL_ID_ENUM)));
196202
sinon.assert.calledWith(writeSpy, sinon.match(helper.apiJsonParamMatcher('type', 'enum')));
197203
sinon.assert.calledWith(writeSpy, sinon.match(helper.apiJsonParamMatcher('label', EXTERNAL_ID_ENUM)));
198-
sinon.assert.calledWith(writeSpy, sinon.match(helper.apiJsonParamMatcher('datasource', { values: datasource_single })));
204+
sinon.assert.calledWith(writeSpy, sinon.match(helper.apiJsonParamMatcher('datasource', {values: datasource_single})));
199205
});
200206
});
201207
it("should create set metadata field", function () {
@@ -251,7 +257,7 @@ describe("structured metadata api", function () {
251257

252258
describe("update_metadata_field_datasource", function () {
253259
it("should update metadata field datasource by external id", function () {
254-
return api.update_metadata_field_datasource(EXTERNAL_ID_ENUM_2, { values: datasource_single })
260+
return api.update_metadata_field_datasource(EXTERNAL_ID_ENUM_2, {values: datasource_single})
255261
.then(() => api.metadata_field_by_field_id(EXTERNAL_ID_ENUM_2))
256262
.then((result) => {
257263
expect(result.datasource).to.beADatasource();
@@ -283,7 +289,7 @@ describe("structured metadata api", function () {
283289
expect(result.message).to.eql("ok");
284290
return api.add_metadata_field(metadata);
285291
})
286-
.catch(({ error }) => {
292+
.catch(({error}) => {
287293
expect(error).not.to.be(void 0);
288294
expect(error.http_code).to.eql(400);
289295
expect(error.message).to.contain(`external id ${EXTERNAL_ID_DELETE_2} already exists`);
@@ -393,7 +399,7 @@ describe("structured metadata api", function () {
393399
.then((result) => {
394400
expect(result).to.beAMetadataField();
395401
return api.metadata_field_by_field_id(EXTERNAL_ID_INT_VALIDATION_2);
396-
}).catch(({ error }) => {
402+
}).catch(({error}) => {
397403
expect(error).not.to.be(void 0);
398404
expect(error.http_code).to.eql(400);
399405
expect(error.message).to.contain(`default_value is invalid`);
@@ -509,4 +515,86 @@ describe("structured metadata api", function () {
509515
})
510516
});
511517
});
518+
519+
describe('rules', () => {
520+
it('should allow listing metadata rules', () => {
521+
const expectedPath = '/metadata_rules';
522+
return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) {
523+
api.list_metadata_rules();
524+
sinon.assert.calledWith(requestSpy, sinon.match({
525+
pathname: sinon.match(new RegExp(expectedPath)),
526+
method: sinon.match('GET')
527+
}));
528+
});
529+
});
530+
531+
it('should allow adding new metadata rules', () => {
532+
const expectedPath = '/metadata_rules';
533+
return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) {
534+
const newMetadataRule = {
535+
metadata_field_id: 'field_id',
536+
name: 'rule_name',
537+
condition: {},
538+
result: {}
539+
};
540+
api.add_metadata_rule(newMetadataRule);
541+
542+
sinon.assert.calledWith(requestSpy, sinon.match({
543+
pathname: sinon.match(new RegExp(expectedPath)),
544+
method: sinon.match('POST')
545+
}));
546+
547+
sinon.assert.calledOnce(writeSpy);
548+
549+
const firstCallArgs = JSON.parse(writeSpy.firstCall.args[0]);
550+
assert.deepStrictEqual(firstCallArgs, {
551+
metadata_field_id: 'field_id',
552+
name: 'rule_name',
553+
condition: {},
554+
result: {}
555+
});
556+
});
557+
});
558+
559+
it('should allow editing metadata rules', () => {
560+
const expectedPath = '/metadata_rules/some-metadata-rule-id';
561+
return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) {
562+
const ruleUpdate = {
563+
metadata_field_id: 'new_field_id',
564+
name: 'new_rule_name',
565+
condition: {},
566+
result: {},
567+
state: 'inactive'
568+
};
569+
api.update_metadata_rule('some-metadata-rule-id', ruleUpdate);
570+
571+
sinon.assert.calledWith(requestSpy, sinon.match({
572+
pathname: sinon.match(new RegExp(expectedPath)),
573+
method: sinon.match('PUT')
574+
}));
575+
576+
sinon.assert.calledOnce(writeSpy);
577+
578+
const firstCallArgs = JSON.parse(writeSpy.firstCall.args[0]);
579+
assert.deepStrictEqual(firstCallArgs, {
580+
metadata_field_id: 'new_field_id',
581+
name: 'new_rule_name',
582+
condition: {},
583+
result: {},
584+
state: 'inactive'
585+
});
586+
});
587+
});
588+
589+
it('should allow removing existing metadata rules', () => {
590+
const expectedPath = '/metadata_rules/some-metadata-rule-id';
591+
return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) {
592+
api.delete_metadata_rule('some-metadata-rule-id');
593+
sinon.assert.calledWith(requestSpy, sinon.match({
594+
pathname: sinon.match(new RegExp(expectedPath)),
595+
method: sinon.match('DELETE')
596+
}));
597+
});
598+
});
599+
});
512600
});

types/index.d.ts

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Transform } from 'stream';
1+
import {Transform} from 'stream';
22

33

44
declare module 'cloudinary' {
@@ -651,6 +651,80 @@ declare module 'cloudinary' {
651651
values: Array<DatasourceEntry>
652652
}
653653

654+
export type MetadataRuleCondition =
655+
MetadataRulePopulatedCondition
656+
| MetadataRuleEqualsCondition
657+
| MetadataRuleIncludesCondition
658+
| MetadataRuleOrCondition
659+
| MetadataRuleAndCondition;
660+
661+
export interface MetadataRulePopulatedCondition {
662+
metadata_field_id: string;
663+
populated: boolean;
664+
}
665+
666+
export interface MetadataRuleEqualsCondition {
667+
metadata_field_id: string;
668+
equals: string;
669+
}
670+
671+
export interface MetadataRuleIncludesCondition {
672+
metadata_field_id: string;
673+
includes: Array<string>;
674+
}
675+
676+
export interface MetadataRuleOrCondition {
677+
and: Array<MetadataRuleCondition>
678+
}
679+
680+
export interface MetadataRuleAndCondition {
681+
or: Array<MetadataRuleCondition>
682+
}
683+
684+
export type MetadataRuleResult =
685+
MetadataRuleResultEnable
686+
| MetadataRuleResultEnableWithActivate
687+
| MetadataRuleResultEnableWithApply;
688+
689+
interface MetadataRuleResultCommon {
690+
set_mandatory?: boolean;
691+
}
692+
693+
export interface MetadataRuleResultEnable extends MetadataRuleResultCommon {
694+
enable: boolean;
695+
}
696+
697+
export interface MetadataRuleResultEnableWithActivate extends MetadataRuleResultCommon {
698+
enable?: boolean;
699+
activate_values: "all" | {
700+
external_ids: string | Array<string> | null;
701+
mode?: "override" | "append";
702+
}
703+
}
704+
705+
export interface MetadataRuleResultEnableWithApply extends MetadataRuleResultCommon {
706+
enable?: boolean;
707+
apply_value: {
708+
value: string | Array<string>;
709+
mode?: "default" | "append";
710+
}
711+
}
712+
713+
export interface MetadataRule {
714+
metadata_field_id: string;
715+
name: string | null;
716+
condition: MetadataRuleCondition;
717+
result: MetadataRuleResult | Array<MetadataRuleResult>;
718+
state?: string;
719+
}
720+
721+
export interface MetadataRuleResponse extends MetadataRule {
722+
condition_signature: string;
723+
external_id: string;
724+
}
725+
726+
export type MetadataRulesListResponse = Array<MetadataRuleResponse>;
727+
654728
export interface ResourceApiResponse {
655729
resources: [
656730
{
@@ -984,6 +1058,24 @@ declare module 'cloudinary' {
9841058
function restore_metadata_field_datasource(field_external_id: string, entries_external_id: string[], options?: AdminApiOptions, callback?: ResponseCallback): Promise<DatasourceChange>;
9851059

9861060
function restore_metadata_field_datasource(field_external_id: string, entries_external_id: string[], callback?: ResponseCallback): Promise<DatasourceChange>;
1061+
1062+
/****************************** Structured Metadata Rules API V2 Methods *************************************/
1063+
function add_metadata_field(rule: MetadataRule, options?: AdminApiOptions, callback?: ResponseCallback): Promise<MetadataRuleResponse>;
1064+
1065+
function add_metadata_field(rule: MetadataRule, callback?: ResponseCallback): Promise<MetadataRuleResponse>;
1066+
1067+
function list_metadata_fields(callback?: ResponseCallback, options?: AdminApiOptions): Promise<MetadataRulesListResponse>;
1068+
1069+
function list_metadata_fields(options?: AdminApiOptions): Promise<MetadataRulesListResponse>;
1070+
1071+
function update_metadata_field(external_id: string, rule: MetadataRule, options?: AdminApiOptions, callback?: ResponseCallback): Promise<MetadataRuleResponse>;
1072+
1073+
function update_metadata_field(external_id: string, rule: MetadataRule, callback?: ResponseCallback): Promise<MetadataRuleResponse>;
1074+
1075+
function delete_metadata_field(external_id: string, options?: AdminApiOptions, callback?: ResponseCallback): Promise<DeleteApiResponse>;
1076+
1077+
function delete_metadata_field(external_id: string, callback?: ResponseCallback): Promise<DeleteApiResponse>;
1078+
9871079
}
9881080

9891081
/****************************** Upload API V2 Methods *************************************/

0 commit comments

Comments
 (0)