Skip to content

Commit 0881199

Browse files
Merge pull request #649 from cloudinary/custom-regions-gravity
Custom regions gravity
2 parents 99827bd + 2806953 commit 0881199

File tree

5 files changed

+170
-0
lines changed

5 files changed

+170
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const toArray = require('../parsing/toArray');
2+
3+
const encodeCoordinates = (coords) => {
4+
if (coords.length < 2) {
5+
throw new TypeError('Regions should contain at least two arrays with two coordinates');
6+
}
7+
8+
return coords.map(e => toArray(e).join(','))
9+
}
10+
11+
function encodeRegions(regions) {
12+
if (!regions) {
13+
throw new TypeError('Cannot encode non existing regions');
14+
}
15+
16+
return Object.keys(regions).map(regionName => {
17+
return `{${regionName}}${encodeCoordinates(regions[regionName])}`;
18+
}).join('|');
19+
}
20+
21+
module.exports = encodeRegions;

lib/utils/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const consumeOption = require('./parsing/consumeOption');
3535
const toArray = require('./parsing/toArray');
3636
let {base64EncodeURL} = require('./encoding/base64EncodeURL');
3737
const encodeDoubleArray = require('./encoding/encodeDoubleArray');
38+
const encodeRegions = require('./encoding/encodeRegions');
3839

