You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

shareitemmodel.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. /*
  2. * Copyright (c) 2015
  3. *
  4. * This file is licensed under the Affero General Public License version 3
  5. * or later.
  6. *
  7. * See the COPYING-README file.
  8. *
  9. */
  10. (function() {
  11. if(!OC.Share) {
  12. OC.Share = {};
  13. OC.Share.Types = {};
  14. }
  15. /**
  16. * @typedef {object} OC.Share.Types.LinkShareInfo
  17. * @property {bool} isLinkShare
  18. * @property {string} token
  19. * @property {string|null} password
  20. * @property {string} link
  21. * @property {number} permissions
  22. * @property {Date} expiration
  23. * @property {number} stime share time
  24. */
  25. /**
  26. * @typedef {object} OC.Share.Types.Reshare
  27. * @property {string} uid_owner
  28. * @property {number} share_type
  29. * @property {string} share_with
  30. * @property {string} displayname_owner
  31. * @property {number} permissions
  32. */
  33. /**
  34. * @typedef {object} OC.Share.Types.ShareInfo
  35. * @property {number} share_type
  36. * @property {number} permissions
  37. * @property {number} file_source optional
  38. * @property {number} item_source
  39. * @property {string} token
  40. * @property {string} share_with
  41. * @property {string} share_with_displayname
  42. * @property {string} mail_send
  43. * @property {Date} expiration optional?
  44. * @property {number} stime optional?
  45. * @property {string} uid_owner
  46. */
  47. /**
  48. * @typedef {object} OC.Share.Types.ShareItemInfo
  49. * @property {OC.Share.Types.Reshare} reshare
  50. * @property {OC.Share.Types.ShareInfo[]} shares
  51. * @property {OC.Share.Types.LinkShareInfo|undefined} linkShare
  52. */
  53. /**
  54. * These properties are sometimes returned by the server as strings instead
  55. * of integers, so we need to convert them accordingly...
  56. */
  57. var SHARE_RESPONSE_INT_PROPS = [
  58. 'id', 'file_parent', 'mail_send', 'file_source', 'item_source', 'permissions',
  59. 'storage', 'share_type', 'parent', 'stime'
  60. ];
  61. /**
  62. * @class OCA.Share.ShareItemModel
  63. * @classdesc
  64. *
  65. * Represents the GUI of the share dialogue
  66. *
  67. * // FIXME: use OC Share API once #17143 is done
  68. *
  69. * // TODO: this really should be a collection of share item models instead,
  70. * where the link share is one of them
  71. */
  72. var ShareItemModel = OC.Backbone.Model.extend({
  73. /**
  74. * @type share id of the link share, if applicable
  75. */
  76. _linkShareId: null,
  77. initialize: function(attributes, options) {
  78. if(!_.isUndefined(options.configModel)) {
  79. this.configModel = options.configModel;
  80. }
  81. if(!_.isUndefined(options.fileInfoModel)) {
  82. /** @type {OC.Files.FileInfo} **/
  83. this.fileInfoModel = options.fileInfoModel;
  84. }
  85. _.bindAll(this, 'addShare');
  86. },
  87. defaults: {
  88. allowPublicUploadStatus: false,
  89. permissions: 0,
  90. linkShare: {}
  91. },
  92. /**
  93. * Saves the current link share information.
  94. *
  95. * This will trigger an ajax call and refetch the model afterwards.
  96. *
  97. * TODO: this should be a separate model
  98. */
  99. saveLinkShare: function(attributes, options) {
  100. options = options || {};
  101. attributes = _.extend({}, attributes);
  102. var shareId = null;
  103. var call;
  104. // oh yeah...
  105. if (attributes.expiration) {
  106. attributes.expireDate = attributes.expiration;
  107. delete attributes.expiration;
  108. }
  109. if (this.get('linkShare') && this.get('linkShare').isLinkShare) {
  110. shareId = this.get('linkShare').id;
  111. // note: update can only update a single value at a time
  112. call = this.updateShare(shareId, attributes, options);
  113. } else {
  114. attributes = _.defaults(attributes, {
  115. password: '',
  116. passwordChanged: false,
  117. permissions: OC.PERMISSION_READ,
  118. expireDate: this.configModel.getDefaultExpirationDateString(),
  119. shareType: OC.Share.SHARE_TYPE_LINK
  120. });
  121. call = this.addShare(attributes, options);
  122. }
  123. return call;
  124. },
  125. removeLinkShare: function() {
  126. if (this.get('linkShare')) {
  127. return this.removeShare(this.get('linkShare').id);
  128. }
  129. },
  130. addShare: function(attributes, options) {
  131. var shareType = attributes.shareType;
  132. options = options || {};
  133. attributes = _.extend({}, attributes);
  134. // Default permissions are Edit (CRUD) and Share
  135. // Check if these permissions are possible
  136. var permissions = OC.PERMISSION_READ;
  137. if (this.updatePermissionPossible()) {
  138. permissions = permissions | OC.PERMISSION_UPDATE;
  139. }
  140. if (this.createPermissionPossible()) {
  141. permissions = permissions | OC.PERMISSION_CREATE;
  142. }
  143. if (this.deletePermissionPossible()) {
  144. permissions = permissions | OC.PERMISSION_DELETE;
  145. }
  146. if (this.configModel.get('isResharingAllowed') && (this.sharePermissionPossible())) {
  147. permissions = permissions | OC.PERMISSION_SHARE;
  148. }
  149. attributes.permissions = permissions;
  150. if (_.isUndefined(attributes.path)) {
  151. attributes.path = this.fileInfoModel.getFullPath();
  152. }
  153. var self = this;
  154. return $.ajax({
  155. type: 'POST',
  156. url: this._getUrl('shares'),
  157. data: attributes,
  158. dataType: 'json'
  159. }).done(function() {
  160. self.fetch().done(function() {
  161. if (_.isFunction(options.success)) {
  162. options.success(self);
  163. }
  164. });
  165. }).fail(function(xhr) {
  166. var msg = t('core', 'Error');
  167. var result = xhr.responseJSON;
  168. if (result.ocs && result.ocs.meta) {
  169. msg = result.ocs.meta.message;
  170. }
  171. if (_.isFunction(options.error)) {
  172. options.error(self, msg);
  173. } else {
  174. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  175. }
  176. });
  177. },
  178. updateShare: function(shareId, attrs, options) {
  179. var self = this;
  180. options = options || {};
  181. return $.ajax({
  182. type: 'PUT',
  183. url: this._getUrl('shares/' + encodeURIComponent(shareId)),
  184. data: attrs,
  185. dataType: 'json'
  186. }).done(function() {
  187. self.fetch({
  188. success: function() {
  189. if (_.isFunction(options.success)) {
  190. options.success(self);
  191. }
  192. }
  193. });
  194. }).fail(function(xhr) {
  195. var msg = t('core', 'Error');
  196. var result = xhr.responseJSON;
  197. if (result.ocs && result.ocs.meta) {
  198. msg = result.ocs.meta.message;
  199. }
  200. if (_.isFunction(options.error)) {
  201. options.error(self, msg);
  202. } else {
  203. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  204. }
  205. });
  206. },
  207. /**
  208. * Deletes the share with the given id
  209. *
  210. * @param {int} shareId share id
  211. * @return {jQuery}
  212. */
  213. removeShare: function(shareId, options) {
  214. var self = this;
  215. options = options || {};
  216. return $.ajax({
  217. type: 'DELETE',
  218. url: this._getUrl('shares/' + encodeURIComponent(shareId)),
  219. }).done(function() {
  220. self.fetch({
  221. success: function() {
  222. if (_.isFunction(options.success)) {
  223. options.success(self);
  224. }
  225. }
  226. });
  227. }).fail(function(xhr) {
  228. var msg = t('core', 'Error');
  229. var result = xhr.responseJSON;
  230. if (result.ocs && result.ocs.meta) {
  231. msg = result.ocs.meta.message;
  232. }
  233. if (_.isFunction(options.error)) {
  234. options.error(self, msg);
  235. } else {
  236. OC.dialogs.alert(msg, t('core', 'Error removing share'));
  237. }
  238. });
  239. },
  240. /**
  241. * @returns {boolean}
  242. */
  243. isPublicUploadAllowed: function() {
  244. return this.get('allowPublicUploadStatus');
  245. },
  246. /**
  247. * @returns {boolean}
  248. */
  249. isFolder: function() {
  250. return this.get('itemType') === 'folder';
  251. },
  252. /**
  253. * @returns {boolean}
  254. */
  255. isFile: function() {
  256. return this.get('itemType') === 'file';
  257. },
  258. /**
  259. * whether this item has reshare information
  260. * @returns {boolean}
  261. */
  262. hasReshare: function() {
  263. var reshare = this.get('reshare');
  264. return _.isObject(reshare) && !_.isUndefined(reshare.uid_owner);
  265. },
  266. /**
  267. * whether this item has user share information
  268. * @returns {boolean}
  269. */
  270. hasUserShares: function() {
  271. return this.getSharesWithCurrentItem().length > 0;
  272. },
  273. /**
  274. * Returns whether this item has a link share
  275. *
  276. * @return {bool} true if a link share exists, false otherwise
  277. */
  278. hasLinkShare: function() {
  279. var linkShare = this.get('linkShare');
  280. if (linkShare && linkShare.isLinkShare) {
  281. return true;
  282. }
  283. return false;
  284. },
  285. /**
  286. * @returns {string}
  287. */
  288. getReshareOwner: function() {
  289. return this.get('reshare').uid_owner;
  290. },
  291. /**
  292. * @returns {string}
  293. */
  294. getReshareOwnerDisplayname: function() {
  295. return this.get('reshare').displayname_owner;
  296. },
  297. /**
  298. * @returns {string}
  299. */
  300. getReshareWith: function() {
  301. return this.get('reshare').share_with;
  302. },
  303. /**
  304. * @returns {number}
  305. */
  306. getReshareType: function() {
  307. return this.get('reshare').share_type;
  308. },
  309. /**
  310. * Returns all share entries that only apply to the current item
  311. * (file/folder)
  312. *
  313. * @return {Array.<OC.Share.Types.ShareInfo>}
  314. */
  315. getSharesWithCurrentItem: function() {
  316. var shares = this.get('shares') || [];
  317. var fileId = this.fileInfoModel.get('id');
  318. return _.filter(shares, function(share) {
  319. return share.item_source === fileId;
  320. });
  321. },
  322. /**
  323. * @param shareIndex
  324. * @returns {string}
  325. */
  326. getShareWith: function(shareIndex) {
  327. /** @type OC.Share.Types.ShareInfo **/
  328. var share = this.get('shares')[shareIndex];
  329. if(!_.isObject(share)) {
  330. throw "Unknown Share";
  331. }
  332. return share.share_with;
  333. },
  334. /**
  335. * @param shareIndex
  336. * @returns {string}
  337. */
  338. getShareWithDisplayName: function(shareIndex) {
  339. /** @type OC.Share.Types.ShareInfo **/
  340. var share = this.get('shares')[shareIndex];
  341. if(!_.isObject(share)) {
  342. throw "Unknown Share";
  343. }
  344. return share.share_with_displayname;
  345. },
  346. getShareType: function(shareIndex) {
  347. /** @type OC.Share.Types.ShareInfo **/
  348. var share = this.get('shares')[shareIndex];
  349. if(!_.isObject(share)) {
  350. throw "Unknown Share";
  351. }
  352. return share.share_type;
  353. },
  354. /**
  355. * whether a share from shares has the requested permission
  356. *
  357. * @param {number} shareIndex
  358. * @param {number} permission
  359. * @returns {boolean}
  360. * @private
  361. */
  362. _shareHasPermission: function(shareIndex, permission) {
  363. /** @type OC.Share.Types.ShareInfo **/
  364. var share = this.get('shares')[shareIndex];
  365. if(!_.isObject(share)) {
  366. throw "Unknown Share";
  367. }
  368. return (share.permissions & permission) === permission;
  369. },
  370. notificationMailWasSent: function(shareIndex) {
  371. /** @type OC.Share.Types.ShareInfo **/
  372. var share = this.get('shares')[shareIndex];
  373. if(!_.isObject(share)) {
  374. throw "Unknown Share";
  375. }
  376. return share.mail_send === 1;
  377. },
  378. /**
  379. * Sends an email notification for the given share
  380. *
  381. * @param {int} shareType share type
  382. * @param {string} shareWith recipient
  383. * @param {bool} state whether to set the notification flag or remove it
  384. */
  385. sendNotificationForShare: function(shareType, shareWith, state) {
  386. var itemType = this.get('itemType');
  387. var itemSource = this.get('itemSource');
  388. return $.post(
  389. OC.generateUrl('core/ajax/share.php'),
  390. {
  391. action: state ? 'informRecipients' : 'informRecipientsDisabled',
  392. recipient: shareWith,
  393. shareType: shareType,
  394. itemSource: itemSource,
  395. itemType: itemType
  396. },
  397. function(result) {
  398. if (result.status !== 'success') {
  399. // FIXME: a model should not show dialogs
  400. OC.dialogs.alert(t('core', result.data.message), t('core', 'Warning'));
  401. }
  402. }
  403. );
  404. },
  405. /**
  406. * Send the link share information by email
  407. *
  408. * @param {string} recipientEmail recipient email address
  409. */
  410. sendEmailPrivateLink: function(recipientEmail) {
  411. var deferred = $.Deferred();
  412. var itemType = this.get('itemType');
  413. var itemSource = this.get('itemSource');
  414. var linkShare = this.get('linkShare');
  415. $.post(
  416. OC.generateUrl('core/ajax/share.php'), {
  417. action: 'email',
  418. toaddress: recipientEmail,
  419. link: linkShare.link,
  420. itemType: itemType,
  421. itemSource: itemSource,
  422. file: this.fileInfoModel.get('name'),
  423. expiration: linkShare.expiration || ''
  424. },
  425. function(result) {
  426. if (!result || result.status !== 'success') {
  427. // FIXME: a model should not show dialogs
  428. OC.dialogs.alert(result.data.message, t('core', 'Error while sending notification'));
  429. deferred.reject();
  430. } else {
  431. deferred.resolve();
  432. }
  433. });
  434. return deferred.promise();
  435. },
  436. /**
  437. * @returns {boolean}
  438. */
  439. sharePermissionPossible: function() {
  440. return (this.get('permissions') & OC.PERMISSION_SHARE) === OC.PERMISSION_SHARE;
  441. },
  442. /**
  443. * @param {number} shareIndex
  444. * @returns {boolean}
  445. */
  446. hasSharePermission: function(shareIndex) {
  447. return this._shareHasPermission(shareIndex, OC.PERMISSION_SHARE);
  448. },
  449. /**
  450. * @returns {boolean}
  451. */
  452. createPermissionPossible: function() {
  453. return (this.get('permissions') & OC.PERMISSION_CREATE) === OC.PERMISSION_CREATE;
  454. },
  455. /**
  456. * @param {number} shareIndex
  457. * @returns {boolean}
  458. */
  459. hasCreatePermission: function(shareIndex) {
  460. return this._shareHasPermission(shareIndex, OC.PERMISSION_CREATE);
  461. },
  462. /**
  463. * @returns {boolean}
  464. */
  465. updatePermissionPossible: function() {
  466. return (this.get('permissions') & OC.PERMISSION_UPDATE) === OC.PERMISSION_UPDATE;
  467. },
  468. /**
  469. * @param {number} shareIndex
  470. * @returns {boolean}
  471. */
  472. hasUpdatePermission: function(shareIndex) {
  473. return this._shareHasPermission(shareIndex, OC.PERMISSION_UPDATE);
  474. },
  475. /**
  476. * @returns {boolean}
  477. */
  478. deletePermissionPossible: function() {
  479. return (this.get('permissions') & OC.PERMISSION_DELETE) === OC.PERMISSION_DELETE;
  480. },
  481. /**
  482. * @param {number} shareIndex
  483. * @returns {boolean}
  484. */
  485. hasDeletePermission: function(shareIndex) {
  486. return this._shareHasPermission(shareIndex, OC.PERMISSION_DELETE);
  487. },
  488. /**
  489. * @returns {boolean}
  490. */
  491. editPermissionPossible: function() {
  492. return this.createPermissionPossible()
  493. || this.updatePermissionPossible()
  494. || this.deletePermissionPossible();
  495. },
  496. /**
  497. * @returns {boolean}
  498. */
  499. hasEditPermission: function(shareIndex) {
  500. return this.hasCreatePermission(shareIndex)
  501. || this.hasUpdatePermission(shareIndex)
  502. || this.hasDeletePermission(shareIndex);
  503. },
  504. _getUrl: function(base, params) {
  505. params = _.extend({format: 'json'}, params || {});
  506. return OC.linkToOCS('apps/files_sharing/api/v1', 2) + base + '?' + OC.buildQueryString(params);
  507. },
  508. _fetchShares: function() {
  509. var path = this.fileInfoModel.getFullPath();
  510. return $.ajax({
  511. type: 'GET',
  512. url: this._getUrl('shares', {path: path, reshares: true})
  513. });
  514. },
  515. _fetchReshare: function() {
  516. // only fetch original share once
  517. if (!this._reshareFetched) {
  518. var path = this.fileInfoModel.getFullPath();
  519. this._reshareFetched = true;
  520. return $.ajax({
  521. type: 'GET',
  522. url: this._getUrl('shares', {path: path, shared_with_me: true})
  523. });
  524. } else {
  525. return $.Deferred().resolve([{
  526. ocs: {
  527. data: [this.get('reshare')]
  528. }
  529. }]);
  530. }
  531. },
  532. fetch: function() {
  533. var model = this;
  534. this.trigger('request', this);
  535. var deferred = $.when(
  536. this._fetchShares(),
  537. this._fetchReshare()
  538. );
  539. deferred.done(function(data1, data2) {
  540. model.trigger('sync', 'GET', this);
  541. var sharesMap = {};
  542. _.each(data1[0].ocs.data, function(shareItem) {
  543. sharesMap[shareItem.id] = shareItem;
  544. });
  545. var reshare = false;
  546. if (data2[0].ocs.data.length) {
  547. reshare = data2[0].ocs.data[0];
  548. }
  549. model.set(model.parse({
  550. shares: sharesMap,
  551. reshare: reshare
  552. }));
  553. });
  554. return deferred;
  555. },
  556. /**
  557. * Updates OC.Share.itemShares and OC.Share.statuses.
  558. *
  559. * This is required in case the user navigates away and comes back,
  560. * the share statuses from the old arrays are still used to fill in the icons
  561. * in the file list.
  562. */
  563. _legacyFillCurrentShares: function(shares) {
  564. var fileId = this.fileInfoModel.get('id');
  565. if (!shares || !shares.length) {
  566. delete OC.Share.statuses[fileId];
  567. OC.Share.currentShares = {};
  568. OC.Share.itemShares = [];
  569. return;
  570. }
  571. var currentShareStatus = OC.Share.statuses[fileId];
  572. if (!currentShareStatus) {
  573. currentShareStatus = {link: false};
  574. OC.Share.statuses[fileId] = currentShareStatus;
  575. }
  576. currentShareStatus.link = false;
  577. OC.Share.currentShares = {};
  578. OC.Share.itemShares = [];
  579. _.each(shares,
  580. /**
  581. * @param {OC.Share.Types.ShareInfo} share
  582. */
  583. function(share) {
  584. if (share.share_type === OC.Share.SHARE_TYPE_LINK) {
  585. OC.Share.itemShares[share.share_type] = true;
  586. currentShareStatus.link = true;
  587. } else {
  588. if (!OC.Share.itemShares[share.share_type]) {
  589. OC.Share.itemShares[share.share_type] = [];
  590. }
  591. OC.Share.itemShares[share.share_type].push(share.share_with);
  592. }
  593. }
  594. );
  595. },
  596. parse: function(data) {
  597. if(data === false) {
  598. console.warn('no data was returned');
  599. this.trigger('fetchError');
  600. return {};
  601. }
  602. var permissions = this.get('possiblePermissions');
  603. if(!_.isUndefined(data.reshare) && !_.isUndefined(data.reshare.permissions) && data.reshare.uid_owner !== OC.currentUser) {
  604. permissions = permissions & data.reshare.permissions;
  605. }
  606. var allowPublicUploadStatus = false;
  607. if(!_.isUndefined(data.shares)) {
  608. $.each(data.shares, function (key, value) {
  609. if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
  610. allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false;
  611. return true;
  612. }
  613. });
  614. }
  615. /** @type {OC.Share.Types.ShareInfo[]} **/
  616. var shares = _.map(data.shares, function(share) {
  617. // properly parse some values because sometimes the server
  618. // returns integers as string...
  619. var i;
  620. for (i = 0; i < SHARE_RESPONSE_INT_PROPS.length; i++) {
  621. var prop = SHARE_RESPONSE_INT_PROPS[i];
  622. if (!_.isUndefined(share[prop])) {
  623. share[prop] = parseInt(share[prop], 10);
  624. }
  625. }
  626. return share;
  627. });
  628. this._legacyFillCurrentShares(shares);
  629. var linkShare = { isLinkShare: false };
  630. // filter out the share by link
  631. shares = _.reject(shares,
  632. /**
  633. * @param {OC.Share.Types.ShareInfo} share
  634. */
  635. function(share) {
  636. var isShareLink =
  637. share.share_type === OC.Share.SHARE_TYPE_LINK
  638. && ( share.file_source === this.get('itemSource')
  639. || share.item_source === this.get('itemSource'));
  640. if (isShareLink) {
  641. /*
  642. * Ignore reshared link shares for now
  643. * FIXME: Find a way to display properly
  644. */
  645. if (share.uid_owner !== OC.currentUser) {
  646. return share;
  647. }
  648. var link = window.location.protocol + '//' + window.location.host;
  649. if (!share.token) {
  650. // pre-token link
  651. var fullPath = this.fileInfoModel.get('path') + '/' +
  652. this.fileInfoModel.get('name');
  653. var location = '/' + OC.currentUser + '/files' + fullPath;
  654. var type = this.fileInfoModel.isDirectory() ? 'folder' : 'file';
  655. link += OC.linkTo('', 'public.php') + '?service=files&' +
  656. type + '=' + encodeURIComponent(location);
  657. } else {
  658. link += OC.generateUrl('/s/') + share.token;
  659. }
  660. linkShare = {
  661. isLinkShare: true,
  662. id: share.id,
  663. token: share.token,
  664. password: share.share_with,
  665. link: link,
  666. permissions: share.permissions,
  667. // currently expiration is only effective for link shares.
  668. expiration: share.expiration,
  669. stime: share.stime
  670. };
  671. return share;
  672. }
  673. },
  674. this
  675. );
  676. return {
  677. reshare: data.reshare,
  678. shares: shares,
  679. linkShare: linkShare,
  680. permissions: permissions,
  681. allowPublicUploadStatus: allowPublicUploadStatus
  682. };
  683. },
  684. /**
  685. * Parses a string to an valid integer (unix timestamp)
  686. * @param time
  687. * @returns {*}
  688. * @internal Only used to work around a bug in the backend
  689. */
  690. _parseTime: function(time) {
  691. if (_.isString(time)) {
  692. // skip empty strings and hex values
  693. if (time === '' || (time.length > 1 && time[0] === '0' && time[1] === 'x')) {
  694. return null;
  695. }
  696. time = parseInt(time, 10);
  697. if(isNaN(time)) {
  698. time = null;
  699. }
  700. }
  701. return time;
  702. }
  703. });
  704. OC.Share.ShareItemModel = ShareItemModel;
  705. })();