Skip to content

Commit 1938e39

Browse files
author
Matt Willer
authored
Add convenience methods for setting metadata (#376)
1 parent 01f21df commit 1938e39

File tree

4 files changed

+388
-89
lines changed

4 files changed

+388
-89
lines changed

docs/metadata.md

+178-89
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,11 @@ in a flexible way, without pre-defined template structure.
3232
- [Update Metadata Template](#update-metadata-template)
3333
- [Get Enterprise Metadata Templates](#get-enterprise-metadata-templates)
3434
- [Delete Metadata Template](#delete-metadata-template)
35-
- [Add Metadata to a File](#add-metadata-to-a-file)
35+
- [Set Metadata on a File](#set-metadata-on-a-file)
3636
- [Get Metadata on a File](#get-metadata-on-a-file)
37-
- [Update Metadata on a File](#update-metadata-on-a-file)
3837
- [Remove Metadata from a File](#remove-metadata-from-a-file)
39-
- [Add Metadata to a Folder](#add-metadata-to-a-folder)
38+
- [Set Metadata on a Folder](#set-metadata-on-a-folder)
4039
- [Get Metadata on a Folder](#get-metadata-on-a-folder)
41-
- [Update Metadata on a Folder](#update-metadata-on-a-folder)
4240
- [Remove Metadata from a Folder](#remove-metadata-from-a-folder)
4341
- [Create Cascade Policy](#create-cascade-policy)
4442
- [Get Cascade Policy](#get-cascade-policy)
@@ -329,13 +327,52 @@ method with the template scope and template name.
329327
client.metadata.deleteTemplate('enterprise', 'testtemplate', callback);
330328
```
331329

332-
Add Metadata to a File
330+
Set Metadata on a File
333331
----------------------
334332

335-
Metadata can be created on a file by calling
336-
[`files.addMetadata(fileID, scope, template, metadata, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/Files.html#addMetadata)
333+
To set metadata on a file, call [`files.setMetadata(fileID, scope, template, metadata, callback)`][set-metadata]
334+
with the scope and template key of the metadata template, as well as an `Object` containing the metadata keys
335+
and values to set.
336+
337+
> __Note:__ This method will unconditionally apply the provided metadata, overwriting existing metadata
338+
> for the keys provided. To specifically create or update metadata, see the `addMetadata()` and `updateMetadata()`
339+
> methods below.
340+
341+
```js
342+
var metadataValues = {
343+
audience: "internal",
344+
documentType: "Q1 plans",
345+
competitiveDocument: "no",
346+
status: "active",
347+
author: "Jones",
348+
currentState: "proposal"
349+
};
350+
client.files.setMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", metadataValues)
351+
.then(metadata => {
352+
/* metadata -> {
353+
audience: 'internal',
354+
documentType: 'Q1 plans',
355+
competitiveDocument: 'no',
356+
status: 'active',
357+
author: 'Jones',
358+
currentState: 'proposal',
359+
'$type': 'marketingCollateral-d086c908-2498-4d3e-8a1f-01e82bfc2abe',
360+
'$parent': 'file_11111',
361+
'$id': '2094c584-68e1-475c-a581-534a4609594e',
362+
'$version': 0,
363+
'$typeVersion': 0,
364+
'$template': 'marketingCollateral',
365+
'$scope': 'enterprise_12345' }
366+
*/
367+
});
368+
```
369+
370+
To add new metadata to a file, call [`files.addMetadata(fileID, scope, template, metadata, callback)`][add-metadata]
337371
with a metadata template and an object of key/value pairs to add as metadata.
338372

373+
> __Note:__: This method will only succeed if the provided metadata template is not current applied to the file,
374+
> otherwise it will fail with a Conflict error.
375+
339376
```js
340377
var metadataValues = {
341378
audience: "internal",
@@ -365,6 +402,52 @@ client.files.addMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingC
365402
});
366403
```
367404

405+
Update a file's existing metadata by calling
406+
[`files.updateMetadata(fileID, scope, template, patch, callback)`][update-metadata]
407+
with an array of [JSON Patch](http://jsonpatch.com/) formatted operations.
408+
409+
> __Note:__ This method will only succeed if the provided metadata template has already been applied to
410+
> the file; if the file does not have existing metadata, this method will fail with a Not Found error.
411+
> This is useful in cases where you know the file will already have metadata applied, since it will
412+
> save an API call compared to `setMetadata()`.
413+
414+
```js
415+
var updates = [
416+
{ op: 'test', path: '/competitiveDocument', value: 'no' },
417+
{ op: 'remove', path: '/competitiveDocument' },
418+
{ op: 'test', path: '/status', value: 'active' },
419+
{ op: 'replace', path: '/status', value: 'inactive' },
420+
{ op: 'test', path: '/author', value: 'Jones' },
421+
{ op: 'copy', from: '/author', path: '/editor' },
422+
{ op: 'test', path: '/currentState', value: 'proposal' },
423+
{ op: 'move', from: '/currentState', path: '/previousState' },
424+
{ op: 'add', path: '/currentState', value: 'reviewed' }
425+
];
426+
client.files.updateMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", updates)
427+
.then(metadata => {
428+
/* metadata -> {
429+
audience: 'internal',
430+
documentType: 'Q1 plans',
431+
status: 'inactive',
432+
author: 'Jones',
433+
'$type': 'marketingCollateral-d086c908-2498-4d3e-8a1f-01e82bfc2abe',
434+
'$parent': 'file_11111',
435+
'$id': '2094c584-68e1-475c-a581-534a4609594e',
436+
'$version': 1,
437+
'$typeVersion': 0,
438+
editor: 'Jones',
439+
previousState: 'proposal',
440+
currentState: 'reviewed',
441+
'$template': 'marketingCollateral',
442+
'$scope': 'enterprise_12345' }
443+
*/
444+
});
445+
```
446+
447+
[set-metadata]: http://opensource.box.com/box-node-sdk/jsdoc/Files.html#setMetadata
448+
[add-metadata]: http://opensource.box.com/box-node-sdk/jsdoc/Files.html#addMetadata
449+
[update-metadata]: http://opensource.box.com/box-node-sdk/jsdoc/Files.html#updateMetadata
450+
368451
Get Metadata on a File
369452
----------------------
370453

@@ -432,66 +515,66 @@ client.files.getAllMetadata('11111')
432515
});
433516
```
434517

435-
Update Metadata on a File
436-
-------------------------
518+
Remove Metadata from a File
519+
---------------------------
437520

438-
Update a file's metadata by calling
439-
[`files.updateMetadata(fileID, scope, template, patch, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/Files.html#updateMetadata)
440-
with an array of [JSON Patch](http://jsonpatch.com/) formatted operations.
521+
A metadata template can be removed from a file by calling
522+
[`files.deleteMetadata(fileID, scope, template, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/Files.html#deleteMetadata).
441523

442524
```js
443-
var updates = [
444-
{ op: 'test', path: '/competitiveDocument', value: 'no' },
445-
{ op: 'remove', path: '/competitiveDocument' },
446-
{ op: 'test', path: '/status', value: 'active' },
447-
{ op: 'replace', path: '/status', value: 'inactive' },
448-
{ op: 'test', path: '/author', value: 'Jones' },
449-
{ op: 'copy', from: '/author', path: '/editor' },
450-
{ op: 'test', path: '/currentState', value: 'proposal' },
451-
{ op: 'move', from: '/currentState', path: '/previousState' },
452-
{ op: 'add', path: '/currentState', value: 'reviewed' }
453-
];
454-
client.files.updateMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", updates)
525+
client.files.deleteMetadata('67890', client.metadata.scopes.GLOBAL, client.metadata.templates.PROPERTIES)
526+
.then(() => {
527+
// removal succeeded — no value returned
528+
});;
529+
```
530+
531+
Set Metadata on a Folder
532+
------------------------
533+
534+
To set metadata on a folder, call [`folders.setMetadata(folderID, scope, template, metadata, callback)`][set-metadata]
535+
with the scope and template key of the metadata template, as well as an `Object` containing the metadata keys
536+
and values to set.
537+
538+
> __Note:__ This method will unconditionally apply the provided metadata, overwriting existing metadata
539+
> for the keys provided. To specifically create or update metadata, see the `addMetadata()` and `updateMetadata()`
540+
> methods below.
541+
542+
```js
543+
var metadataValues = {
544+
audience: "internal",
545+
documentType: "Q1 plans",
546+
competitiveDocument: "no",
547+
status: "active",
548+
author: "Jones",
549+
currentState: "proposal"
550+
};
551+
client.folders.setMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", metadataValues)
455552
.then(metadata => {
456553
/* metadata -> {
457554
audience: 'internal',
458555
documentType: 'Q1 plans',
459-
status: 'inactive',
556+
competitiveDocument: 'no',
557+
status: 'active',
460558
author: 'Jones',
559+
currentState: 'proposal',
461560
'$type': 'marketingCollateral-d086c908-2498-4d3e-8a1f-01e82bfc2abe',
462-
'$parent': 'file_11111',
561+
'$parent': 'folder_11111',
463562
'$id': '2094c584-68e1-475c-a581-534a4609594e',
464-
'$version': 1,
563+
'$version': 0,
465564
'$typeVersion': 0,
466-
editor: 'Jones',
467-
previousState: 'proposal',
468-
currentState: 'reviewed',
469565
'$template': 'marketingCollateral',
470566
'$scope': 'enterprise_12345' }
471567
*/
472568
});
473569
```
474570

475-
Remove Metadata from a File
476-
---------------------------
477-
478-
A metadata template can be removed from a file by calling
479-
[`files.deleteMetadata(fileID, scope, template, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/Files.html#deleteMetadata).
480-
481-
```js
482-
client.files.deleteMetadata('67890', client.metadata.scopes.GLOBAL, client.metadata.templates.PROPERTIES)
483-
.then(() => {
484-
// removal succeeded — no value returned
485-
});;
486-
```
487-
488-
Add Metadata to a Folder
489-
------------------------
490-
491-
Metadata can be created on a folder by calling
492-
[`folders.addMetadata(folderID, scope, template, metadata, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/Folders.html#addMetadata)
571+
To add new metadata to a folder, call
572+
[`folders.addMetadata(folderID, scope, template, metadata, callback)`][add-metadata]
493573
with a metadata template and an object of key/value pairs to add as metadata.
494574

575+
> __Note:__: This method will only succeed if the provided metadata template is not current applied to the folder,
576+
> otherwise it will fail with a Conflict error.
577+
495578
```js
496579
var metadataValues = {
497580
audience: "internal",
@@ -501,7 +584,7 @@ var metadataValues = {
501584
author: "Jones",
502585
currentState: "proposal"
503586
};
504-
client.folders.addMetadata('11111', client.metadata.scopes.ENTERPRISE, 'marketingCollateral', metadataValues);
587+
client.folders.addMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", metadataValues)
505588
.then(metadata => {
506589
/* metadata -> {
507590
audience: 'internal',
@@ -521,6 +604,52 @@ client.folders.addMetadata('11111', client.metadata.scopes.ENTERPRISE, 'marketin
521604
});
522605
```
523606

607+
Update a folder's existing metadata by calling
608+
[`folders.updateMetadata(fileID, scope, template, patch, callback)`][update-metadata]
609+
with an array of [JSON Patch](http://jsonpatch.com/) formatted operations.
610+
611+
> __Note:__ This method will only succeed if the provided metadata template has already been applied to
612+
> the folder; if the folder does not have existing metadata, this method will fail with a Not Found error.
613+
> This is useful in cases where you know the folder will already have metadata applied, since it will
614+
> save an API call compared to `setMetadata()`.
615+
616+
```js
617+
var updates = [
618+
{ op: 'test', path: '/competitiveDocument', value: 'no' },
619+
{ op: 'remove', path: '/competitiveDocument' },
620+
{ op: 'test', path: '/status', value: 'active' },
621+
{ op: 'replace', path: '/status', value: 'inactive' },
622+
{ op: 'test', path: '/author', value: 'Jones' },
623+
{ op: 'copy', from: '/author', path: '/editor' },
624+
{ op: 'test', path: '/currentState', value: 'proposal' },
625+
{ op: 'move', from: '/currentState', path: '/previousState' },
626+
{ op: 'add', path: '/currentState', value: 'reviewed' }
627+
];
628+
client.folders.updateMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", updates)
629+
.then(metadata => {
630+
/* metadata -> {
631+
audience: 'internal',
632+
documentType: 'Q1 plans',
633+
status: 'inactive',
634+
author: 'Jones',
635+
'$type': 'marketingCollateral-d086c908-2498-4d3e-8a1f-01e82bfc2abe',
636+
'$parent': 'folder_11111',
637+
'$id': '2094c584-68e1-475c-a581-534a4609594e',
638+
'$version': 1,
639+
'$typeVersion': 0,
640+
editor: 'Jones',
641+
previousState: 'proposal',
642+
currentState: 'reviewed',
643+
'$template': 'marketingCollateral',
644+
'$scope': 'enterprise_12345' }
645+
*/
646+
});
647+
```
648+
649+
[set-metadata]: http://opensource.box.com/box-node-sdk/jsdoc/Folders.html#setMetadata
650+
[add-metadata]: http://opensource.box.com/box-node-sdk/jsdoc/Folders.html#addMetadata
651+
[update-metadata]: http://opensource.box.com/box-node-sdk/jsdoc/Folders.html#updateMetadata
652+
524653
Get Metadata on a Folder
525654
------------------------
526655

@@ -588,46 +717,6 @@ client.folders.getAllMetadata('11111')
588717
});
589718
```
590719

591-
Update Metadata on a Folder
592-
---------------------------
593-
594-
Update a folder's metadata by calling
595-
[`folders.updateMetadata(folderID, scope, template, patch, callback)`](http://opensource.box.com/box-node-sdk/jsdoc/Folders.html#updateMetadata)
596-
with an array of [JSON Patch](http://jsonpatch.com/) formatted operations.
597-
598-
```js
599-
var updates = [
600-
{ op: 'test', path: '/competitiveDocument', value: 'no' },
601-
{ op: 'remove', path: '/competitiveDocument' },
602-
{ op: 'test', path: '/status', value: 'active' },
603-
{ op: 'replace', path: '/status', value: 'inactive' },
604-
{ op: 'test', path: '/author', value: 'Jones' },
605-
{ op: 'copy', from: '/author', path: '/editor' },
606-
{ op: 'test', path: '/currentState', value: 'proposal' },
607-
{ op: 'move', from: '/currentState', path: '/previousState' },
608-
{ op: 'add', path: '/currentState', value: 'reviewed' }
609-
];
610-
client.folders.updateMetadata('11111', client.metadata.scopes.ENTERPRISE, "marketingCollateral", updates)
611-
.then(metadata => {
612-
/* metadata -> {
613-
audience: 'internal',
614-
documentType: 'Q1 plans',
615-
status: 'inactive',
616-
author: 'Jones',
617-
'$type': 'marketingCollateral-d086c908-2498-4d3e-8a1f-01e82bfc2abe',
618-
'$parent': 'folder_11111',
619-
'$id': '2094c584-68e1-475c-a581-534a4609594e',
620-
'$version': 1,
621-
'$typeVersion': 0,
622-
editor: 'Jones',
623-
previousState: 'proposal',
624-
currentState: 'reviewed',
625-
'$template': 'marketingCollateral',
626-
'$scope': 'enterprise_12345' }
627-
*/
628-
});
629-
```
630-
631720
Remove Metadata from a Folder
632721
-----------------------------
633722

lib/managers/files.js

+31
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,37 @@ Files.prototype.updateMetadata = function(fileID, scope, template, patch, callba
743743
return this.client.wrapWithDefaultHandler(this.client.put)(apiPath, params, callback);
744744
};
745745

746+
/**
747+
* Sets metadata on a file, overwriting any metadata that exists for the provided keys.
748+
*
749+
* @param {string} fileID - The file to set metadata on
750+
* @param {string} scope - The scope of the metadata template
751+
* @param {string} template - The key of the metadata template
752+
* @param {Object} metadata - The metadata to set
753+
* @param {Function} [callback] - Called with updated metadata if successful
754+
* @returns {Promise<Object>} A promise resolving to the updated metadata
755+
*/
756+
Files.prototype.setMetadata = function(fileID, scope, template, metadata, callback) {
757+
758+
return this.addMetadata(fileID, scope, template, metadata)
759+
.catch(err => {
760+
761+
if (err.statusCode !== 409) {
762+
throw err;
763+
}
764+
765+
// Metadata already exists on the file; update instead
766+
var updates = Object.keys(metadata).map(key => ({
767+
op: 'add',
768+
path: `/${key}`,
769+
value: metadata[key],
770+
}));
771+
772+
return this.updateMetadata(fileID, scope, template, updates);
773+
})
774+
.asCallback(callback);
775+
};
776+
746777
/**
747778
* Deletes a metadata template from a file.
748779
*

0 commit comments

Comments
 (0)