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 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  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 && 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. isHideFileListSet: function() {
  250. return this.get('hideFileListStatus');
  251. },
  252. /**
  253. * @returns {boolean}
  254. */
  255. isFolder: function() {
  256. return this.get('itemType') === 'folder';
  257. },
  258. /**
  259. * @returns {boolean}
  260. */
  261. isFile: function() {
  262. return this.get('itemType') === 'file';
  263. },
  264. /**
  265. * whether this item has reshare information
  266. * @returns {boolean}
  267. */
  268. hasReshare: function() {
  269. var reshare = this.get('reshare');
  270. return _.isObject(reshare) && !_.isUndefined(reshare.uid_owner);
  271. },
  272. /**
  273. * whether this item has user share information
  274. * @returns {boolean}
  275. */
  276. hasUserShares: function() {
  277. return this.getSharesWithCurrentItem().length > 0;
  278. },
  279. /**
  280. * Returns whether this item has a link share
  281. *
  282. * @return {bool} true if a link share exists, false otherwise
  283. */
  284. hasLinkShare: function() {
  285. var linkShare = this.get('linkShare');
  286. if (linkShare && linkShare.isLinkShare) {
  287. return true;
  288. }
  289. return false;
  290. },
  291. /**
  292. * @returns {string}
  293. */
  294. getReshareOwner: function() {
  295. return this.get('reshare').uid_owner;
  296. },
  297. /**
  298. * @returns {string}
  299. */
  300. getReshareOwnerDisplayname: function() {
  301. return this.get('reshare').displayname_owner;
  302. },
  303. /**
  304. * @returns {string}
  305. */
  306. getReshareWith: function() {
  307. return this.get('reshare').share_with;
  308. },
  309. /**
  310. * @returns {number}
  311. */
  312. getReshareType: function() {
  313. return this.get('reshare').share_type;
  314. },
  315. /**
  316. * Returns all share entries that only apply to the current item
  317. * (file/folder)
  318. *
  319. * @return {Array.<OC.Share.Types.ShareInfo>}
  320. */
  321. getSharesWithCurrentItem: function() {
  322. var shares = this.get('shares') || [];
  323. var fileId = this.fileInfoModel.get('id');
  324. return _.filter(shares, function(share) {
  325. return share.item_source === fileId;
  326. });
  327. },
  328. /**
  329. * @param shareIndex
  330. * @returns {string}
  331. */
  332. getShareWith: function(shareIndex) {
  333. /** @type OC.Share.Types.ShareInfo **/
  334. var share = this.get('shares')[shareIndex];
  335. if(!_.isObject(share)) {
  336. throw "Unknown Share";
  337. }
  338. return share.share_with;
  339. },
  340. /**
  341. * @param shareIndex
  342. * @returns {string}
  343. */
  344. getShareWithDisplayName: function(shareIndex) {
  345. /** @type OC.Share.Types.ShareInfo **/
  346. var share = this.get('shares')[shareIndex];
  347. if(!_.isObject(share)) {
  348. throw "Unknown Share";
  349. }
  350. return share.share_with_displayname;
  351. },
  352. getShareType: function(shareIndex) {
  353. /** @type OC.Share.Types.ShareInfo **/
  354. var share = this.get('shares')[shareIndex];
  355. if(!_.isObject(share)) {
  356. throw "Unknown Share";
  357. }
  358. return share.share_type;
  359. },
  360. /**
  361. * whether a share from shares has the requested permission
  362. *
  363. * @param {number} shareIndex
  364. * @param {number} permission
  365. * @returns {boolean}
  366. * @private
  367. */
  368. _shareHasPermission: function(shareIndex, permission) {
  369. /** @type OC.Share.Types.ShareInfo **/
  370. var share = this.get('shares')[shareIndex];
  371. if(!_.isObject(share)) {
  372. throw "Unknown Share";
  373. }
  374. return (share.permissions & permission) === permission;
  375. },
  376. notificationMailWasSent: function(shareIndex) {
  377. /** @type OC.Share.Types.ShareInfo **/
  378. var share = this.get('shares')[shareIndex];
  379. if(!_.isObject(share)) {
  380. throw "Unknown Share";
  381. }
  382. return share.mail_send === 1;
  383. },
  384. /**
  385. * Sends an email notification for the given share
  386. *
  387. * @param {int} shareType share type
  388. * @param {string} shareWith recipient
  389. * @param {bool} state whether to set the notification flag or remove it
  390. */
  391. sendNotificationForShare: function(shareType, shareWith, state) {
  392. var itemType = this.get('itemType');
  393. var itemSource = this.get('itemSource');
  394. return $.post(
  395. OC.generateUrl('core/ajax/share.php'),
  396. {
  397. action: state ? 'informRecipients' : 'informRecipientsDisabled',
  398. recipient: shareWith,
  399. shareType: shareType,
  400. itemSource: itemSource,
  401. itemType: itemType
  402. },
  403. function(result) {
  404. if (result.status !== 'success') {
  405. // FIXME: a model should not show dialogs
  406. OC.dialogs.alert(t('core', result.data.message), t('core', 'Warning'));
  407. }
  408. }
  409. );
  410. },
  411. /**
  412. * Send the link share information by email
  413. *
  414. * @param {string} recipientEmail recipient email address
  415. */
  416. sendEmailPrivateLink: function(recipientEmail) {
  417. var deferred = $.Deferred();
  418. var itemType = this.get('itemType');
  419. var itemSource = this.get('itemSource');
  420. var linkShare = this.get('linkShare');
  421. $.post(
  422. OC.generateUrl('core/ajax/share.php'), {
  423. action: 'email',
  424. toaddress: recipientEmail,
  425. link: linkShare.link,
  426. itemType: itemType,
  427. itemSource: itemSource,
  428. file: this.fileInfoModel.get('name'),
  429. expiration: linkShare.expiration || ''
  430. },
  431. function(result) {
  432. if (!result || result.status !== 'success') {
  433. // FIXME: a model should not show dialogs
  434. OC.dialogs.alert(result.data.message, t('core', 'Error while sending notification'));
  435. deferred.reject();
  436. } else {
  437. deferred.resolve();
  438. }
  439. });
  440. return deferred.promise();
  441. },
  442. /**
  443. * @returns {boolean}
  444. */
  445. sharePermissionPossible: function() {
  446. return (this.get('permissions') & OC.PERMISSION_SHARE) === OC.PERMISSION_SHARE;
  447. },
  448. /**
  449. * @param {number} shareIndex
  450. * @returns {boolean}
  451. */
  452. hasSharePermission: function(shareIndex) {
  453. return this._shareHasPermission(shareIndex, OC.PERMISSION_SHARE);
  454. },
  455. /**
  456. * @returns {boolean}
  457. */
  458. createPermissionPossible: function() {
  459. return (this.get('permissions') & OC.PERMISSION_CREATE) === OC.PERMISSION_CREATE;
  460. },
  461. /**
  462. * @param {number} shareIndex
  463. * @returns {boolean}
  464. */
  465. hasCreatePermission: function(shareIndex) {
  466. return this._shareHasPermission(shareIndex, OC.PERMISSION_CREATE);
  467. },
  468. /**
  469. * @returns {boolean}
  470. */
  471. updatePermissionPossible: function() {
  472. return (this.get('permissions') & OC.PERMISSION_UPDATE) === OC.PERMISSION_UPDATE;
  473. },
  474. /**
  475. * @param {number} shareIndex
  476. * @returns {boolean}
  477. */
  478. hasUpdatePermission: function(shareIndex) {
  479. return this._shareHasPermission(shareIndex, OC.PERMISSION_UPDATE);
  480. },
  481. /**
  482. * @returns {boolean}
  483. */
  484. deletePermissionPossible: function() {
  485. return (this.get('permissions') & OC.PERMISSION_DELETE) === OC.PERMISSION_DELETE;
  486. },
  487. /**
  488. * @param {number} shareIndex
  489. * @returns {boolean}
  490. */
  491. hasDeletePermission: function(shareIndex) {
  492. return this._shareHasPermission(shareIndex, OC.PERMISSION_DELETE);
  493. },
  494. /**
  495. * @returns {boolean}
  496. */
  497. editPermissionPossible: function() {
  498. return this.createPermissionPossible()
  499. || this.updatePermissionPossible()
  500. || this.deletePermissionPossible();
  501. },
  502. /**
  503. * @returns {boolean}
  504. */
  505. hasEditPermission: function(shareIndex) {
  506. return this.hasCreatePermission(shareIndex)
  507. || this.hasUpdatePermission(shareIndex)
  508. || this.hasDeletePermission(shareIndex);
  509. },
  510. _getUrl: function(base, params) {
  511. params = _.extend({format: 'json'}, params || {});
  512. return OC.linkToOCS('apps/files_sharing/api/v1', 2) + base + '?' + OC.buildQueryString(params);
  513. },
  514. _fetchShares: function() {
  515. var path = this.fileInfoModel.getFullPath();
  516. return $.ajax({
  517. type: 'GET',
  518. url: this._getUrl('shares', {path: path, reshares: true})
  519. });
  520. },
  521. _fetchReshare: function() {
  522. // only fetch original share once
  523. if (!this._reshareFetched) {
  524. var path = this.fileInfoModel.getFullPath();
  525. this._reshareFetched = true;
  526. return $.ajax({
  527. type: 'GET',
  528. url: this._getUrl('shares', {path: path, shared_with_me: true})
  529. });
  530. } else {
  531. return $.Deferred().resolve([{
  532. ocs: {
  533. data: [this.get('reshare')]
  534. }
  535. }]);
  536. }
  537. },
  538. /**
  539. * Group reshares into a single super share element.
  540. * Does this by finding the most precise share and
  541. * combines the permissions to be the most permissive.
  542. *
  543. * @param {Array} reshares
  544. * @return {Object} reshare
  545. */
  546. _groupReshares: function(reshares) {
  547. if (!reshares || !reshares.length) {
  548. return false;
  549. }
  550. var superShare = reshares.shift();
  551. var combinedPermissions = superShare.permissions;
  552. _.each(reshares, function(reshare) {
  553. // use share have higher priority than group share
  554. if (reshare.share_type === OC.Share.SHARE_TYPE_USER && superShare.share_type === OC.Share.SHARE_TYPE_GROUP) {
  555. superShare = reshare;
  556. }
  557. combinedPermissions |= reshare.permissions;
  558. });
  559. superShare.permissions = combinedPermissions;
  560. return superShare;
  561. },
  562. fetch: function() {
  563. var model = this;
  564. this.trigger('request', this);
  565. var deferred = $.when(
  566. this._fetchShares(),
  567. this._fetchReshare()
  568. );
  569. deferred.done(function(data1, data2) {
  570. model.trigger('sync', 'GET', this);
  571. var sharesMap = {};
  572. _.each(data1[0].ocs.data, function(shareItem) {
  573. sharesMap[shareItem.id] = shareItem;
  574. });
  575. var reshare = false;
  576. if (data2[0].ocs.data.length) {
  577. reshare = model._groupReshares(data2[0].ocs.data);
  578. }
  579. model.set(model.parse({
  580. shares: sharesMap,
  581. reshare: reshare
  582. }));
  583. });
  584. return deferred;
  585. },
  586. /**
  587. * Updates OC.Share.itemShares and OC.Share.statuses.
  588. *
  589. * This is required in case the user navigates away and comes back,
  590. * the share statuses from the old arrays are still used to fill in the icons
  591. * in the file list.
  592. */
  593. _legacyFillCurrentShares: function(shares) {
  594. var fileId = this.fileInfoModel.get('id');
  595. if (!shares || !shares.length) {
  596. delete OC.Share.statuses[fileId];
  597. OC.Share.currentShares = {};
  598. OC.Share.itemShares = [];
  599. return;
  600. }
  601. var currentShareStatus = OC.Share.statuses[fileId];
  602. if (!currentShareStatus) {
  603. currentShareStatus = {link: false};
  604. OC.Share.statuses[fileId] = currentShareStatus;
  605. }
  606. currentShareStatus.link = false;
  607. OC.Share.currentShares = {};
  608. OC.Share.itemShares = [];
  609. _.each(shares,
  610. /**
  611. * @param {OC.Share.Types.ShareInfo} share
  612. */
  613. function(share) {
  614. if (share.share_type === OC.Share.SHARE_TYPE_LINK) {
  615. OC.Share.itemShares[share.share_type] = true;
  616. currentShareStatus.link = true;
  617. } else {
  618. if (!OC.Share.itemShares[share.share_type]) {
  619. OC.Share.itemShares[share.share_type] = [];
  620. }
  621. OC.Share.itemShares[share.share_type].push(share.share_with);
  622. }
  623. }
  624. );
  625. },
  626. parse: function(data) {
  627. if(data === false) {
  628. console.warn('no data was returned');
  629. this.trigger('fetchError');
  630. return {};
  631. }
  632. var permissions = this.get('possiblePermissions');
  633. if(!_.isUndefined(data.reshare) && !_.isUndefined(data.reshare.permissions) && data.reshare.uid_owner !== OC.currentUser) {
  634. permissions = permissions & data.reshare.permissions;
  635. }
  636. var allowPublicUploadStatus = false;
  637. if(!_.isUndefined(data.shares)) {
  638. $.each(data.shares, function (key, value) {
  639. if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
  640. allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false;
  641. return true;
  642. }
  643. });
  644. }
  645. var hideFileListStatus = false;
  646. if(!_.isUndefined(data.shares)) {
  647. $.each(data.shares, function (key, value) {
  648. if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
  649. hideFileListStatus = (value.permissions & OC.PERMISSION_READ) ? false : true;
  650. return true;
  651. }
  652. });
  653. }
  654. /** @type {OC.Share.Types.ShareInfo[]} **/
  655. var shares = _.map(data.shares, function(share) {
  656. // properly parse some values because sometimes the server
  657. // returns integers as string...
  658. var i;
  659. for (i = 0; i < SHARE_RESPONSE_INT_PROPS.length; i++) {
  660. var prop = SHARE_RESPONSE_INT_PROPS[i];
  661. if (!_.isUndefined(share[prop])) {
  662. share[prop] = parseInt(share[prop], 10);
  663. }
  664. }
  665. return share;
  666. });
  667. this._legacyFillCurrentShares(shares);
  668. var linkShare = { isLinkShare: false };
  669. // filter out the share by link
  670. shares = _.reject(shares,
  671. /**
  672. * @param {OC.Share.Types.ShareInfo} share
  673. */
  674. function(share) {
  675. var isShareLink =
  676. share.share_type === OC.Share.SHARE_TYPE_LINK
  677. && ( share.file_source === this.get('itemSource')
  678. || share.item_source === this.get('itemSource'));
  679. if (isShareLink) {
  680. /*
  681. * Ignore reshared link shares for now
  682. * FIXME: Find a way to display properly
  683. */
  684. if (share.uid_owner !== OC.currentUser) {
  685. return share;
  686. }
  687. var link = window.location.protocol + '//' + window.location.host;
  688. if (!share.token) {
  689. // pre-token link
  690. var fullPath = this.fileInfoModel.get('path') + '/' +
  691. this.fileInfoModel.get('name');
  692. var location = '/' + OC.currentUser + '/files' + fullPath;
  693. var type = this.fileInfoModel.isDirectory() ? 'folder' : 'file';
  694. link += OC.linkTo('', 'public.php') + '?service=files&' +
  695. type + '=' + encodeURIComponent(location);
  696. } else {
  697. link += OC.generateUrl('/s/') + share.token;
  698. }
  699. linkShare = {
  700. isLinkShare: true,
  701. id: share.id,
  702. token: share.token,
  703. password: share.share_with,
  704. link: link,
  705. permissions: share.permissions,
  706. // currently expiration is only effective for link shares.
  707. expiration: share.expiration,
  708. stime: share.stime
  709. };
  710. return share;
  711. }
  712. },
  713. this
  714. );
  715. return {
  716. reshare: data.reshare,
  717. shares: shares,
  718. linkShare: linkShare,
  719. permissions: permissions,
  720. allowPublicUploadStatus: allowPublicUploadStatus,
  721. hideFileListStatus: hideFileListStatus
  722. };
  723. },
  724. /**
  725. * Parses a string to an valid integer (unix timestamp)
  726. * @param time
  727. * @returns {*}
  728. * @internal Only used to work around a bug in the backend
  729. */
  730. _parseTime: function(time) {
  731. if (_.isString(time)) {
  732. // skip empty strings and hex values
  733. if (time === '' || (time.length > 1 && time[0] === '0' && time[1] === 'x')) {
  734. return null;
  735. }
  736. time = parseInt(time, 10);
  737. if(isNaN(time)) {
  738. time = null;
  739. }
  740. }
  741. return time;
  742. }
  743. });
  744. OC.Share.ShareItemModel = ShareItemModel;
  745. })();