1 var REST = library.REST.REST(); 2 var Request = library.Request.build(); 3 var myDownloadTempDir = null; 4 5 var kS3Enabled = args("aws.defaultBucket", "") !== ""; 6 7 /** 8 * Used to increment files with the same name test.txt becomes test 1.txt 9 * @param theParentPath 10 * @param theOldName 11 * @returns {string} 12 */ 13 function incrementName(theParentPath, theOldName) { 14 var anExtension = theOldName.substring( 15 theOldName.lastIndexOf("."), 16 theOldName.length 17 ); 18 var aFileNumber; 19 var aNewName; 20 if (theOldName.lastIndexOf(" ") !== -1) { 21 aNewName = theOldName.substring(0, theOldName.lastIndexOf(" ")); 22 aFileNumber = theOldName.substring( 23 theOldName.lastIndexOf(" "), 24 theOldName.lastIndexOf(anExtension) 25 ); 26 if (aFileNumber == null || aFileNumber === " ") { 27 aFileNumber = 0; 28 } else { 29 var aMightBeNumber = aFileNumber; 30 aFileNumber = parseInt(aFileNumber); 31 if (isNaN(aFileNumber)) { 32 //aFileNumber isn't a number. add the original back to the name 33 aNewName += aMightBeNumber; 34 aFileNumber = 0; 35 } 36 } 37 } else { 38 aFileNumber = 0; 39 aNewName = theOldName.substring(0, theOldName.lastIndexOf(".")); 40 } 41 aFileNumber++; 42 while ( 43 fileManager.isFile( 44 theParentPath + aNewName + " " + aFileNumber + anExtension 45 ) 46 ) { 47 aFileNumber++; 48 } 49 return aNewName + " " + aFileNumber + anExtension; 50 } 51 52 function upload() { 53 var aDest = REST.getFullPath(context.getParameter("dest")); 54 var aDestId = context.getParameter("destId"); 55 var aManagedFolder; 56 if (!!aDestId) { 57 aManagedFolder = fileManager.getFolderObjectById(aDestId); 58 if (!aManagedFolder) { 59 REST.pushError( 60 REST.errors.e404, 61 "The dest folder does not exist by id: " + aDestId 62 ); 63 return; 64 } 65 } 66 67 var aUnzip = context.getParameter("unzip"); 68 var aVersion = context.getParameter("version"); 69 if (!aVersion) { 70 aVersion = context.getParameter("replace"); 71 if (!!aVersion) { 72 logger.info( 73 "'replace' parameter is deprecated, should be using 'version'." 74 ); 75 } 76 } 77 var aDownloadedFiles = downloadFiles(context.getParameter("urls")); 78 try { 79 var anUploadedFile = context.getUploadedFile(); 80 if (anUploadedFile == null && aDownloadedFiles.length === 0) { 81 REST.pushError( 82 REST.errors.e400, 83 "A file was not attached to the form-data of the Body of the POST" 84 ); 85 return; 86 } 87 var aFiles = []; 88 if (anUploadedFile != null) { 89 if (anUploadedFile.constructor === Array) { 90 for (var i = 0; i < anUploadedFile.length; i++) { 91 aFiles.push(anUploadedFile[i]); 92 } 93 } else { 94 aFiles.push(anUploadedFile); 95 } 96 } 97 if (aDownloadedFiles.length > 0) { 98 for (i = 0; i < aDownloadedFiles.length; i++) { 99 aFiles.push(aDownloadedFiles[i]); 100 } 101 } 102 // Create the destination directory path if it does not already exist 103 if (!aManagedFolder) { 104 var aPathArray = aDest.toString().split("/"); 105 var aPath = ""; 106 for (i = 0; i < aPathArray.length; i++) { 107 // Continue on empty paths. 108 if (aPathArray[i] === "") { 109 continue; 110 } 111 aPath += aPathArray[i] + "/"; 112 113 //Only import unmanaged folders 114 var aDoImport = !fileManager.isManagedFolderPath(aPath); 115 var importingFolder = fileManager.folderNewByPath(aPath); 116 117 //Exclude the renditions folder from import 118 if (aDoImport && importingFolder.path.indexOf("Renditions") !== 0) { 119 fileManager.folderImport(importingFolder, false); 120 } 121 } 122 aManagedFolder = new ManagedFolder(aDest); 123 } 124 if (aManagedFolder == null) { 125 REST.pushError(REST.errors.e404, "Folder not found: " + aDest); 126 return; 127 } 128 129 if (kS3Enabled) { 130 uploadToS3( 131 aFiles.length === 1 ? aFiles[0] : aFiles, 132 aManagedFolder.path, 133 aUnzip, 134 aVersion 135 ); 136 } else { 137 doUpload(aFiles, aManagedFolder.path, aUnzip, aVersion); 138 } 139 140 if (myDownloadTempDir != null) { 141 fileManager.folderDelete(myDownloadTempDir); 142 myDownloadTempDir = null; 143 } 144 } catch (err) { 145 REST.pushError(REST.errors.e500, "Failed to upload to: " + aDest, err); 146 } 147 } 148 149 /** 150 * Copies the xmp from the xmpAsset to theAsset and keeps both assets unmanaged. 151 * 152 * @param theAsset the destination asset. 153 * @param theXmpAsset the asset with the source XMP. 154 */ 155 function setXmp(theAsset, theXmpAsset) { 156 var aSourceMeta = 157 theXmpAsset.xmp && theXmpAsset.xmp.meta ? theXmpAsset.xmp.meta : null; 158 var aDestMeta = theAsset.xmp && theAsset.xmp.meta ? theAsset.xmp.meta : null; 159 160 if (aSourceMeta != null && aDestMeta != null) { 161 logger.info("---------- Apply source meta"); 162 var aProperties = aSourceMeta.getFields(); 163 for (var i = 0; i < aProperties.length; i++) { 164 var aProperty = aProperties[i]; 165 var aField = aSourceMeta.getField(aProperty); 166 aDestMeta.addField(aProperty, aField); 167 } 168 } else { 169 logger.info("---------- Still o source meta"); 170 } 171 theAsset.writeXmp(); 172 } 173 174 /** 175 * Stamps the metadata provided via rest api to the asset uploaded. 176 * @param theAsset 177 */ 178 var stampMetadata = function (theAsset) { 179 //key value pairs of field name to field value 180 var aMetadata = context.getParameter("metadata"); 181 if (!!aMetadata) { 182 var aMeta = theAsset.xmp && theAsset.xmp.meta ? theAsset.xmp.meta : null; 183 if (aMeta != null) { 184 for (var aKey in aMetadata) { 185 var aValue = aMetadata[aKey]; 186 if (aValue != null) 187 { 188 aValue = aValue.trim(); 189 } 190 var aParamName = aKey.toLowerCase(); 191 var aSplit = aParamName.split(" "); 192 var aProperty = getPropertyCaseInsensitive(aSplit[0], aSplit[1]); 193 if (!!aProperty) { 194 var aField = aMeta.getField(aProperty); 195 if (fieldManager.isContainer(aProperty)) { 196 logger.info("Is container"); 197 var anArray = aValue.split(","); 198 if (aField instanceof Bag) { 199 aValue = theAsset.xmp.newBag(); 200 } else { 201 aValue = theAsset.xmp.newSeq(); 202 } 203 for (j = 0; j < anArray.length; j++) { 204 logger.info(anArray[j].trim()); 205 aValue.addItem(anArray[j].trim()); 206 } 207 } 208 aMeta.addProperty(aProperty, aValue); 209 } else { 210 logger.warning( 211 "Unknown field and unable to create default: " + aParamName 212 ); 213 } 214 } 215 var anIsWritten = theAsset.writeXmp(); 216 if (!anIsWritten) { 217 logger.warning( 218 "Metadata was not written properly to file: " + theAsset.path 219 ); 220 throw "Failed to write metadata"; 221 } 222 } 223 } 224 }; 225 226 /** 227 * Gets the property value based on namespace and field id 228 * @param theNamespace 229 * @param theField 230 * @returns {Property|null} 231 */ 232 function getPropertyCaseInsensitive(theNamespace, theField) 233 { 234 try { 235 var aQuery = 236 "SELECT j56c_id, j56c_namespace FROM j56t_xmp_namespaces WHERE lower(j56c_namespace) = '" + 237 escapeSql(theNamespace.toLowerCase()) + 238 "' ORDER BY j56c_id asc"; 239 var aSQL = new SQL(); 240 var aRes = aSQL.queryForMap(aQuery); 241 if (aRes.length > 0) 242 { 243 // we ordered by oldest so we want the first row 244 aQuery = 245 "SELECT j57c_name FROM j57t_xmp_fields WHERE lower(j57c_name) = '" + 246 escapeSql(theField.toLowerCase()) + 247 "' AND j57c_namespace = " + 248 aRes[0]["j56c_id"]; 249 var aField = aSQL.queryForString(aQuery); 250 if (!!aField && aField != "undefined" && aField != "null") 251 { 252 theField = aField; 253 theNamespace = aRes[0]["j56c_namespace"]; // set only if above call succeeded as well 254 } 255 } 256 } catch (e) 257 { 258 logger.warning("Unable to query for case-insensitive field name\n" + getErrorMessage(e)); 259 return null; 260 } 261 logger.info('Using "' + theNamespace + " " + theField + '"'); 262 return new Property(theNamespace, theField); 263 } 264 265 function escapeSql(theString) 266 { 267 return theString.replace(/'/g, "''"); 268 } 269 270 /** 271 * Formats the exception so its pretty for logging or the response 272 * @param theException 273 * @returns {string} 274 */ 275 function getErrorMessage(theException) 276 { 277 return ( theException.toString() + (!!theException.stack ? "\n\n" + theException.stack : "")); 278 } 279 280 /** 281 * Perform S3 upload(s) 282 * 283 * @param theUploadedFile the file(s) being uploaded 284 * @param theDestination the destination folder 285 * @param theUnzip should we unzip? 286 * @param theVersion should we create a new version? 287 */ 288 function uploadToS3(theUploadedFile, theDestination, theUnzip, theVersion) { 289 if (theUploadedFile.constructor === Array) { 290 for (var i = 0; i < theUploadedFile.length; i++) { 291 logger.warning("Uploading: " + i); 292 var aUploadedFile = theUploadedFile[i]; 293 294 var aFileExtension = aUploadedFile.name.split(".").pop(); 295 var isLoneFile = true; 296 297 if (aFileExtension !== "xmp") { 298 // look for side-car .xmp files and apply them 299 for (var j = 0; j < theUploadedFile.length; j++) { 300 if ( 301 theUploadedFile[j].name === 302 aUploadedFile.name.split(".")[0] + ".xmp" 303 ) { 304 // Found a side-car xmp file, apply it and continue on 305 setXmp(aUploadedFile, theUploadedFile[j]); 306 break; 307 } 308 } 309 } else { 310 for (var k = 0; k < theUploadedFile.length; k++) { 311 if ( 312 aUploadedFile.name === 313 theUploadedFile[k].name.split(".")[0] + ".xmp" 314 ) { 315 // File is a side-car xmp, ignore it 316 isLoneFile = false; 317 break; 318 } 319 } 320 } 321 322 // Upload to S3 if it's not a side-car xmp 323 if (isLoneFile) { 324 uploadS3File(aUploadedFile, theDestination, theUnzip, theVersion); 325 } 326 } 327 } else { 328 uploadS3File(theUploadedFile, theDestination, theUnzip, theVersion); 329 } 330 } 331 332 /** 333 * Upload a single file or archive to S3 334 * 335 * @param theUploadedFile the file to upload 336 * @param theDestination the destination 337 * @param theUnzip should we unzip? 338 * @param theVersion should we create a new version? 339 */ 340 function uploadS3File(theUploadedFile, theDestination, theUnzip, theVersion) { 341 // Handle Unzipping 342 var anIsAsyncImport = isAsyncImport(); 343 if (theUnzip && theUploadedFile.name.endsWith(".zip")) { 344 if (theUploadedFile.name.indexOf(".zip") > 0 && theUnzip === true) { 345 var aDecompressedDir = fileManager.decompressFiles( 346 theUploadedFile, 347 new ManagedFolder(theDestination), 348 "UTF-8", 349 false, 350 "", 351 anIsAsyncImport 352 ); 353 fileManager.fileDelete(theUploadedFile); 354 355 if (REST.isFile(aDecompressedDir)) { 356 // Upload unzipped asset to S3 357 doS3Upload( 358 aDecompressedDir, 359 theDestination, 360 anIsAsyncImport, 361 theVersion 362 ); 363 return; 364 } 365 var anIterator = aDecompressedDir.getContents(); 366 while (anIterator.hasNext()) { 367 var aFileOrFolder = anIterator.next(); 368 if (REST.isFile(aFileOrFolder)) { 369 // Upload unzipped asset to S3 370 doS3Upload( 371 aFileOrFolder, 372 theDestination, 373 anIsAsyncImport, 374 theVersion 375 ); 376 fileManager.fileDelete(aFileOrFolder); 377 } 378 } 379 return; 380 } 381 } 382 383 // Upload asset to S3 384 doS3Upload( 385 theUploadedFile, 386 theDestination, 387 anIsAsyncImport, 388 theVersion 389 ); 390 } 391 392 /** 393 * Performs S3 upload. 394 * 395 * @param theFile the file to upload 396 * @param theDestination the destination folder 397 * @param theIsAsyncImport is asynchronous import 398 * @param theVersion should we create a new version? 399 */ 400 function doS3Upload(theFile, theDestination, theIsAsyncImport, theVersion) { 401 if (fileManager.isManagedFilePath(theDestination + theFile.name) && theVersion) 402 { 403 var aDestFile = new ManagedFile(theDestination + theFile.name); 404 checkin(aDestFile, theFile); 405 pushUploadedAsset(fileManager.getFileObjectById(aDestFile.assetId)); 406 return; 407 } 408 if (!!theIsAsyncImport) 409 { 410 var anActionId = s3Manager.doS3UploadAsync( 411 context.getUser().username, 412 theFile, 413 theDestination 414 ); 415 pushAsyncUploadedAsset(theFile, theDestination, anActionId); 416 } else 417 { 418 var anAssetId = s3Manager.doS3Upload( 419 context.getUser().username, 420 theFile, 421 theDestination 422 ); 423 var aNewAsset = fileManager.getFileObjectById(anAssetId); 424 pushUploadedAsset(aNewAsset); 425 } 426 } 427 428 function doUpload(theUploadedFiles, theDestination, theUnzip, theVersion) { 429 var anIsAsyncImport = isAsyncImport(); 430 // Versioning parameters 431 var aComment = 432 context.getParameter("message") === undefined 433 ? "" 434 : context.getParameter("comment"); 435 var replaceName = 436 context.getParameter("replaceName") === "true" || 437 context.getParameter("replaceName") === true; 438 var aReplaceMetadata = 439 context.getParameter("replaceMetadata") === "true" || 440 context.getParameter("replaceMetadata") === true; 441 442 for (var i = 0; i < theUploadedFiles.length; i++) { 443 var aFileExtension = theUploadedFiles[i].name.split(".").pop(); 444 var isStandAloneAsset = true; 445 var aFileToUpload = theUploadedFiles[i]; 446 447 if (aFileExtension !== "xmp") { 448 // if it's not an XMP file, see if it has a matching XMP to stick to it. 449 for (var j = 0; j < theUploadedFiles.length; j++) { 450 // Found a matching .XMP add to the mapping to apply it later 451 if ( 452 theUploadedFiles[j].name === 453 aFileToUpload.name.split(".")[0] + ".xmp" 454 ) { 455 setXmp(aFileToUpload, theUploadedFiles[j]); 456 break; 457 } 458 } 459 } else { 460 // If it is an XMP file, see if it's a lone XMP (no matching asset), if so, upload like a normal data asset 461 for (var j = 0; j < theUploadedFiles.length; j++) { 462 if ( 463 theUploadedFiles[j].name.split(".").pop() !== "xmp" && 464 theUploadedFiles[j].name.split(".")[0] === 465 aFileToUpload.name.split(".")[0] 466 ) { 467 isStandAloneAsset = false; 468 break; 469 } 470 } 471 } 472 473 // this file is an xmp for another asset we'll process later 474 if (!isStandAloneAsset) { 475 continue; 476 } 477 478 if ( 479 fileManager.isManagedFilePath(theDestination + aFileToUpload.name) && 480 theVersion && 481 !theUnzip 482 ) { 483 var aDestFile = new ManagedFile(theDestination + aFileToUpload.name); 484 versionManager.createNewVersion( 485 aDestFile.assetId, 486 aFileToUpload, 487 aComment, 488 replaceName, 489 aReplaceMetadata 490 ); 491 pushUploadedAsset(fileManager.getFileObjectById(aDestFile.assetId)); 492 } else if (aFileToUpload.name.indexOf(".zip") > 0 && theUnzip === true) { 493 var aDecompressedDir = fileManager.decompressFiles( 494 aFileToUpload, 495 new ManagedFolder(theDestination), 496 "UTF-8", 497 false, 498 "", 499 anIsAsyncImport 500 ); 501 fileManager.fileDelete(aFileToUpload); 502 if (REST.isFile(aDecompressedDir)) { 503 finishUpload(aDecompressedDir, theDestination, anIsAsyncImport); 504 return; 505 } 506 var anIterator = aDecompressedDir.getContents(); 507 while (anIterator.hasNext()) { 508 var aFileOrFolder = anIterator.next(); 509 if (REST.isFile(aFileOrFolder)) { 510 finishUpload(aFileOrFolder, theDestination, anIsAsyncImport); 511 } 512 } 513 } else { 514 var anUploaded = fileManager.fileMove( 515 aFileToUpload, 516 new ManagedFolder(theDestination), 517 theVersion, 518 null, 519 anIsAsyncImport 520 ); 521 finishUpload(anUploaded, theDestination, anIsAsyncImport); 522 } 523 } 524 } 525 526 /** 527 * Finishes the standard upload. 528 * 529 * @param theFile the uploaded file 530 * @param theDestination the destination folder 531 * @param theIsAsyncImport is asynchronous import 532 */ 533 function finishUpload(theFile, theDestination, theIsAsyncImport) 534 { 535 if (!!theIsAsyncImport) 536 { 537 var anActionId = fileManager.fileImportAsync(theFile); 538 pushAsyncUploadedAsset(theFile, theDestination, anActionId); 539 } else 540 { 541 pushUploadedAsset(theFile); 542 } 543 } 544 545 /** 546 * Check in the working copy as a new version of the asset. 547 * 548 * @param theDestFile the destination file 549 * @param theSourceFile the source file 550 */ 551 function checkin(theDestFile, theSourceFile) 552 { 553 try 554 { 555 var aStartTime = new Date(); 556 if (theSourceFile == null) 557 { 558 throw "A file was not attached to the form-data of the Body of the POST"; 559 } 560 logger.info("Checking in upload: " + theSourceFile.path); 561 checkoutManager.checkout(theDestFile); 562 if ( 563 !checkoutManager.checkinWorkingCopy( 564 theDestFile, 565 "Checkin from REST API", 566 theSourceFile 567 ) 568 ) 569 { 570 checkoutManager.cancelCheckout(theDestFile); 571 throw "Unable to checkin file, check MediaBeacon logs"; 572 } 573 var i = 0; 574 while (i < 10) 575 { 576 try 577 { 578 fileManager.fileDelete(theSourceFile); 579 break; 580 } catch (theE) 581 { 582 logger.info("Failed to delete, trying again"); 583 workflowManager.sleep(1); 584 i++; 585 } 586 } 587 var aMetric = { 588 action: "Checkin from 'REST API'", 589 subject: "Asset", 590 user_name: "System", 591 datestamp: new Date(), 592 elapsed_time: new Date() - aStartTime, 593 path: theDestFile.path, 594 asset_id: theDestFile.assetId, 595 description: 596 "REST API Checkin: " + theDestFile.path + ", SIZE: " + theDestFile.length, 597 }; 598 metricsManager.addMetric(aMetric); 599 } catch (theE) 600 { 601 throw "Failed to upload: " + theE; 602 } 603 } 604 605 /** 606 * Writes the uploaded user to the file and adds it to the response 607 * @param theAsset 608 */ 609 function pushUploadedAsset(theAsset) { 610 addUploadData(theAsset); 611 var aStub = {}; 612 var anAssetAdded = REST.triggerAssetBasedWorkflows( 613 REST.AssetTriggers.Added, 614 theAsset 615 ); 616 if (anAssetAdded) { 617 theAsset = fileManager.getFileObjectById(theAsset.assetId); 618 aStub.triggerAssetAdded = anAssetAdded.ok; 619 } 620 REST.push(theAsset, aStub); 621 } 622 623 /** 624 * Writes data to the response. 625 * 626 * @param theAsset the uploaded asset 627 * @param theDestination the destination folder 628 * @param theActionId the action id 629 */ 630 function pushAsyncUploadedAsset(theAsset, theDestination, theActionId) { 631 addUploadData(theAsset); 632 REST.push( 633 null, 634 { 635 name: theAsset.name, 636 path: theDestination + theAsset.name, 637 actionId: theActionId 638 } 639 ); 640 } 641 642 /** 643 * Is asynchronous import? 644 */ 645 function isAsyncImport() { 646 return context.getParameter("asyncImport") === "true" || 647 context.getParameter("asyncImport") === true; 648 } 649 650 /** 651 * Downloads files by given url(s). 652 * 653 * @param theUrls the url(s) 654 */ 655 function downloadFiles(theUrls) { 656 var aRes = []; 657 if (theUrls == null) { 658 return aRes; 659 } 660 for (var i = 0; i < theUrls.length; i++) { 661 var aFileName = theUrls[i].substr(theUrls[i].lastIndexOf("/") + 1); 662 aFileName = aFileName.split("?")[0]; 663 var aFile = Request.get(theUrls[i], { dataType: "file", selfSigned: true, fileName: aFileName }); 664 myDownloadTempDir = aFile.parent; 665 aRes.push(aFile); 666 } 667 return aRes; 668 } 669 670 /** 671 * Adds the upload id and upload username to the xmp of the asset. 672 * @param theAsset 673 */ 674 function addUploadData(theAsset) 675 { 676 var aProperty = new Property( 677 "http://mediabeacon.com/ns/default/1.0/", 678 "uploadUser" 679 ); 680 theAsset.xmp.meta.addField(aProperty, context.getUser().username); 681 var aUploadIDProperty = new Property( 682 "http://mediabeacon.com/ns/default/1.0/", 683 "uploadId" 684 ); 685 theAsset.xmp.meta.addField(aUploadIDProperty, Date.now().toString()); 686 theAsset.writeXmp(); 687 stampMetadata(theAsset); 688 } 689 690 /** 691 * @name Upload 692 * @class Upload an asset into MediaBeacon 693 * @description For every asset defined in "data", this endpoint sets the xmp from the given xmp string 694 * @param file the file needs to be added to the body of the POST in the form data with the name "file" 695 * @param dest the path to the destination folder "upload/here/" 696 * @param destId the directory id of the destination folder. 697 * @param [unzip=false] unzip the uploaded files 698 * @param [version=false] if a file already exists in the destination, new version it with the uploaded file 699 * @param [verbose=false] Setting this to true will collect a variety of default values for each asset. 700 * @param [fields] An array of field id's to collect the values for each asset 701 * @param [message] Comment for versioned file 702 * @param [replaceMetadata=false] Replace metadata for versioned file 703 * @param [replaceName=false] Replace name for versioned file 704 * @param [triggerAssetBasedWorkflow=true] set to false to avoid triggering other asset added workflows 705 * @param [asyncImport=false] set to true to import the uploaded file asynchronously 706 * @param metadata a JSON object contains key as field Id and value as value of the field to be stamped to the uploaded asset. 707 * metadata = 708 * { 709 * "http://purl.org/dc/elements/1.1/ subject" : "newValue" 710 * } 711 * @returns [{assetInfo}, ... ] 712 * 713 * @deprecated [replace=false] use 'version' instead, now it creates a new version if the file already exists. 714 * 715 * @example /wf/restapi/v2/upload 716 * 717 * Parameters: 718 * file={{FILE DATA IN POST BODY}} 719 * dest="upload/here/" 720 * verbose=true 721 * 722 * Response: 723 [ 724 { 725 "id": 201629401, 726 "name": "heic0006a_orig.tif", 727 "path": "upload/here/heic0006a_orig.tif", 728 "height": 746, 729 "width": 1500, 730 "bytes": 1459026, 731 "lastModified": 1508187662000, 732 "mimeType": "image/tiff", 733 "previews": { 734 "thumbnail": "../servlet/jb.view?table=thumbnails&col=thumbnails&id=pe_323031363239343031", 735 "viewex": "../servlet/jb.view?table=viewex&col=viewex&id=pe_323031363239343031", 736 "downloadUrl": "../servlet/dload?id=pe_323031363239343031" 737 } 738 } 739 ] 740 741 * @example /wf/restapi/v2/upload 742 * 743 * Parameters: 744 * file={{ZIPPED FILE}} 745 * dest="upload/here/" 746 * unzip=true 747 * verbose=true 748 * 749 * Response: 750 [ 751 { 752 "name": "hubble", 753 "path": "upload/here/", 754 "resolver": "directory://162", 755 "assets": [ 756 { 757 "id": 201629404, 758 "name": "heic0006a_orig.tif", 759 "path": "upload/here/heic0006a_orig.tif", 760 "height": 746, 761 "width": 1500, 762 "bytes": 1459026, 763 "lastModified": 1262635000, 764 "mimeType": "image/tiff", 765 "previews": { 766 "thumbnail": "../servlet/jb.view?table=thumbnails&col=thumbnails&id=pe_323031363239343034", 767 "viewex": "../servlet/jb.view?table=viewex&col=viewex&id=pe_323031363239343034", 768 "downloadUrl": "../servlet/dload?id=pe_323031363239343034" 769 } 770 }, 771 { 772 "id": 201629405, 773 "name": "heic0106a1_orig.tif", 774 "path": "upload/here/heic0106a1_orig.tif", 775 "height": 573, 776 "width": 564, 777 "bytes": 817080, 778 "lastModified": 1262635000, 779 "mimeType": "image/tiff", 780 "previews": { 781 "thumbnail": "../servlet/jb.view?table=thumbnails&col=thumbnails&id=pe_323031363239343035", 782 "viewex": "../servlet/jb.view?table=viewex&col=viewex&id=pe_323031363239343035", 783 "downloadUrl": "../servlet/dload?id=pe_323031363239343035" 784 } 785 } 786 ] 787 } 788 ] 789 790 * @example /wf/restapi/v2/upload 791 * 792 * Parameters: 793 * file={{FILE DATA IN POST BODY}} 794 * destId=123 795 * verbose=true 796 * 797 * Response: 798 [ 799 { 800 "id": 201629401, 801 "name": "heic0006a_orig.tif", 802 "path": "upload/here/heic0006a_orig.tif", 803 "directoryId": 123 804 "height": 746, 805 "width": 1500, 806 "bytes": 1459026, 807 "lastModified": 1508187662000, 808 "mimeType": "image/tiff", 809 "previews": { 810 "thumbnail": "../servlet/jb.view?table=thumbnails&col=thumbnails&id=pe_323031363239343031", 811 "viewex": "../servlet/jb.view?table=viewex&col=viewex&id=pe_323031363239343031", 812 "downloadUrl": "../servlet/dload?id=pe_323031363239343031" 813 } 814 } 815 ] 816 817 * @example /wf/restapi/v2/upload 818 * 819 * Parameters: 820 * file={{FILE DATA IN POST BODY}} 821 * dest="upload/here/" 822 * verbose=true 823 * asyncImport=true 824 * 825 * Response: 826 [ 827 { 828 "name": "heic0006a_orig.tif", 829 "path": "upload/here/heic0006a_orig.tif", 830 "actionId": "12AF58A0-6C54-4413-91D7-D1A521B9D6D2" 831 } 832 ] 833 */ 834 function main() { 835 if (!context.getUser().isPermissionEnabled("fileUpload")) { 836 REST.pushError(REST.errors.e403, "upload permission is not enabled"); 837 return REST.execute(); 838 } 839 REST.setCallback(upload); 840 return REST.execute(); 841 } 842 main(); 843