3940
const config = require("../config");
4041
const generate_token = require("../auth_token");
@@ -720,6 +721,9 @@ function updateable_resource_params(options, params = {}) {
720721
if (options.visual_search != null) {
721722
params.visual_search = options.visual_search;
722723
}
724+
if (options.regions != null) {
725+
params.regions = encodeRegions(options.regions);
726+
}
723727
return params;
724728
}
725729

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const assert = require('assert');
2+
const sinon = require('sinon');
3+
4+
const cloudinary = require('../../../../lib/cloudinary');
5+
const createTestConfig = require('../../../testUtils/createTestConfig');
6+
const helper = require('../../../spechelper');
7+
const ClientRequest = require('_http_client').ClientRequest;
8+
9+
describe('Uploader', () => {
10+
let spy;
11+
let xhr;
12+
13+
before(() => {
14+
xhr = sinon.useFakeXMLHttpRequest();
15+
spy = sinon.spy(ClientRequest.prototype, 'write');
16+
});
17+
18+
after(() => {
19+
spy.restore();
20+
xhr.restore();
21+
});
22+
23+
describe('upload', () => {
24+
it('should send a request with encoded custom region gravity that represents a box', () => {
25+
const boxRegionGravityEncoded = '{box_1}1,2,3,4|{box_2}5,6,7,8';
26+
27+
cloudinary.v2.uploader.upload('irrelevant', {
28+
regions: {
29+
'box_1': [[1, 2], [3, 4]],
30+
'box_2': [[5, 6], [7, 8]]
31+
}
32+
});
33+
34+
sinon.assert.calledWith(spy, sinon.match(helper.uploadParamMatcher('regions', boxRegionGravityEncoded)));
35+
});
36+
37+
it('should send a request with encoded custom region gravity that represents a custom shape', () => {
38+
const customRegionGravityEncoded = '{custom_1}1,2,3,4,5,6,7,8|{custom_2}10,11,12,13,14,15';
39+
40+
cloudinary.v2.uploader.upload('irrelevant', {
41+
regions: {
42+
'custom_1': [[1, 2], [3, 4], [5, 6], [7, 8]],
43+
'custom_2': [[10, 11], [12, 13], [14, 15]]
44+
}
45+
});
46+
47+
sinon.assert.calledWith(spy, sinon.match(helper.uploadParamMatcher('regions', customRegionGravityEncoded)));
48+
});
49+
50+
it('should throw an error when insufficient custom region gravity details', () => {
51+
assert.throws(() => {
52+
cloudinary.v2.uploader.upload('irrelevant', {
53+
regions: {
54+
'error_1': [[1, 2]]
55+
}
56+
})
57+
}, {
58+
name: 'TypeError',
59+
message: 'Regions should contain at least two arrays with two coordinates'
60+
});
61+
});
62+
});
63+
64+
describe('explicit', () => {
65+
it('should send a request with encoded custom region gravity that represents a box', () => {
66+
const boxRegionGravityEncoded = '{box_1}1,2,3,4|{box_2}5,6,7,8';
67+
68+
cloudinary.v2.uploader.explicit('irrelevant', {
69+
regions: {
70+
'box_1': [[1, 2], [3, 4]],
71+
'box_2': [[5, 6], [7, 8]]
72+
}
73+
});
74+
75+
sinon.assert.calledWith(spy, sinon.match(helper.uploadParamMatcher('regions', boxRegionGravityEncoded)));
76+
});
77+
78+
it('should send a request with encoded custom region gravity that represents a custom shape', () => {
79+
const customRegionGravityEncoded = '{custom_1}1,2,3,4,5,6,7,8|{custom_2}10,11,12,13,14,15';
80+
81+
cloudinary.v2.uploader.explicit('irrelevant', {
82+
regions: {
83+
'custom_1': [[1, 2], [3, 4], [5, 6], [7, 8]],
84+
'custom_2': [[10, 11], [12, 13], [14, 15]]
85+
}
86+
});
87+
88+
sinon.assert.calledWith(spy, sinon.match(helper.uploadParamMatcher('regions', customRegionGravityEncoded)));
89+
});
90+
91+
it('should throw an error when insufficient custom region gravity details', () => {
92+
assert.throws(() => {
93+
cloudinary.v2.uploader.upload('irrelevant', {
94+
regions: {
95+
'error_1': [[1, 2]]
96+
}
97+
})
98+
}, {
99+
name: 'TypeError',
100+
message: 'Regions should contain at least two arrays with two coordinates'
101+
});
102+
});
103+
});
104+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const assert = require('assert');
2+
3+
const encodeRegions = require('../../../lib/utils/encoding/encodeRegions');
4+
5+
describe('encodeRegions', () => {
6+
it('should properly encode an object with single region', () => {
7+
const regions = {
8+
region1: [[1, 2], [3, 4]]
9+
};
10+
const encodedRegions = encodeRegions(regions);
11+
assert.deepStrictEqual('{region1}1,2,3,4', encodedRegions);
12+
});
13+
14+
it('should properly encode an object with multiple regions', () => {
15+
const regions = {
16+
region1: [[1, 2], [3, 4]],
17+
region2: [[5, 6], [7, 8]]
18+
};
19+
const encodedRegions = encodeRegions(regions);
20+
assert.deepStrictEqual('{region1}1,2,3,4|{region2}5,6,7,8', encodedRegions);
21+
});
22+
23+
it('should properly encode an object with multiple regions with multiple coordinates', () => {
24+
const regions = {
25+
region1: [[1, 2], [3, 4], [5, 6]],
26+
region2: [[7, 8], [9, 10], [11, 12], [13, 14]]
27+
};
28+
const encodedRegions = encodeRegions(regions);
29+
assert.deepStrictEqual('{region1}1,2,3,4,5,6|{region2}7,8,9,10,11,12,13,14', encodedRegions);
30+
});
31+
32+
it('should throw an error if used incorrectly', () => {
33+
assert.throws(encodeRegions, {
34+
name: 'TypeError',
35+
message: 'Cannot encode non existing regions'
36+
});
37+
});
38+
});

types/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,10 +540,13 @@ declare module 'cloudinary' {
540540
disable_promises?: boolean;
541541
oauth_token?: string;
542542
use_asset_folder_as_public_id_prefix?: boolean;
543+
regions?: Record<string, [RegionCoordinate, RegionCoordinate, ...Array<RegionCoordinate>]>;
543544

544545
[futureKey: string]: any;
545546
}
546547

548+
export type RegionCoordinate = [number, number];
549+
547550
export interface ProvisioningApiOptions {
548551
account_id?: string;
549552
provisioning_api_key?: string;

0 commit comments

Comments
 (0)