FilesController.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = exports.FilesController = void 0;
  6. var _cryptoUtils = require("../cryptoUtils");
  7. var _AdaptableController = _interopRequireDefault(require("./AdaptableController"));
  8. var _FilesAdapter = require("../Adapters/Files/FilesAdapter");
  9. var _path = _interopRequireDefault(require("path"));
  10. var _mime = _interopRequireDefault(require("mime"));
  11. function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
  12. // FilesController.js
  13. const Parse = require('parse').Parse;
  14. const legacyFilesRegex = new RegExp('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}-.*');
  15. class FilesController extends _AdaptableController.default {
  16. getFileData(config, filename) {
  17. return this.adapter.getFileData(filename);
  18. }
  19. async createFile(config, filename, data, contentType, options) {
  20. const extname = _path.default.extname(filename);
  21. const hasExtension = extname.length > 0;
  22. if (!hasExtension && contentType && _mime.default.getExtension(contentType)) {
  23. filename = filename + '.' + _mime.default.getExtension(contentType);
  24. } else if (hasExtension && !contentType) {
  25. contentType = _mime.default.getType(filename);
  26. }
  27. if (!this.options.preserveFileName) {
  28. filename = (0, _cryptoUtils.randomHexString)(32) + '_' + filename;
  29. }
  30. const location = await this.adapter.getFileLocation(config, filename);
  31. await this.adapter.createFile(filename, data, contentType, options);
  32. return {
  33. url: location,
  34. name: filename
  35. };
  36. }
  37. deleteFile(config, filename) {
  38. return this.adapter.deleteFile(filename);
  39. }
  40. getMetadata(filename) {
  41. if (typeof this.adapter.getMetadata === 'function') {
  42. return this.adapter.getMetadata(filename);
  43. }
  44. return Promise.resolve({});
  45. }
  46. /**
  47. * Find file references in REST-format object and adds the url key
  48. * with the current mount point and app id.
  49. * Object may be a single object or list of REST-format objects.
  50. */
  51. async expandFilesInObject(config, object) {
  52. if (object instanceof Array) {
  53. const promises = object.map(obj => this.expandFilesInObject(config, obj));
  54. await Promise.all(promises);
  55. return;
  56. }
  57. if (typeof object !== 'object') {
  58. return;
  59. }
  60. for (const key in object) {
  61. const fileObject = object[key];
  62. if (fileObject && fileObject['__type'] === 'File') {
  63. if (fileObject['url']) {
  64. continue;
  65. }
  66. const filename = fileObject['name'];
  67. // all filenames starting with "tfss-" should be from files.parsetfss.com
  68. // all filenames starting with a "-" seperated UUID should be from files.parse.com
  69. // all other filenames have been migrated or created from Parse Server
  70. if (config.fileKey === undefined) {
  71. fileObject['url'] = await this.adapter.getFileLocation(config, filename);
  72. } else {
  73. if (filename.indexOf('tfss-') === 0) {
  74. fileObject['url'] = 'http://files.parsetfss.com/' + config.fileKey + '/' + encodeURIComponent(filename);
  75. } else if (legacyFilesRegex.test(filename)) {
  76. fileObject['url'] = 'http://files.parse.com/' + config.fileKey + '/' + encodeURIComponent(filename);
  77. } else {
  78. fileObject['url'] = await this.adapter.getFileLocation(config, filename);
  79. }
  80. }
  81. }
  82. }
  83. }
  84. expectedAdapterType() {
  85. return _FilesAdapter.FilesAdapter;
  86. }
  87. handleFileStream(config, filename, req, res, contentType) {
  88. return this.adapter.handleFileStream(filename, req, res, contentType);
  89. }
  90. validateFilename(filename) {
  91. if (typeof this.adapter.validateFilename === 'function') {
  92. const error = this.adapter.validateFilename(filename);
  93. if (typeof error !== 'string') {
  94. return error;
  95. }
  96. return new Parse.Error(Parse.Error.INVALID_FILE_NAME, error);
  97. }
  98. return (0, _FilesAdapter.validateFilename)(filename);
  99. }
  100. }
  101. exports.FilesController = FilesController;
  102. var _default = exports.default = FilesController;
  103. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY3J5cHRvVXRpbHMiLCJyZXF1aXJlIiwiX0FkYXB0YWJsZUNvbnRyb2xsZXIiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX0ZpbGVzQWRhcHRlciIsIl9wYXRoIiwiX21pbWUiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJQYXJzZSIsImxlZ2FjeUZpbGVzUmVnZXgiLCJSZWdFeHAiLCJGaWxlc0NvbnRyb2xsZXIiLCJBZGFwdGFibGVDb250cm9sbGVyIiwiZ2V0RmlsZURhdGEiLCJjb25maWciLCJmaWxlbmFtZSIsImFkYXB0ZXIiLCJjcmVhdGVGaWxlIiwiZGF0YSIsImNvbnRlbnRUeXBlIiwib3B0aW9ucyIsImV4dG5hbWUiLCJwYXRoIiwiaGFzRXh0ZW5zaW9uIiwibGVuZ3RoIiwibWltZSIsImdldEV4dGVuc2lvbiIsImdldFR5cGUiLCJwcmVzZXJ2ZUZpbGVOYW1lIiwicmFuZG9tSGV4U3RyaW5nIiwibG9jYXRpb24iLCJnZXRGaWxlTG9jYXRpb24iLCJ1cmwiLCJuYW1lIiwiZGVsZXRlRmlsZSIsImdldE1ldGFkYXRhIiwiUHJvbWlzZSIsInJlc29sdmUiLCJleHBhbmRGaWxlc0luT2JqZWN0Iiwib2JqZWN0IiwiQXJyYXkiLCJwcm9taXNlcyIsIm1hcCIsIm9iaiIsImFsbCIsImtleSIsImZpbGVPYmplY3QiLCJmaWxlS2V5IiwidW5kZWZpbmVkIiwiaW5kZXhPZiIsImVuY29kZVVSSUNvbXBvbmVudCIsInRlc3QiLCJleHBlY3RlZEFkYXB0ZXJUeXBlIiwiRmlsZXNBZGFwdGVyIiwiaGFuZGxlRmlsZVN0cmVhbSIsInJlcSIsInJlcyIsInZhbGlkYXRlRmlsZW5hbWUiLCJlcnJvciIsIkVycm9yIiwiSU5WQUxJRF9GSUxFX05BTUUiLCJleHBvcnRzIiwiX2RlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvQ29udHJvbGxlcnMvRmlsZXNDb250cm9sbGVyLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIEZpbGVzQ29udHJvbGxlci5qc1xuaW1wb3J0IHsgcmFuZG9tSGV4U3RyaW5nIH0gZnJvbSAnLi4vY3J5cHRvVXRpbHMnO1xuaW1wb3J0IEFkYXB0YWJsZUNvbnRyb2xsZXIgZnJvbSAnLi9BZGFwdGFibGVDb250cm9sbGVyJztcbmltcG9ydCB7IHZhbGlkYXRlRmlsZW5hbWUsIEZpbGVzQWRhcHRlciB9IGZyb20gJy4uL0FkYXB0ZXJzL0ZpbGVzL0ZpbGVzQWRhcHRlcic7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBtaW1lIGZyb20gJ21pbWUnO1xuY29uc3QgUGFyc2UgPSByZXF1aXJlKCdwYXJzZScpLlBhcnNlO1xuXG5jb25zdCBsZWdhY3lGaWxlc1JlZ2V4ID0gbmV3IFJlZ0V4cChcbiAgJ15bMC05YS1mQS1GXXs4fS1bMC05YS1mQS1GXXs0fS1bMC05YS1mQS1GXXs0fS1bMC05YS1mQS1GXXs0fS1bMC05YS1mQS1GXXsxMn0tLionXG4pO1xuXG5leHBvcnQgY2xhc3MgRmlsZXNDb250cm9sbGVyIGV4dGVuZHMgQWRhcHRhYmxlQ29udHJvbGxlciB7XG4gIGdldEZpbGVEYXRhKGNvbmZpZywgZmlsZW5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyLmdldEZpbGVEYXRhKGZpbGVuYW1lKTtcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZUZpbGUoY29uZmlnLCBmaWxlbmFtZSwgZGF0YSwgY29udGVudFR5cGUsIG9wdGlvbnMpIHtcbiAgICBjb25zdCBleHRuYW1lID0gcGF0aC5leHRuYW1lKGZpbGVuYW1lKTtcblxuICAgIGNvbnN0IGhhc0V4dGVuc2lvbiA9IGV4dG5hbWUubGVuZ3RoID4gMDtcblxuICAgIGlmICghaGFzRXh0ZW5zaW9uICYmIGNvbnRlbnRUeXBlICYmIG1pbWUuZ2V0RXh0ZW5zaW9uKGNvbnRlbnRUeXBlKSkge1xuICAgICAgZmlsZW5hbWUgPSBmaWxlbmFtZSArICcuJyArIG1pbWUuZ2V0RXh0ZW5zaW9uKGNvbnRlbnRUeXBlKTtcbiAgICB9IGVsc2UgaWYgKGhhc0V4dGVuc2lvbiAmJiAhY29udGVudFR5cGUpIHtcbiAgICAgIGNvbnRlbnRUeXBlID0gbWltZS5nZXRUeXBlKGZpbGVuYW1lKTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMub3B0aW9ucy5wcmVzZXJ2ZUZpbGVOYW1lKSB7XG4gICAgICBmaWxlbmFtZSA9IHJhbmRvbUhleFN0cmluZygzMikgKyAnXycgKyBmaWxlbmFtZTtcbiAgICB9XG5cbiAgICBjb25zdCBsb2NhdGlvbiA9IGF3YWl0IHRoaXMuYWRhcHRlci5nZXRGaWxlTG9jYXRpb24oY29uZmlnLCBmaWxlbmFtZSk7XG4gICAgYXdhaXQgdGhpcy5hZGFwdGVyLmNyZWF0ZUZpbGUoZmlsZW5hbWUsIGRhdGEsIGNvbnRlbnRUeXBlLCBvcHRpb25zKTtcbiAgICByZXR1cm4ge1xuICAgICAgdXJsOiBsb2NhdGlvbixcbiAgICAgIG5hbWU6IGZpbGVuYW1lLFxuICAgIH1cbiAgfVxuXG4gIGRlbGV0ZUZpbGUoY29uZmlnLCBmaWxlbmFtZSkge1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIuZGVsZXRlRmlsZShmaWxlbmFtZSk7XG4gIH1cblxuICBnZXRNZXRhZGF0YShmaWxlbmFtZSkge1xuICAgIGlmICh0eXBlb2YgdGhpcy5hZGFwdGVyLmdldE1ldGFkYXRhID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gdGhpcy5hZGFwdGVyLmdldE1ldGFkYXRhKGZpbGVuYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBmaWxlIHJlZmVyZW5jZXMgaW4gUkVTVC1mb3JtYXQgb2JqZWN0IGFuZCBhZGRzIHRoZSB1cmwga2V5XG4gICAqIHdpdGggdGhlIGN1cnJlbnQgbW91bnQgcG9pbnQgYW5kIGFwcCBpZC5cbiAgICogT2JqZWN0IG1heSBiZSBhIHNpbmdsZSBvYmplY3Qgb3IgbGlzdCBvZiBSRVNULWZvcm1hdCBvYmplY3RzLlxuICAgKi9cbiAgYXN5bmMgZXhwYW5kRmlsZXNJbk9iamVjdChjb25maWcsIG9iamVjdCkge1xuICAgIGlmIChvYmplY3QgaW5zdGFuY2VvZiBBcnJheSkge1xuICAgICAgY29uc3QgcHJvbWlzZXMgPSBvYmplY3QubWFwKG9iaiA9PiB0aGlzLmV4cGFuZEZpbGVzSW5PYmplY3QoY29uZmlnLCBvYmopKTtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBvYmplY3QgIT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZvciAoY29uc3Qga2V5IGluIG9iamVjdCkge1xuICAgICAgY29uc3QgZmlsZU9iamVjdCA9IG9iamVjdFtrZXldO1xuICAgICAgaWYgKGZpbGVPYmplY3QgJiYgZmlsZU9iamVjdFsnX190eXBlJ10gPT09ICdGaWxlJykge1xuICAgICAgICBpZiAoZmlsZU9iamVjdFsndXJsJ10pIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBmaWxlbmFtZSA9IGZpbGVPYmplY3RbJ25hbWUnXTtcbiAgICAgICAgLy8gYWxsIGZpbGVuYW1lcyBzdGFydGluZyB3aXRoIFwidGZzcy1cIiBzaG91bGQgYmUgZnJvbSBmaWxlcy5wYXJzZXRmc3MuY29tXG4gICAgICAgIC8vIGFsbCBmaWxlbmFtZXMgc3RhcnRpbmcgd2l0aCBhIFwiLVwiIHNlcGVyYXRlZCBVVUlEIHNob3VsZCBiZSBmcm9tIGZpbGVzLnBhcnNlLmNvbVxuICAgICAgICAvLyBhbGwgb3RoZXIgZmlsZW5hbWVzIGhhdmUgYmVlbiBtaWdyYXRlZCBvciBjcmVhdGVkIGZyb20gUGFyc2UgU2VydmVyXG4gICAgICAgIGlmIChjb25maWcuZmlsZUtleSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgZmlsZU9iamVjdFsndXJsJ10gPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZ2V0RmlsZUxvY2F0aW9uKGNvbmZpZywgZmlsZW5hbWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlmIChmaWxlbmFtZS5pbmRleE9mKCd0ZnNzLScpID09PSAwKSB7XG4gICAgICAgICAgICBmaWxlT2JqZWN0Wyd1cmwnXSA9XG4gICAgICAgICAgICAgICdodHRwOi8vZmlsZXMucGFyc2V0ZnNzLmNvbS8nICsgY29uZmlnLmZpbGVLZXkgKyAnLycgKyBlbmNvZGVVUklDb21wb25lbnQoZmlsZW5hbWUpO1xuICAgICAgICAgIH0gZWxzZSBpZiAobGVnYWN5RmlsZXNSZWdleC50ZXN0KGZpbGVuYW1lKSkge1xuICAgICAgICAgICAgZmlsZU9iamVjdFsndXJsJ10gPVxuICAgICAgICAgICAgICAnaHR0cDovL2ZpbGVzLnBhcnNlLmNvbS8nICsgY29uZmlnLmZpbGVLZXkgKyAnLycgKyBlbmNvZGVVUklDb21wb25lbnQoZmlsZW5hbWUpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmaWxlT2JqZWN0Wyd1cmwnXSA9IGF3YWl0IHRoaXMuYWRhcHRlci5nZXRGaWxlTG9jYXRpb24oY29uZmlnLCBmaWxlbmFtZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZXhwZWN0ZWRBZGFwdGVyVHlwZSgpIHtcbiAgICByZXR1cm4gRmlsZXNBZGFwdGVyO1xuICB9XG5cbiAgaGFuZGxlRmlsZVN0cmVhbShjb25maWcsIGZpbGVuYW1lLCByZXEsIHJlcywgY29udGVudFR5cGUpIHtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyLmhhbmRsZUZpbGVTdHJlYW0oZmlsZW5hbWUsIHJlcSwgcmVzLCBjb250ZW50VHlwZSk7XG4gIH1cblxuICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKSB7XG4gICAgaWYgKHR5cGVvZiB0aGlzLmFkYXB0ZXIudmFsaWRhdGVGaWxlbmFtZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgY29uc3QgZXJyb3IgPSB0aGlzLmFkYXB0ZXIudmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICBpZiAodHlwZW9mIGVycm9yICE9PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gZXJyb3I7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfRklMRV9OQU1FLCBlcnJvcik7XG4gICAgfVxuICAgIHJldHVybiB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBGaWxlc0NvbnRyb2xsZXI7XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLElBQUFBLFlBQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLG9CQUFBLEdBQUFDLHNCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBRyxhQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxLQUFBLEdBQUFGLHNCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBSyxLQUFBLEdBQUFILHNCQUFBLENBQUFGLE9BQUE7QUFBd0IsU0FBQUUsdUJBQUFJLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVBQUFGLENBQUE7QUFMeEI7O0FBTUEsTUFBTUcsS0FBSyxHQUFHVCxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUNTLEtBQUs7QUFFcEMsTUFBTUMsZ0JBQWdCLEdBQUcsSUFBSUMsTUFBTSxDQUNqQyxpRkFDRixDQUFDO0FBRU0sTUFBTUMsZUFBZSxTQUFTQyw0QkFBbUIsQ0FBQztFQUN2REMsV0FBV0EsQ0FBQ0MsTUFBTSxFQUFFQyxRQUFRLEVBQUU7SUFDNUIsT0FBTyxJQUFJLENBQUNDLE9BQU8sQ0FBQ0gsV0FBVyxDQUFDRSxRQUFRLENBQUM7RUFDM0M7RUFFQSxNQUFNRSxVQUFVQSxDQUFDSCxNQUFNLEVBQUVDLFFBQVEsRUFBRUcsSUFBSSxFQUFFQyxXQUFXLEVBQUVDLE9BQU8sRUFBRTtJQUM3RCxNQUFNQyxPQUFPLEdBQUdDLGFBQUksQ0FBQ0QsT0FBTyxDQUFDTixRQUFRLENBQUM7SUFFdEMsTUFB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