1 var REST = library.REST.REST(); 2 3 /** 4 * Gets a the container for the field. Either an Empty container or the container already saved to the Resource 5 * @param theFile the file we are dialing with 6 * @param theResourceWrapper where we are pulling the current data from 7 * @param theProperty the field we are working with 8 * @param theForcedType the type to force upon the field if the field is empty 9 * @returns SeqWrapper | BagWrapper | AltWrapper | String 10 */ 11 function getFieldWrapper( 12 theFile, 13 theResourceWrapper, 14 theProperty, 15 theForcedType 16 ) { 17 var aFieldValue = theResourceWrapper.getField(theProperty); 18 19 //Create a new Resource wrapper 20 var aFieldWrapper; 21 if (!!aFieldValue) { 22 //If the field already has a type, maintain it 23 aFieldWrapper = aFieldValue; 24 } else if (!!theForcedType) { 25 switch (theForcedType) { 26 case "Bag": 27 aFieldWrapper = theFile.xmp.newBag(); 28 break; 29 case "Alt": 30 aFieldWrapper = theFile.xmp.newAlt(); 31 break; 32 case "Seq": 33 case "RDB": 34 aFieldWrapper = theFile.xmp.newSeq(); 35 break; 36 default: 37 aFieldWrapper = ""; 38 } 39 } else if ( 40 theProperty.getFieldType() !== null && 41 theProperty.getFieldType().indexOf("list") >= 0 42 ) { 43 aFieldWrapper = theFile.xmp.newSeq(); 44 } else { 45 aFieldWrapper = ""; 46 } 47 48 return aFieldWrapper; 49 } 50 51 /** 52 * Determines if the JSON field value has the required structure for an RDB field 53 * @param theJSONValue 54 * @returns {boolean} 55 */ 56 function isRDB(theJSONValue, theProperty) { 57 var aFieldType = theProperty.getFieldType(); 58 if (!!aFieldType) { 59 return ( 60 aFieldType.toLowerCase() === "rdb" && 61 theJSONValue instanceof Array && 62 theJSONValue.length > 0 && 63 theJSONValue[0] instanceof Array && 64 theJSONValue[0].length > 0 && 65 !!theJSONValue[0][0].fieldId 66 ); 67 } else { 68 return false; 69 } 70 } 71 72 /** 73 * Gets a value to write to the file for the field defined in theFieldJSON 74 * @param theFile the asset we are currently writing to 75 * @param theResourceWrapper the resouce wrapper we should be pulling the current data from 76 * @param theFieldJSON defines the field and what we are writing 77 { 78 "fieldId": "http://purl.org/dc/elements/1.1/ title", 79 "value": "A new value for Dublin Core title", 80 "append": true 81 } 82 83 Normal container field 84 { 85 "fieldId": "http://purl.org/dc/elements/1.1/ title", 86 "value": ["A new value for Dublin Core title","value2"], 87 "append": true 88 } 89 90 Repeating data block container field 91 { 92 "fieldId": "http://purl.org/dc/elements/1.1/ repeating", 93 "append": true, 94 "value": 95 [ 96 [ 97 { 98 "fieldId": "http://purl.org/dc/elements/1.1/ blockField1", 99 "value": "Field1 in block" 100 }, 101 { 102 "fieldId": "http://purl.org/dc/elements/1.1/ blockField2", 103 "value": "Field2 in block" 104 } 105 ] 106 ] 107 } 108 109 * @returns {*} 110 */ 111 function getNewFieldValue(theFile, theResourceWrapper, theFieldJSON) { 112 var aValue = theFieldJSON.value; 113 var anAppend = theFieldJSON.append; 114 var anAllowDuplicates = !!theFieldJSON.allowDuplicates; 115 var aProperty = REST.getProperty(theFieldJSON.fieldId); 116 117 if (isRDB(aValue, aProperty)) { 118 //Repeating Data Block!!! 119 var aWrapper = getFieldWrapper(theFile, theFile.xmp.meta, aProperty, "RDB"); 120 if (!theFieldJSON.append) { 121 aWrapper.clear(); 122 } 123 124 for (var i in aValue) { 125 var aBlockFields = aValue[i]; 126 var aBlock = theFile.xmp.newStructure(); 127 for (var j in aBlockFields) { 128 var aRDBField = aBlockFields[j]; 129 var aBlockField = REST.getProperty(aRDBField.fieldId); 130 var aFieldValue = getNewFieldValue(theFile, aBlock, aRDBField); 131 aBlock.addField(aBlockField, aFieldValue); 132 } 133 aWrapper = aWrapper.addItem(aBlock); 134 } 135 return aWrapper; 136 } else { 137 var aFieldWrapper = getFieldWrapper(theFile, theResourceWrapper, aProperty); 138 139 if (typeof aFieldWrapper == "string") { 140 if (aValue instanceof Array) { 141 var aStringValue = ""; 142 for (var i in aValue) { 143 var anObject = aValue[i]; 144 if (typeof anObject == "object") { 145 aStringValue += JSON.stringify(anObject); 146 } else { 147 aStringValue += anObject; 148 } 149 if (i != aValue.length - 1) { 150 aStringValue += ","; 151 } 152 } 153 aValue = aStringValue; 154 } 155 return anAppend ? aFieldWrapper + aValue : aValue; 156 } 157 158 //Deal with container types 159 aValue = aValue instanceof Array ? aValue : [aValue]; 160 if (!anAppend) { 161 aFieldWrapper.clear(); 162 } 163 if (!anAllowDuplicates) { 164 var aValues = {}; 165 var aFiltered = aFieldWrapper.filter(function (theValue) { 166 if (!aValues[theValue]) { 167 aValues[theValue] = true; 168 return true; 169 } 170 return false; 171 }); 172 aFieldWrapper.clear(); 173 for (var i = 0; i < aFiltered.length; i++) { 174 aFieldWrapper.addItem(aFiltered[i]); 175 } 176 } 177 for (var j = 0; j < aValue.length; j++) { 178 var aSubValue = aValue[j]; 179 if (typeof aSubValue == "object") { 180 //The request is malformed or the user is trying to write a data block to a non data block field 181 aSubValue = JSON.stringify(aSubValue); 182 } 183 if (!anAllowDuplicates && aFieldWrapper.contains(aSubValue)) { 184 continue; 185 } 186 aFieldWrapper.addItem(aSubValue); 187 } 188 return aFieldWrapper; 189 } 190 } 191 192 /** 193 * writes field values for the asset 194 * 195 * @param theFieldData 196 * { 197 * "id":123456, 198 * "fields: 199 * [ 200 * { 201 * "fieldId": "http://purl.org/dc/elements/1.1/ title", 202 * "value": "A new value for Dublin Core title", 203 * "append": true 204 * },... 205 * ] 206 * } 207 */ 208 function setFields(theFieldData) { 209 var aChangeList = {}; 210 211 var aFile = fileManager.getFileObjectById(theFieldData.id); 212 if ( 213 aFile == null || 214 searchManager.filterByACL([theFieldData.id]).length == 0 215 ) { 216 REST.pushError( 217 REST.errors.e404, 218 "The file for this id is not found: " + theFieldData.id 219 ); 220 return; 221 } 222 var aFields = theFieldData.fields; 223 for (var i in aFields) { 224 var aField = aFields[i]; 225 if ( 226 !fieldManager.canEdit(aField.fieldId, context.getUser().getEditLevel()) 227 ) { 228 logger.warning("Cannot edit field due to field level: " + aField.fieldId); 229 REST.pushError( 230 REST.errors.e403, 231 "Cannot edit field due to field level: " + aField.fieldId 232 ); 233 continue; 234 } 235 var aProperty = REST.getProperty(aField.fieldId); 236 var aFieldValue = getNewFieldValue(aFile, aFile.xmp.meta, aField); 237 var aOldFieldValue = getFieldWrapper(aFile, aFile.xmp.meta, aProperty); 238 aFile.xmp.meta.addField(aProperty, aFieldValue); 239 240 // If we have a workflow to run after we should add the metadata change to the trigger event. 241 aChangeList = REST.addToChangeList( 242 aChangeList, 243 aProperty, 244 aOldFieldValue, 245 aFieldValue 246 ); 247 } 248 var anIsModified = aFile.isXmpModified(); 249 if (!aFile.writeXmp()) { 250 REST.pushError( 251 REST.errors.e500, 252 "Failed to write to the asset: " + 253 theFieldData.id + 254 ". Ensure that the field values are allowed by the field structure" 255 ); 256 return; 257 } 258 if (!anIsModified) { 259 return; 260 } 261 var aJsonStub = {}; 262 var aTriggerResponse = REST.triggerAssetBasedWorkflows( 263 REST.AssetTriggers.Modified, 264 aFile, 265 aChangeList 266 ); 267 if (aTriggerResponse) { 268 // If we have a workflow that we want to trigger post-file writing do it here. 269 aJsonStub.triggerAssetModified = aTriggerResponse.ok; 270 } 271 272 REST.push(aFile, aJsonStub); 273 } 274 275 /** 276 * @name SetFields 277 * @class Writes a values to assets 278 * @description For each asset in "data", this endpoint writes the defined field values to the asset. 279 * @param data an array of objects with an asset id and the fields to set. 280 * <pre><code> 281 * [ 282 * { 283 * "id":123456, 284 * "fields": 285 * [ 286 * { 287 * "fieldId": "http://purl.org/dc/elements/1.1/ title", 288 * "value": "A new value for Dublin Core title", 289 * "append": true 290 * },... 291 * ] 292 * },... 293 * ] 294 * </code></pre> 295 * @param [verbose=false] Setting this to true will collect a variety of default values for each asset. 296 * @param [fields] An array of field id's to collect the values for each asset 297 * @param [triggerAssetBasedWorkflow=false] Set to false to avoid chaining other metadata edited workflows 298 * @returns [{assetInfo}, ... ] 299 * 300 * @example /wf/restapi/v2/setFields 301 * 302 * Parameters: 303 * data= 304 [ 305 { 306 "id": 201629375, 307 "fields": [ 308 { 309 "fieldId": "http://purl.org/dc/elements/1.1/ title", 310 "value": "A new value for Dublin Core title", 311 "append": false 312 } 313 ] 314 }, 315 { 316 "id": 201628784, 317 "fields": [ 318 { 319 "fieldId": "http://purl.org/dc/elements/1.1/ title", 320 "value": "A new value for Dublin Core title", 321 "append": false 322 } 323 ] 324 } 325 ] 326 * fields=["http://purl.org/dc/elements/1.1/ title"] 327 * triggerAssetModified=true 328 * 329 * Response: 330 [ 331 { 332 "id": 201629375, 333 "fields": { 334 "http://purl.org/dc/elements/1.1/ title": "A new value for Dublin Core title" 335 }, 336 "triggerAssetModified": { 337 "ok": true, 338 "workflowTriggered": "Renditions/Workflows/moveAsset.xmpwf" 339 } 340 }, 341 { 342 "id": 201628784, 343 "fields": { 344 "http://purl.org/dc/elements/1.1/ title": "A new value for Dublin Core title" 345 }, 346 "triggerAssetModified": { 347 "ok": true, 348 "workflowTriggered": "Renditions/Workflows/moveAsset.xmpwf" 349 } 350 } 351 ] 352 353 * @example /wf/restapi/v2/setFields 354 * 355 * Parameters: 356 * data= 357 [ 358 { 359 "id": 201629375, 360 "fields": [ 361 { 362 "fieldId": "http://purl.org/dc/elements/1.1/ title", 363 "value": " append this ", 364 "append": true 365 } 366 ] 367 }, 368 { 369 "id": 201628784, 370 "fields": [ 371 { 372 "fieldId": "http://purl.org/dc/elements/1.1/ title", 373 "value": " append that", 374 "append": true 375 } 376 ] 377 } 378 ] 379 * fields=["http://purl.org/dc/elements/1.1/ title"] 380 * 381 * Response: 382 [ 383 { 384 "id": 201629375, 385 "fields": { 386 "http://purl.org/dc/elements/1.1/ title": "A new value for Dublin Core title append this " 387 } 388 }, 389 { 390 "id": 201628784, 391 "fields": { 392 "http://purl.org/dc/elements/1.1/ title": "A new value for Dublin Core title append that" 393 } 394 } 395 ] 396 397 * @example /wf/restapi/v2/setFields 398 * 399 * Parameters: 400 * data= 401 [ 402 { 403 "id": 201629375, 404 "fields": [ 405 { 406 "fieldId": "http://purl.org/dc/elements/1.1/ title", 407 "value": "DC Title", 408 "append": false 409 }, 410 { 411 "fieldId": "http://purl.org/dc/elements/1.1/ subject", 412 "value": ["DC Keywords"], 413 "append": false 414 } 415 ] 416 } 417 ] 418 * fields=["http://purl.org/dc/elements/1.1/ title", "http://purl.org/dc/elements/1.1/ subject"] 419 * 420 * Response: 421 [ 422 { 423 "id": 201629375, 424 "fields": { 425 "http://purl.org/dc/elements/1.1/ title": "DC Title", 426 "http://purl.org/dc/elements/1.1/ subject": [ 427 "DC Keywords" 428 ] 429 } 430 } 431 ] 432 433 * @example Setting multiple values in a container(CSV) field 434 * /wf/restapi/v2/setFields 435 * 436 * Parameters: 437 * data= 438 [ 439 { 440 "id": 201629375, 441 "fields": [ 442 { 443 "fieldId": "http://purl.org/dc/elements/1.1/ subject", 444 "value": ["value1","value2"], 445 "append": false 446 } 447 ] 448 } 449 ] 450 * fields=["http://purl.org/dc/elements/1.1/ subject"] 451 * 452 * Response: 453 [ 454 { 455 "id": 201629375, 456 "fields": { 457 "http://purl.org/dc/elements/1.1/ subject": [ 458 "value1", 459 "value2" 460 ] 461 } 462 } 463 ] 464 465 466 * @example Writing to data block fields 467 * /wf/restapi/v2/setFields 468 * 469 * Parameters: 470 * data= 471 [ 472 { 473 "id": 201629375, 474 "fields": [ 475 { 476 "fieldId": "http://ns.mediabeacon.com/REST_v2_testing/container/en/1.0/ datablock", 477 "value": [ 478 [ 479 { 480 "fieldId": "http://purl.org/dc/elements/1.1/ title", 481 "value": "textField" 482 }, 483 { 484 "fieldId": "http://purl.org/dc/elements/1.1/ subject", 485 "value": [ 486 "value1", 487 "value2" 488 ] 489 } 490 ] 491 ], 492 "append": false 493 } 494 ] 495 } 496 ] 497 * fields=["http://ns.mediabeacon.com/REST_v2_testing/container/en/1.0/ datablock"] 498 * 499 * Response: 500 [ 501 { 502 "id": 201631907, 503 "fields": { 504 "http://ns.mediabeacon.com/REST_v2_testing/container/en/1.0/ datablock": [ 505 { 506 "http://purl.org/dc/elements/1.1/ title": "textField", 507 "http://purl.org/dc/elements/1.1/ subject": [ 508 "value1", 509 "value2" 510 ] 511 } 512 ] 513 } 514 } 515 ] 516 517 * @example Writing multiple data blocks 518 * /wf/restapi/v2/setFields 519 * 520 * Parameters: 521 * data= 522 [ 523 { 524 "id": 201629375, 525 "fields": [ 526 { 527 "fieldId": "http://ns.mediabeacon.com/REST_v2_testing/container/en/1.0/ datablock", 528 "value": [ 529 [ 530 { 531 "fieldId": "http://purl.org/dc/elements/1.1/ title", 532 "value": "textField" 533 }, 534 { 535 "fieldId": "http://purl.org/dc/elements/1.1/ subject", 536 "value": [ 537 "value1", 538 "value2" 539 ] 540 } 541 ], 542 [ 543 { 544 "fieldId": "http://purl.org/dc/elements/1.1/ title", 545 "value": "block 2" 546 }, 547 { 548 "fieldId": "http://purl.org/dc/elements/1.1/ subject", 549 "value": [ 550 "block 2" 551 ] 552 } 553 ] 554 ], 555 "append": false 556 } 557 ] 558 } 559 ] 560 * fields=["http://ns.mediabeacon.com/REST_v2_testing/container/en/1.0/ datablock"] 561 * 562 * Response: 563 [ 564 { 565 "id": 201631907, 566 "fields": { 567 "http://ns.mediabeacon.com/REST_v2_testing/container/en/1.0/ datablock": [ 568 { 569 "http://purl.org/dc/elements/1.1/ title": "textField", 570 "http://purl.org/dc/elements/1.1/ subject": [ 571 "value1", 572 "value2" 573 ] 574 }, 575 { 576 "http://purl.org/dc/elements/1.1/ title": "block 2", 577 "http://purl.org/dc/elements/1.1/ subject": [ 578 "block 2" 579 ] 580 } 581 ] 582 } 583 } 584 ] 585 586 */ 587 function main() { 588 if (!context.getUser().isPermissionEnabled("editMetaData")) { 589 REST.pushError(REST.errors.e403, "editMetadata permission is not enabled"); 590 return REST.execute(); 591 } 592 REST.setCallback(setFields); 593 return REST.execute("data"); 594 } 595 main(); 596