ParseFile.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  7. var _ParseFileEncode = require("./ParseFileEncode");
  8. function _interopRequireDefault(obj) {
  9. return obj && obj.__esModule ? obj : {
  10. default: obj
  11. };
  12. }
  13. function ownKeys(object, enumerableOnly) {
  14. var keys = Object.keys(object);
  15. if (Object.getOwnPropertySymbols) {
  16. var symbols = Object.getOwnPropertySymbols(object);
  17. enumerableOnly && (symbols = symbols.filter(function (sym) {
  18. return Object.getOwnPropertyDescriptor(object, sym).enumerable;
  19. })), keys.push.apply(keys, symbols);
  20. }
  21. return keys;
  22. }
  23. function _objectSpread(target) {
  24. for (var i = 1; i < arguments.length; i++) {
  25. var source = null != arguments[i] ? arguments[i] : {};
  26. i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
  27. _defineProperty(target, key, source[key]);
  28. }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
  29. Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
  30. });
  31. }
  32. return target;
  33. }
  34. function _defineProperty(obj, key, value) {
  35. if (key in obj) {
  36. Object.defineProperty(obj, key, {
  37. value: value,
  38. enumerable: true,
  39. configurable: true,
  40. writable: true
  41. });
  42. } else {
  43. obj[key] = value;
  44. }
  45. return obj;
  46. }
  47. const ParseError = require('./ParseError').default;
  48. /*:: type Base64 = { base64: string };*/
  49. /*:: type Uri = { uri: string };*/
  50. /*:: type FileData = Array<number> | Base64 | Blob | Uri;*/
  51. /*:: export type FileSource =
  52. | {
  53. format: 'file',
  54. file: Blob,
  55. type: string,
  56. }
  57. | {
  58. format: 'base64',
  59. base64: string,
  60. type: string,
  61. }
  62. | {
  63. format: 'uri',
  64. uri: string,
  65. type: string,
  66. };*/
  67. const dataUriRegexp = /^data:([a-zA-Z]+\/[-a-zA-Z0-9+.]+)(;charset=[a-zA-Z0-9\-/]*)?;base64,/;
  68. /**
  69. * A Parse.File is a local representation of a file that is saved to the Parse
  70. * cloud.
  71. *
  72. * @alias Parse.File
  73. */
  74. class ParseFile {
  75. /**
  76. * @param name {String} The file's name. This will be prefixed by a unique
  77. * value once the file has finished saving. The file name must begin with
  78. * an alphanumeric character, and consist of alphanumeric characters,
  79. * periods, spaces, underscores, or dashes.
  80. * @param data {Array} The data for the file, as either:
  81. * 1. an Array of byte value Numbers, or
  82. * 2. an Object like { base64: "..." } with a base64-encoded String.
  83. * 3. an Object like { uri: "..." } with a uri String.
  84. * 4. a File object selected with a file upload control. (3) only works
  85. * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+.
  86. * For example:
  87. * <pre>
  88. * var fileUploadControl = $("#profilePhotoFileUpload")[0];
  89. * if (fileUploadControl.files.length > 0) {
  90. * var file = fileUploadControl.files[0];
  91. * var name = "photo.jpg";
  92. * var parseFile = new Parse.File(name, file);
  93. * parseFile.save().then(function() {
  94. * // The file has been saved to Parse.
  95. * }, function(error) {
  96. * // The file either could not be read, or could not be saved to Parse.
  97. * });
  98. * }</pre>
  99. * @param type {String} Optional Content-Type header to use for the file. If
  100. * this is omitted, the content type will be inferred from the name's
  101. * extension.
  102. * @param metadata {Object} Optional key value pairs to be stored with file object
  103. * @param tags {Object} Optional key value pairs to be stored with file object
  104. */
  105. constructor(name
  106. /*: string*/
  107. , data
  108. /*:: ?: FileData*/
  109. , type
  110. /*:: ?: string*/
  111. , metadata
  112. /*:: ?: Object*/
  113. , tags
  114. /*:: ?: Object*/
  115. ) {
  116. _defineProperty(this, "_name", void 0);
  117. _defineProperty(this, "_url", void 0);
  118. _defineProperty(this, "_hash", void 0);
  119. _defineProperty(this, "_ipfs", void 0);
  120. _defineProperty(this, "_source", void 0);
  121. _defineProperty(this, "_previousSave", void 0);
  122. _defineProperty(this, "_data", void 0);
  123. _defineProperty(this, "_requestTask", void 0);
  124. _defineProperty(this, "_metadata", void 0);
  125. _defineProperty(this, "_tags", void 0);
  126. const specifiedType = type || '';
  127. this._name = name;
  128. this._metadata = metadata || {};
  129. this._tags = tags || {};
  130. if (data !== undefined) {
  131. if (Array.isArray(data)) {
  132. this._data = ParseFile.encodeBase64(data);
  133. this._source = {
  134. format: 'base64',
  135. base64: this._data,
  136. type: specifiedType
  137. };
  138. } else if (typeof Blob !== 'undefined' && data instanceof Blob) {
  139. this._source = {
  140. format: 'file',
  141. file: data,
  142. type: specifiedType
  143. };
  144. } else if (data && typeof data.uri === 'string' && data.uri !== undefined) {
  145. this._source = {
  146. format: 'uri',
  147. uri: data.uri,
  148. type: specifiedType
  149. };
  150. } else if (data && typeof data.base64 === 'string') {
  151. const {
  152. base64
  153. } = data;
  154. const commaIndex = base64.indexOf(',');
  155. if (commaIndex !== -1) {
  156. const matches = dataUriRegexp.exec(base64.slice(0, commaIndex + 1)); // if data URI with type and charset, there will be 4 matches.
  157. this._data = base64.slice(commaIndex + 1);
  158. this._source = {
  159. format: 'base64',
  160. base64: this._data,
  161. type: matches[1]
  162. };
  163. } else {
  164. this._data = base64;
  165. this._source = {
  166. format: 'base64',
  167. base64: base64,
  168. type: specifiedType
  169. };
  170. }
  171. } else {
  172. throw new TypeError('Cannot create a Parse.File with that data.');
  173. }
  174. }
  175. }
  176. /**
  177. * Return the data for the file, downloading it if not already present.
  178. * Data is present if initialized with Byte Array, Base64 or Saved with Uri.
  179. * Data is cleared if saved with File object selected with a file upload control
  180. *
  181. * @returns {Promise} Promise that is resolve with base64 data
  182. */
  183. async getData()
  184. /*: Promise<String>*/
  185. {
  186. if (this._data) {
  187. return this._data;
  188. }
  189. if (!this._url) {
  190. throw new Error('Cannot retrieve data for unsaved ParseFile.');
  191. }
  192. const controller = _CoreManager.default.getFileController();
  193. const result = await controller.download(this._url, {
  194. requestTask: task => this._requestTask = task
  195. });
  196. this._data = result.base64;
  197. return this._data;
  198. }
  199. /**
  200. * Gets the name of the file. Before save is called, this is the filename
  201. * given by the user. After save is called, that name gets prefixed with a
  202. * unique identifier.
  203. *
  204. * @returns {string}
  205. */
  206. name()
  207. /*: string*/
  208. {
  209. return this._name;
  210. }
  211. /**
  212. * Gets the url of the file. It is only available after you save the file or
  213. * after you get the file from a Parse.Object.
  214. *
  215. * @param {object} options An object to specify url options
  216. * @returns {string}
  217. */
  218. url(options
  219. /*:: ?: { forceSecure?: boolean }*/
  220. )
  221. /*: ?string*/
  222. {
  223. options = options || {};
  224. if (!this._url) {
  225. return;
  226. }
  227. if (options.forceSecure) {
  228. return this._url.replace(/^http:\/\//i, 'https://');
  229. }
  230. return this._url;
  231. }
  232. ipfs() {
  233. return this._ipfs;
  234. }
  235. hash() {
  236. return this._hash;
  237. }
  238. /**
  239. * Gets the metadata of the file.
  240. *
  241. * @returns {object}
  242. */
  243. metadata()
  244. /*: Object*/
  245. {
  246. return this._metadata;
  247. }
  248. /**
  249. * Gets the tags of the file.
  250. *
  251. * @returns {object}
  252. */
  253. tags()
  254. /*: Object*/
  255. {
  256. return this._tags;
  257. }
  258. /**
  259. * Saves the file to the Parse cloud.
  260. *
  261. * @param {object} options
  262. * * Valid options are:<ul>
  263. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  264. * be used for this request.
  265. * <li>sessionToken: A valid session token, used for making a request on
  266. * behalf of a specific user.
  267. * <li>progress: In Browser only, callback for upload progress. For example:
  268. * <pre>
  269. * let parseFile = new Parse.File(name, file);
  270. * parseFile.save({
  271. * progress: (progressValue, loaded, total, { type }) => {
  272. * if (type === "upload" && progressValue !== null) {
  273. * // Update the UI using progressValue
  274. * }
  275. * }
  276. * });
  277. * </pre>
  278. * </ul>
  279. * @returns {Promise} Promise that is resolved when the save finishes.
  280. */
  281. save(options
  282. /*:: ?: FullOptions*/
  283. ) {
  284. options = options || {};
  285. options.requestTask = task => this._requestTask = task;
  286. options.metadata = this._metadata;
  287. options.tags = this._tags;
  288. const controller = _CoreManager.default.getFileController();
  289. if (!this._previousSave) {
  290. if (this._source.format === 'file') {
  291. this._previousSave = controller.saveFile(this._name, this._source, options).then(res => {
  292. this._name = res.name;
  293. this._url = res.url;
  294. this._hash = res.hash;
  295. this._ipfs = res.ipfs;
  296. this._data = null;
  297. this._requestTask = null;
  298. return this;
  299. });
  300. } else if (this._source.format === 'uri') {
  301. this._previousSave = controller.download(this._source.uri, options).then(result => {
  302. if (!(result && result.base64)) {
  303. return {};
  304. }
  305. const newSource = {
  306. format: 'base64',
  307. base64: result.base64,
  308. type: result.contentType
  309. };
  310. this._data = result.base64;
  311. this._requestTask = null;
  312. return controller.saveBase64(this._name, newSource, options);
  313. }).then(res => {
  314. this._name = res.name;
  315. this._url = res.url;
  316. this._hash = res.hash;
  317. this._ipfs = res.ipfs;
  318. this._requestTask = null;
  319. return this;
  320. });
  321. } else {
  322. this._previousSave = controller.saveBase64(this._name, this._source, options).then(res => {
  323. this._name = res.name;
  324. this._url = res.url;
  325. this._hash = res.hash;
  326. this._ipfs = res.ipfs;
  327. this._requestTask = null;
  328. return this;
  329. });
  330. }
  331. }
  332. if (this._previousSave) {
  333. return this._previousSave;
  334. }
  335. }
  336. saveIPFS(options
  337. /*:: ?: FullOptions*/
  338. ) {
  339. return this.save(_objectSpread(_objectSpread({}, options), {}, {
  340. ipfs: true
  341. }));
  342. }
  343. /**
  344. * Aborts the request if it has already been sent.
  345. */
  346. cancel() {
  347. if (this._requestTask && typeof this._requestTask.abort === 'function') {
  348. this._requestTask.abort();
  349. }
  350. this._requestTask = null;
  351. }
  352. /**
  353. * Deletes the file from the Parse cloud.
  354. * In Cloud Code and Node only with Master Key.
  355. *
  356. * @param {object} options
  357. * * Valid options are:<ul>
  358. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  359. * be used for this request.
  360. * <pre>
  361. * @returns {Promise} Promise that is resolved when the delete finishes.
  362. */
  363. destroy(options
  364. /*:: ?: FullOptions*/
  365. = {}) {
  366. if (!this._name) {
  367. throw new ParseError(ParseError.FILE_DELETE_UNNAMED_ERROR, 'Cannot delete an unnamed file.');
  368. }
  369. const destroyOptions = {
  370. useMasterKey: true
  371. };
  372. if (options.hasOwnProperty('useMasterKey')) {
  373. destroyOptions.useMasterKey = options.useMasterKey;
  374. }
  375. const controller = _CoreManager.default.getFileController();
  376. return controller.deleteFile(this._name, destroyOptions).then(() => {
  377. this._data = null;
  378. this._requestTask = null;
  379. return this;
  380. });
  381. }
  382. toJSON()
  383. /*: { name: ?string, url: ?string }*/
  384. {
  385. return {
  386. __type: 'File',
  387. name: this._name,
  388. url: this._url,
  389. ipfs: this._ipfs,
  390. hash: this._hash
  391. };
  392. }
  393. equals(other
  394. /*: mixed*/
  395. )
  396. /*: boolean*/
  397. {
  398. if (this === other) {
  399. return true;
  400. } // Unsaved Files are never equal, since they will be saved to different URLs
  401. return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined';
  402. }
  403. /**
  404. * Sets metadata to be saved with file object. Overwrites existing metadata
  405. *
  406. * @param {object} metadata Key value pairs to be stored with file object
  407. */
  408. setMetadata(metadata
  409. /*: any*/
  410. ) {
  411. if (metadata && typeof metadata === 'object') {
  412. Object.keys(metadata).forEach(key => {
  413. this.addMetadata(key, metadata[key]);
  414. });
  415. }
  416. }
  417. /**
  418. * Sets metadata to be saved with file object. Adds to existing metadata.
  419. *
  420. * @param {string} key key to store the metadata
  421. * @param {*} value metadata
  422. */
  423. addMetadata(key
  424. /*: string*/
  425. , value
  426. /*: any*/
  427. ) {
  428. if (typeof key === 'string') {
  429. this._metadata[key] = value;
  430. }
  431. }
  432. /**
  433. * Sets tags to be saved with file object. Overwrites existing tags
  434. *
  435. * @param {object} tags Key value pairs to be stored with file object
  436. */
  437. setTags(tags
  438. /*: any*/
  439. ) {
  440. if (tags && typeof tags === 'object') {
  441. Object.keys(tags).forEach(key => {
  442. this.addTag(key, tags[key]);
  443. });
  444. }
  445. }
  446. /**
  447. * Sets tags to be saved with file object. Adds to existing tags.
  448. *
  449. * @param {string} key key to store tags
  450. * @param {*} value tag
  451. */
  452. addTag(key
  453. /*: string*/
  454. , value
  455. /*: string*/
  456. ) {
  457. if (typeof key === 'string') {
  458. this._tags[key] = value;
  459. }
  460. }
  461. static fromJSON(obj)
  462. /*: ParseFile*/
  463. {
  464. if (obj.__type !== 'File') {
  465. throw new TypeError('JSON object does not represent a ParseFile');
  466. }
  467. const file = new ParseFile(obj.name);
  468. file._url = obj.url;
  469. file._hash = obj.hash;
  470. file._ipfs = obj.ipfs;
  471. return file;
  472. }
  473. static encodeBase64(bytes
  474. /*: Array<number>*/
  475. )
  476. /*: string*/
  477. {
  478. return (0, _ParseFileEncode.encodeBase64)(bytes);
  479. }
  480. }
  481. _CoreManager.default.setFileController(require('./ParseFileController.default'));
  482. var _default = ParseFile;
  483. exports.default = _default;
  484. exports.b64Digit = _ParseFileEncode.b64Digit;