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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  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} share_with_avatar
  43. * @property {string} mail_send
  44. * @property {Date} expiration optional?
  45. * @property {number} stime optional?
  46. * @property {string} uid_owner
  47. * @property {string} displayname_owner
  48. */
  49. /**
  50. * @typedef {object} OC.Share.Types.ShareItemInfo
  51. * @property {OC.Share.Types.Reshare} reshare
  52. * @property {OC.Share.Types.ShareInfo[]} shares
  53. * @property {OC.Share.Types.LinkShareInfo|undefined} linkShare
  54. */
  55. /**
  56. * These properties are sometimes returned by the server as strings instead
  57. * of integers, so we need to convert them accordingly...
  58. */
  59. var SHARE_RESPONSE_INT_PROPS = [
  60. 'id', 'file_parent', 'mail_send', 'file_source', 'item_source', 'permissions',
  61. 'storage', 'share_type', 'parent', 'stime'
  62. ];
  63. /**
  64. * @class OCA.Share.ShareItemModel
  65. * @classdesc
  66. *
  67. * Represents the GUI of the share dialogue
  68. *
  69. * // FIXME: use OC Share API once #17143 is done
  70. *
  71. * // TODO: this really should be a collection of share item models instead,
  72. * where the link share is one of them
  73. */
  74. var ShareItemModel = OC.Backbone.Model.extend({
  75. /**
  76. * @type share id of the link share, if applicable
  77. */
  78. _linkShareId: null,
  79. initialize: function(attributes, options) {
  80. if(!_.isUndefined(options.configModel)) {
  81. this.configModel = options.configModel;
  82. }
  83. if(!_.isUndefined(options.fileInfoModel)) {
  84. /** @type {OC.Files.FileInfo} **/
  85. this.fileInfoModel = options.fileInfoModel;
  86. }
  87. _.bindAll(this, 'addShare');
  88. },
  89. defaults: {
  90. allowPublicUploadStatus: false,
  91. permissions: 0,
  92. linkShare: {}
  93. },
  94. /**
  95. * Saves the current link share information.
  96. *
  97. * This will trigger an ajax call and, if successful, refetch the model
  98. * afterwards. Callbacks "success", "error" and "complete" can be given
  99. * in the options object; "success" is called after a successful save
  100. * once the model is refetch, "error" is called after a failed save, and
  101. * "complete" is called both after a successful save and after a failed
  102. * save. Note that "complete" is called before "success" and "error" are
  103. * called (unlike in jQuery, in which it is called after them); this
  104. * ensures that "complete" is called even if refetching the model fails.
  105. *
  106. * TODO: this should be a separate model
  107. */
  108. saveLinkShare: function(attributes, options) {
  109. options = options || {};
  110. attributes = _.extend({}, attributes);
  111. var shareId = null;
  112. var call;
  113. // oh yeah...
  114. if (attributes.expiration) {
  115. attributes.expireDate = attributes.expiration;
  116. delete attributes.expiration;
  117. }
  118. if (this.get('linkShare') && this.get('linkShare').isLinkShare) {
  119. shareId = this.get('linkShare').id;
  120. // note: update can only update a single value at a time
  121. call = this.updateShare(shareId, attributes, options);
  122. } else {
  123. attributes = _.defaults(attributes, {
  124. password: '',
  125. passwordChanged: false,
  126. permissions: OC.PERMISSION_READ,
  127. expireDate: this.configModel.getDefaultExpirationDateString(),
  128. shareType: OC.Share.SHARE_TYPE_LINK
  129. });
  130. call = this.addShare(attributes, options);
  131. }
  132. return call;
  133. },
  134. removeLinkShare: function() {
  135. if (this.get('linkShare')) {
  136. return this.removeShare(this.get('linkShare').id);
  137. }
  138. },
  139. addShare: function(attributes, options) {
  140. var shareType = attributes.shareType;
  141. attributes = _.extend({}, attributes);
  142. // get default permissions
  143. var defaultPermissions = OC.getCapabilities()['files_sharing']['default_permissions'] || OC.PERMISSION_ALL;
  144. var possiblePermissions = OC.PERMISSION_READ;
  145. if (this.updatePermissionPossible()) {
  146. possiblePermissions = possiblePermissions | OC.PERMISSION_UPDATE;
  147. }
  148. if (this.createPermissionPossible()) {
  149. possiblePermissions = possiblePermissions | OC.PERMISSION_CREATE;
  150. }
  151. if (this.deletePermissionPossible()) {
  152. possiblePermissions = possiblePermissions | OC.PERMISSION_DELETE;
  153. }
  154. if (this.configModel.get('isResharingAllowed') && (this.sharePermissionPossible())) {
  155. possiblePermissions = possiblePermissions | OC.PERMISSION_SHARE;
  156. }
  157. attributes.permissions = defaultPermissions & possiblePermissions;
  158. if (_.isUndefined(attributes.path)) {
  159. attributes.path = this.fileInfoModel.getFullPath();
  160. }
  161. return this._addOrUpdateShare({
  162. type: 'POST',
  163. url: this._getUrl('shares'),
  164. data: attributes,
  165. dataType: 'json'
  166. }, options);
  167. },
  168. updateShare: function(shareId, attrs, options) {
  169. return this._addOrUpdateShare({
  170. type: 'PUT',
  171. url: this._getUrl('shares/' + encodeURIComponent(shareId)),
  172. data: attrs,
  173. dataType: 'json'
  174. }, options);
  175. },
  176. _addOrUpdateShare: function(ajaxSettings, options) {
  177. var self = this;
  178. options = options || {};
  179. return $.ajax(
  180. ajaxSettings
  181. ).always(function() {
  182. if (_.isFunction(options.complete)) {
  183. options.complete(self);
  184. }
  185. }).done(function() {
  186. self.fetch().done(function() {
  187. if (_.isFunction(options.success)) {
  188. options.success(self);
  189. }
  190. });
  191. }).fail(function(xhr) {
  192. var msg = t('core', 'Error');
  193. var result = xhr.responseJSON;
  194. if (result && result.ocs && result.ocs.meta) {
  195. msg = result.ocs.meta.message;
  196. }
  197. if (_.isFunction(options.error)) {
  198. options.error(self, msg);
  199. } else {
  200. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  201. }
  202. });
  203. },
  204. /**
  205. * Deletes the share with the given id
  206. *
  207. * @param {int} shareId share id
  208. * @return {jQuery}
  209. */
  210. removeShare: function(shareId, options) {
  211. var self = this;
  212. options = options || {};
  213. return $.ajax({
  214. type: 'DELETE',
  215. url: this._getUrl('shares/' + encodeURIComponent(shareId)),
  216. }).done(function() {
  217. self.fetch({
  218. success: function() {
  219. if (_.isFunction(options.success)) {
  220. options.success(self);
  221. }
  222. }
  223. });
  224. }).fail(function(xhr) {
  225. var msg = t('core', 'Error');
  226. var result = xhr.responseJSON;
  227. if (result.ocs && result.ocs.meta) {
  228. msg = result.ocs.meta.message;
  229. }
  230. if (_.isFunction(options.error)) {
  231. options.error(self, msg);
  232. } else {
  233. OC.dialogs.alert(msg, t('core', 'Error removing share'));
  234. }
  235. });
  236. },
  237. /**
  238. * @returns {boolean}
  239. */
  240. isPublicUploadAllowed: function() {
  241. return this.get('allowPublicUploadStatus');
  242. },
  243. isPublicEditingAllowed: function() {
  244. return this.get('allowPublicEditingStatus');
  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. getReshareNote: function() {
  307. return this.get('reshare').note;
  308. },
  309. /**
  310. * @returns {string}
  311. */
  312. getReshareWith: function() {
  313. return this.get('reshare').share_with;
  314. },
  315. /**
  316. * @returns {string}
  317. */
  318. getReshareWithDisplayName: function() {
  319. var reshare = this.get('reshare');
  320. return reshare.share_with_displayname || reshare.share_with;
  321. },
  322. /**
  323. * @returns {number}
  324. */
  325. getReshareType: function() {
  326. return this.get('reshare').share_type;
  327. },
  328. getExpireDate: function(shareIndex) {
  329. return this._shareExpireDate(shareIndex);
  330. },
  331. getNote: function(shareIndex) {
  332. return this._shareNote(shareIndex);
  333. },
  334. /**
  335. * Returns all share entries that only apply to the current item
  336. * (file/folder)
  337. *
  338. * @return {Array.<OC.Share.Types.ShareInfo>}
  339. */
  340. getSharesWithCurrentItem: function() {
  341. var shares = this.get('shares') || [];
  342. var fileId = this.fileInfoModel.get('id');
  343. return _.filter(shares, function(share) {
  344. return share.item_source === fileId;
  345. });
  346. },
  347. /**
  348. * @param shareIndex
  349. * @returns {string}
  350. */
  351. getShareWith: function(shareIndex) {
  352. /** @type OC.Share.Types.ShareInfo **/
  353. var share = this.get('shares')[shareIndex];
  354. if(!_.isObject(share)) {
  355. throw "Unknown Share";
  356. }
  357. return share.share_with;
  358. },
  359. /**
  360. * @param shareIndex
  361. * @returns {string}
  362. */
  363. getShareWithDisplayName: function(shareIndex) {
  364. /** @type OC.Share.Types.ShareInfo **/
  365. var share = this.get('shares')[shareIndex];
  366. if(!_.isObject(share)) {
  367. throw "Unknown Share";
  368. }
  369. return share.share_with_displayname;
  370. },
  371. /**
  372. * @param shareIndex
  373. * @returns {string}
  374. */
  375. getShareWithAvatar: function(shareIndex) {
  376. /** @type OC.Share.Types.ShareInfo **/
  377. var share = this.get('shares')[shareIndex];
  378. if(!_.isObject(share)) {
  379. throw "Unknown Share";
  380. }
  381. return share.share_with_avatar;
  382. },
  383. /**
  384. * @param shareIndex
  385. * @returns {string}
  386. */
  387. getSharedBy: function(shareIndex) {
  388. /** @type OC.Share.Types.ShareInfo **/
  389. var share = this.get('shares')[shareIndex];
  390. if(!_.isObject(share)) {
  391. throw "Unknown Share";
  392. }
  393. return share.uid_owner;
  394. },
  395. /**
  396. * @param shareIndex
  397. * @returns {string}
  398. */
  399. getSharedByDisplayName: function(shareIndex) {
  400. /** @type OC.Share.Types.ShareInfo **/
  401. var share = this.get('shares')[shareIndex];
  402. if(!_.isObject(share)) {
  403. throw "Unknown Share";
  404. }
  405. return share.displayname_owner;
  406. },
  407. /**
  408. * returns the array index of a sharee for a provided shareId
  409. *
  410. * @param shareId
  411. * @returns {number}
  412. */
  413. findShareWithIndex: function(shareId) {
  414. var shares = this.get('shares');
  415. if(!_.isArray(shares)) {
  416. throw "Unknown Share";
  417. }
  418. for(var i = 0; i < shares.length; i++) {
  419. var shareWith = shares[i];
  420. if(shareWith.id === shareId) {
  421. return i;
  422. }
  423. }
  424. throw "Unknown Sharee";
  425. },
  426. getShareType: function(shareIndex) {
  427. /** @type OC.Share.Types.ShareInfo **/
  428. var share = this.get('shares')[shareIndex];
  429. if(!_.isObject(share)) {
  430. throw "Unknown Share";
  431. }
  432. return share.share_type;
  433. },
  434. /**
  435. * whether a share from shares has the requested permission
  436. *
  437. * @param {number} shareIndex
  438. * @param {number} permission
  439. * @returns {boolean}
  440. * @private
  441. */
  442. _shareHasPermission: function(shareIndex, permission) {
  443. /** @type OC.Share.Types.ShareInfo **/
  444. var share = this.get('shares')[shareIndex];
  445. if(!_.isObject(share)) {
  446. throw "Unknown Share";
  447. }
  448. return (share.permissions & permission) === permission;
  449. },
  450. _shareExpireDate: function(shareIndex) {
  451. var share = this.get('shares')[shareIndex];
  452. if(!_.isObject(share)) {
  453. throw "Unknown Share";
  454. }
  455. var date2 = share.expiration;
  456. return date2;
  457. },
  458. _shareNote: function(shareIndex) {
  459. var share = this.get('shares')[shareIndex];
  460. if(!_.isObject(share)) {
  461. throw "Unknown Share";
  462. }
  463. return share.note;
  464. },
  465. /**
  466. * @return {int}
  467. */
  468. getPermissions: function() {
  469. return this.get('permissions');
  470. },
  471. /**
  472. * @returns {boolean}
  473. */
  474. sharePermissionPossible: function() {
  475. return (this.get('permissions') & OC.PERMISSION_SHARE) === OC.PERMISSION_SHARE;
  476. },
  477. /**
  478. * @param {number} shareIndex
  479. * @returns {boolean}
  480. */
  481. hasSharePermission: function(shareIndex) {
  482. return this._shareHasPermission(shareIndex, OC.PERMISSION_SHARE);
  483. },
  484. /**
  485. * @returns {boolean}
  486. */
  487. createPermissionPossible: function() {
  488. return (this.get('permissions') & OC.PERMISSION_CREATE) === OC.PERMISSION_CREATE;
  489. },
  490. /**
  491. * @param {number} shareIndex
  492. * @returns {boolean}
  493. */
  494. hasCreatePermission: function(shareIndex) {
  495. return this._shareHasPermission(shareIndex, OC.PERMISSION_CREATE);
  496. },
  497. /**
  498. * @returns {boolean}
  499. */
  500. updatePermissionPossible: function() {
  501. return (this.get('permissions') & OC.PERMISSION_UPDATE) === OC.PERMISSION_UPDATE;
  502. },
  503. /**
  504. * @param {number} shareIndex
  505. * @returns {boolean}
  506. */
  507. hasUpdatePermission: function(shareIndex) {
  508. return this._shareHasPermission(shareIndex, OC.PERMISSION_UPDATE);
  509. },
  510. /**
  511. * @returns {boolean}
  512. */
  513. deletePermissionPossible: function() {
  514. return (this.get('permissions') & OC.PERMISSION_DELETE) === OC.PERMISSION_DELETE;
  515. },
  516. /**
  517. * @param {number} shareIndex
  518. * @returns {boolean}
  519. */
  520. hasDeletePermission: function(shareIndex) {
  521. return this._shareHasPermission(shareIndex, OC.PERMISSION_DELETE);
  522. },
  523. hasReadPermission: function(shareIndex) {
  524. return this._shareHasPermission(shareIndex, OC.PERMISSION_READ);
  525. },
  526. /**
  527. * @returns {boolean}
  528. */
  529. editPermissionPossible: function() {
  530. return this.createPermissionPossible()
  531. || this.updatePermissionPossible()
  532. || this.deletePermissionPossible();
  533. },
  534. /**
  535. * @returns {string}
  536. * The state that the 'can edit' permission checkbox should have.
  537. * Possible values:
  538. * - empty string: no permission
  539. * - 'checked': all applicable permissions
  540. * - 'indeterminate': some but not all permissions
  541. */
  542. editPermissionState: function(shareIndex) {
  543. var hcp = this.hasCreatePermission(shareIndex);
  544. var hup = this.hasUpdatePermission(shareIndex);
  545. var hdp = this.hasDeletePermission(shareIndex);
  546. if (!hcp && !hup && !hdp) {
  547. return '';
  548. }
  549. if ( (this.createPermissionPossible() && !hcp)
  550. || (this.updatePermissionPossible() && !hup)
  551. || (this.deletePermissionPossible() && !hdp) ) {
  552. return 'indeterminate';
  553. }
  554. return 'checked';
  555. },
  556. /**
  557. * @returns {int}
  558. */
  559. linkSharePermissions: function() {
  560. if (!this.hasLinkShare()) {
  561. return -1;
  562. } else {
  563. return this.get('linkShare').permissions;
  564. }
  565. },
  566. _getUrl: function(base, params) {
  567. params = _.extend({format: 'json'}, params || {});
  568. return OC.linkToOCS('apps/files_sharing/api/v1', 2) + base + '?' + OC.buildQueryString(params);
  569. },
  570. _fetchShares: function() {
  571. var path = this.fileInfoModel.getFullPath();
  572. return $.ajax({
  573. type: 'GET',
  574. url: this._getUrl('shares', {path: path, reshares: true})
  575. });
  576. },
  577. _fetchReshare: function() {
  578. // only fetch original share once
  579. if (!this._reshareFetched) {
  580. var path = this.fileInfoModel.getFullPath();
  581. this._reshareFetched = true;
  582. return $.ajax({
  583. type: 'GET',
  584. url: this._getUrl('shares', {path: path, shared_with_me: true})
  585. });
  586. } else {
  587. return $.Deferred().resolve([{
  588. ocs: {
  589. data: [this.get('reshare')]
  590. }
  591. }]);
  592. }
  593. },
  594. /**
  595. * Group reshares into a single super share element.
  596. * Does this by finding the most precise share and
  597. * combines the permissions to be the most permissive.
  598. *
  599. * @param {Array} reshares
  600. * @return {Object} reshare
  601. */
  602. _groupReshares: function(reshares) {
  603. if (!reshares || !reshares.length) {
  604. return false;
  605. }
  606. var superShare = reshares.shift();
  607. var combinedPermissions = superShare.permissions;
  608. _.each(reshares, function(reshare) {
  609. // use share have higher priority than group share
  610. if (reshare.share_type === OC.Share.SHARE_TYPE_USER && superShare.share_type === OC.Share.SHARE_TYPE_GROUP) {
  611. superShare = reshare;
  612. }
  613. combinedPermissions |= reshare.permissions;
  614. });
  615. superShare.permissions = combinedPermissions;
  616. return superShare;
  617. },
  618. fetch: function(options) {
  619. var model = this;
  620. this.trigger('request', this);
  621. var deferred = $.when(
  622. this._fetchShares(),
  623. this._fetchReshare()
  624. );
  625. deferred.done(function(data1, data2) {
  626. model.trigger('sync', 'GET', this);
  627. var sharesMap = {};
  628. _.each(data1[0].ocs.data, function(shareItem) {
  629. sharesMap[shareItem.id] = shareItem;
  630. });
  631. var reshare = false;
  632. if (data2[0].ocs.data.length) {
  633. reshare = model._groupReshares(data2[0].ocs.data);
  634. }
  635. model.set(model.parse({
  636. shares: sharesMap,
  637. reshare: reshare
  638. }));
  639. if(!_.isUndefined(options) && _.isFunction(options.success)) {
  640. options.success();
  641. }
  642. });
  643. return deferred;
  644. },
  645. /**
  646. * Updates OC.Share.itemShares and OC.Share.statuses.
  647. *
  648. * This is required in case the user navigates away and comes back,
  649. * the share statuses from the old arrays are still used to fill in the icons
  650. * in the file list.
  651. */
  652. _legacyFillCurrentShares: function(shares) {
  653. var fileId = this.fileInfoModel.get('id');
  654. if (!shares || !shares.length) {
  655. delete OC.Share.statuses[fileId];
  656. OC.Share.currentShares = {};
  657. OC.Share.itemShares = [];
  658. return;
  659. }
  660. var currentShareStatus = OC.Share.statuses[fileId];
  661. if (!currentShareStatus) {
  662. currentShareStatus = {link: false};
  663. OC.Share.statuses[fileId] = currentShareStatus;
  664. }
  665. currentShareStatus.link = false;
  666. OC.Share.currentShares = {};
  667. OC.Share.itemShares = [];
  668. _.each(shares,
  669. /**
  670. * @param {OC.Share.Types.ShareInfo} share
  671. */
  672. function(share) {
  673. if (share.share_type === OC.Share.SHARE_TYPE_LINK) {
  674. OC.Share.itemShares[share.share_type] = true;
  675. currentShareStatus.link = true;
  676. } else {
  677. if (!OC.Share.itemShares[share.share_type]) {
  678. OC.Share.itemShares[share.share_type] = [];
  679. }
  680. OC.Share.itemShares[share.share_type].push(share.share_with);
  681. }
  682. }
  683. );
  684. },
  685. parse: function(data) {
  686. if(data === false) {
  687. console.warn('no data was returned');
  688. this.trigger('fetchError');
  689. return {};
  690. }
  691. var permissions = this.fileInfoModel.get('permissions');
  692. if(!_.isUndefined(data.reshare) && !_.isUndefined(data.reshare.permissions) && data.reshare.uid_owner !== OC.currentUser) {
  693. permissions = permissions & data.reshare.permissions;
  694. }
  695. var allowPublicUploadStatus = false;
  696. if(!_.isUndefined(data.shares)) {
  697. $.each(data.shares, function (key, value) {
  698. if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
  699. allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false;
  700. return true;
  701. }
  702. });
  703. }
  704. var allowPublicEditingStatus = true;
  705. if(!_.isUndefined(data.shares)) {
  706. $.each(data.shares, function (key, value) {
  707. if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
  708. allowPublicEditingStatus = (value.permissions & OC.PERMISSION_UPDATE) ? true : false;
  709. return true;
  710. }
  711. });
  712. }
  713. var hideFileListStatus = false;
  714. if(!_.isUndefined(data.shares)) {
  715. $.each(data.shares, function (key, value) {
  716. if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
  717. hideFileListStatus = (value.permissions & OC.PERMISSION_READ) ? false : true;
  718. return true;
  719. }
  720. });
  721. }
  722. /** @type {OC.Share.Types.ShareInfo[]} **/
  723. var shares = _.map(data.shares, function(share) {
  724. // properly parse some values because sometimes the server
  725. // returns integers as string...
  726. var i;
  727. for (i = 0; i < SHARE_RESPONSE_INT_PROPS.length; i++) {
  728. var prop = SHARE_RESPONSE_INT_PROPS[i];
  729. if (!_.isUndefined(share[prop])) {
  730. share[prop] = parseInt(share[prop], 10);
  731. }
  732. }
  733. return share;
  734. });
  735. this._legacyFillCurrentShares(shares);
  736. var linkShare = { isLinkShare: false };
  737. // filter out the share by link
  738. shares = _.reject(shares,
  739. /**
  740. * @param {OC.Share.Types.ShareInfo} share
  741. */
  742. function(share) {
  743. var isShareLink =
  744. share.share_type === OC.Share.SHARE_TYPE_LINK
  745. && ( share.file_source === this.get('itemSource')
  746. || share.item_source === this.get('itemSource'));
  747. if (isShareLink) {
  748. /*
  749. * Ignore reshared link shares for now
  750. * FIXME: Find a way to display properly
  751. */
  752. if (share.uid_owner !== OC.currentUser) {
  753. return;
  754. }
  755. var link = window.location.protocol + '//' + window.location.host;
  756. if (!share.token) {
  757. // pre-token link
  758. var fullPath = this.fileInfoModel.get('path') + '/' +
  759. this.fileInfoModel.get('name');
  760. var location = '/' + OC.currentUser + '/files' + fullPath;
  761. var type = this.fileInfoModel.isDirectory() ? 'folder' : 'file';
  762. link += OC.linkTo('', 'public.php') + '?service=files&' +
  763. type + '=' + encodeURIComponent(location);
  764. } else {
  765. link += OC.generateUrl('/s/') + share.token;
  766. }
  767. linkShare = {
  768. isLinkShare: true,
  769. id: share.id,
  770. token: share.token,
  771. password: share.share_with,
  772. link: link,
  773. permissions: share.permissions,
  774. // currently expiration is only effective for link shares.
  775. expiration: share.expiration,
  776. stime: share.stime
  777. };
  778. return share;
  779. }
  780. },
  781. this
  782. );
  783. return {
  784. reshare: data.reshare,
  785. shares: shares,
  786. linkShare: linkShare,
  787. permissions: permissions,
  788. allowPublicUploadStatus: allowPublicUploadStatus,
  789. allowPublicEditingStatus: allowPublicEditingStatus,
  790. hideFileListStatus: hideFileListStatus
  791. };
  792. },
  793. /**
  794. * Parses a string to an valid integer (unix timestamp)
  795. * @param time
  796. * @returns {*}
  797. * @internal Only used to work around a bug in the backend
  798. */
  799. _parseTime: function(time) {
  800. if (_.isString(time)) {
  801. // skip empty strings and hex values
  802. if (time === '' || (time.length > 1 && time[0] === '0' && time[1] === 'x')) {
  803. return null;
  804. }
  805. time = parseInt(time, 10);
  806. if(isNaN(time)) {
  807. time = null;
  808. }
  809. }
  810. return time;
  811. },
  812. /**
  813. * Returns a list of share types from the existing shares.
  814. *
  815. * @return {Array.<int>} array of share types
  816. */
  817. getShareTypes: function() {
  818. var result;
  819. result = _.pluck(this.getSharesWithCurrentItem(), 'share_type');
  820. if (this.hasLinkShare()) {
  821. result.push(OC.Share.SHARE_TYPE_LINK);
  822. }
  823. return _.uniq(result);
  824. }
  825. });
  826. OC.Share.ShareItemModel = ShareItemModel;
  827. })();