2015-07-31 01:07:41 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015
|
|
|
|
*
|
|
|
|
* This file is licensed under the Affero General Public License version 3
|
|
|
|
* or later.
|
|
|
|
*
|
|
|
|
* See the COPYING-README file.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
if(!OC.Share) {
|
|
|
|
OC.Share = {};
|
|
|
|
OC.Share.Types = {};
|
|
|
|
}
|
|
|
|
|
2015-09-03 16:53:17 +03:00
|
|
|
/**
|
|
|
|
* @typedef {object} OC.Share.Types.LinkShareInfo
|
|
|
|
* @property {bool} isLinkShare
|
|
|
|
* @property {string} token
|
|
|
|
* @property {string|null} password
|
|
|
|
* @property {string} link
|
2015-09-12 18:02:03 +03:00
|
|
|
* @property {number} permissions
|
2015-09-04 16:31:45 +03:00
|
|
|
* @property {Date} expiration
|
|
|
|
* @property {number} stime share time
|
2015-09-03 16:53:17 +03:00
|
|
|
*/
|
|
|
|
|
2015-07-31 01:07:41 +03:00
|
|
|
/**
|
|
|
|
* @typedef {object} OC.Share.Types.Reshare
|
|
|
|
* @property {string} uid_owner
|
|
|
|
* @property {number} share_type
|
|
|
|
* @property {string} share_with
|
|
|
|
* @property {string} displayname_owner
|
|
|
|
* @property {number} permissions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {object} OC.Share.Types.ShareInfo
|
|
|
|
* @property {number} share_type
|
|
|
|
* @property {number} permissions
|
|
|
|
* @property {number} file_source optional
|
|
|
|
* @property {number} item_source
|
|
|
|
* @property {string} token
|
|
|
|
* @property {string} share_with
|
|
|
|
* @property {string} share_with_displayname
|
2017-06-06 14:21:42 +03:00
|
|
|
* @property {string} share_with_avatar
|
2015-09-23 13:14:09 +03:00
|
|
|
* @property {string} mail_send
|
2015-07-31 01:07:41 +03:00
|
|
|
* @property {Date} expiration optional?
|
|
|
|
* @property {number} stime optional?
|
2016-02-10 18:00:55 +03:00
|
|
|
* @property {string} uid_owner
|
2017-04-10 18:07:45 +03:00
|
|
|
* @property {string} displayname_owner
|
2015-07-31 01:07:41 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {object} OC.Share.Types.ShareItemInfo
|
|
|
|
* @property {OC.Share.Types.Reshare} reshare
|
|
|
|
* @property {OC.Share.Types.ShareInfo[]} shares
|
2015-09-03 16:53:17 +03:00
|
|
|
* @property {OC.Share.Types.LinkShareInfo|undefined} linkShare
|
2015-07-31 01:07:41 +03:00
|
|
|
*/
|
|
|
|
|
2015-09-23 13:14:09 +03:00
|
|
|
/**
|
|
|
|
* These properties are sometimes returned by the server as strings instead
|
|
|
|
* of integers, so we need to convert them accordingly...
|
|
|
|
*/
|
|
|
|
var SHARE_RESPONSE_INT_PROPS = [
|
|
|
|
'id', 'file_parent', 'mail_send', 'file_source', 'item_source', 'permissions',
|
2015-09-24 13:21:19 +03:00
|
|
|
'storage', 'share_type', 'parent', 'stime'
|
2015-09-23 13:14:09 +03:00
|
|
|
];
|
|
|
|
|
2015-07-31 01:07:41 +03:00
|
|
|
/**
|
|
|
|
* @class OCA.Share.ShareItemModel
|
|
|
|
* @classdesc
|
|
|
|
*
|
|
|
|
* Represents the GUI of the share dialogue
|
|
|
|
*
|
2015-08-11 15:10:25 +03:00
|
|
|
* // FIXME: use OC Share API once #17143 is done
|
2015-09-14 13:48:01 +03:00
|
|
|
*
|
|
|
|
* // TODO: this really should be a collection of share item models instead,
|
|
|
|
* where the link share is one of them
|
2015-07-31 01:07:41 +03:00
|
|
|
*/
|
2015-08-10 23:23:52 +03:00
|
|
|
var ShareItemModel = OC.Backbone.Model.extend({
|
2016-01-22 19:30:18 +03:00
|
|
|
/**
|
|
|
|
* @type share id of the link share, if applicable
|
|
|
|
*/
|
|
|
|
_linkShareId: null,
|
|
|
|
|
2015-08-13 03:38:14 +03:00
|
|
|
initialize: function(attributes, options) {
|
|
|
|
if(!_.isUndefined(options.configModel)) {
|
|
|
|
this.configModel = options.configModel;
|
|
|
|
}
|
2015-09-03 16:53:17 +03:00
|
|
|
if(!_.isUndefined(options.fileInfoModel)) {
|
|
|
|
/** @type {OC.Files.FileInfo} **/
|
|
|
|
this.fileInfoModel = options.fileInfoModel;
|
|
|
|
}
|
2015-09-05 03:02:55 +03:00
|
|
|
|
|
|
|
_.bindAll(this, 'addShare');
|
2015-07-31 01:07:41 +03:00
|
|
|
},
|
|
|
|
|
2015-08-12 00:14:44 +03:00
|
|
|
defaults: {
|
2015-08-25 00:37:04 +03:00
|
|
|
allowPublicUploadStatus: false,
|
2015-09-03 16:53:17 +03:00
|
|
|
permissions: 0,
|
|
|
|
linkShare: {}
|
2015-08-12 00:14:44 +03:00
|
|
|
},
|
|
|
|
|
2015-09-14 13:48:01 +03:00
|
|
|
/**
|
|
|
|
* Saves the current link share information.
|
|
|
|
*
|
2017-04-24 23:05:34 +03:00
|
|
|
* This will trigger an ajax call and, if successful, refetch the model
|
|
|
|
* afterwards. Callbacks "success", "error" and "complete" can be given
|
|
|
|
* in the options object; "success" is called after a successful save
|
|
|
|
* once the model is refetch, "error" is called after a failed save, and
|
|
|
|
* "complete" is called both after a successful save and after a failed
|
|
|
|
* save. Note that "complete" is called before "success" and "error" are
|
|
|
|
* called (unlike in jQuery, in which it is called after them); this
|
|
|
|
* ensures that "complete" is called even if refetching the model fails.
|
2015-09-14 13:48:01 +03:00
|
|
|
*
|
|
|
|
* TODO: this should be a separate model
|
|
|
|
*/
|
|
|
|
saveLinkShare: function(attributes, options) {
|
2016-01-22 19:30:18 +03:00
|
|
|
options = options || {};
|
|
|
|
attributes = _.extend({}, attributes);
|
2015-09-12 18:02:03 +03:00
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
var shareId = null;
|
|
|
|
var call;
|
2015-10-22 18:32:40 +03:00
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
// oh yeah...
|
|
|
|
if (attributes.expiration) {
|
|
|
|
attributes.expireDate = attributes.expiration;
|
|
|
|
delete attributes.expiration;
|
|
|
|
}
|
2015-09-14 13:48:01 +03:00
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
if (this.get('linkShare') && this.get('linkShare').isLinkShare) {
|
|
|
|
shareId = this.get('linkShare').id;
|
2015-09-12 15:21:14 +03:00
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
// note: update can only update a single value at a time
|
2016-01-28 19:07:51 +03:00
|
|
|
call = this.updateShare(shareId, attributes, options);
|
2016-01-22 19:30:18 +03:00
|
|
|
} else {
|
|
|
|
attributes = _.defaults(attributes, {
|
|
|
|
password: '',
|
|
|
|
passwordChanged: false,
|
|
|
|
permissions: OC.PERMISSION_READ,
|
|
|
|
expireDate: this.configModel.getDefaultExpirationDateString(),
|
|
|
|
shareType: OC.Share.SHARE_TYPE_LINK
|
|
|
|
});
|
2015-09-12 15:21:14 +03:00
|
|
|
|
2016-01-28 19:07:51 +03:00
|
|
|
call = this.addShare(attributes, options);
|
2015-09-14 02:01:02 +03:00
|
|
|
}
|
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
return call;
|
2015-09-14 13:48:01 +03:00
|
|
|
},
|
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
removeLinkShare: function() {
|
|
|
|
if (this.get('linkShare')) {
|
|
|
|
return this.removeShare(this.get('linkShare').id);
|
|
|
|
}
|
2015-09-14 02:01:02 +03:00
|
|
|
},
|
|
|
|
|
2015-09-14 18:47:47 +03:00
|
|
|
addShare: function(attributes, options) {
|
|
|
|
var shareType = attributes.shareType;
|
2016-01-22 19:30:18 +03:00
|
|
|
attributes = _.extend({}, attributes);
|
2015-09-05 03:02:55 +03:00
|
|
|
|
2017-12-01 13:35:01 +03:00
|
|
|
// get default permissions
|
|
|
|
var defaultPermissions = OC.getCapabilities()['files_sharing']['default_permissions'] || OC.PERMISSION_ALL;
|
|
|
|
var possiblePermissions = OC.PERMISSION_READ;
|
|
|
|
|
2016-04-18 18:15:20 +03:00
|
|
|
if (this.updatePermissionPossible()) {
|
2017-12-01 13:35:01 +03:00
|
|
|
possiblePermissions = possiblePermissions | OC.PERMISSION_UPDATE;
|
2016-04-18 18:15:20 +03:00
|
|
|
}
|
|
|
|
if (this.createPermissionPossible()) {
|
2017-12-01 13:35:01 +03:00
|
|
|
possiblePermissions = possiblePermissions | OC.PERMISSION_CREATE;
|
2016-04-18 18:15:20 +03:00
|
|
|
}
|
|
|
|
if (this.deletePermissionPossible()) {
|
2017-12-01 13:35:01 +03:00
|
|
|
possiblePermissions = possiblePermissions | OC.PERMISSION_DELETE;
|
2016-04-18 18:15:20 +03:00
|
|
|
}
|
|
|
|
if (this.configModel.get('isResharingAllowed') && (this.sharePermissionPossible())) {
|
2017-12-01 13:35:01 +03:00
|
|
|
possiblePermissions = possiblePermissions | OC.PERMISSION_SHARE;
|
2015-09-05 03:02:55 +03:00
|
|
|
}
|
|
|
|
|
2017-12-01 13:35:01 +03:00
|
|
|
attributes.permissions = defaultPermissions & possiblePermissions;
|
2016-01-22 19:30:18 +03:00
|
|
|
if (_.isUndefined(attributes.path)) {
|
|
|
|
attributes.path = this.fileInfoModel.getFullPath();
|
|
|
|
}
|
2015-09-05 03:02:55 +03:00
|
|
|
|
2017-04-24 23:07:08 +03:00
|
|
|
return this._addOrUpdateShare({
|
2016-01-22 19:30:18 +03:00
|
|
|
type: 'POST',
|
|
|
|
url: this._getUrl('shares'),
|
|
|
|
data: attributes,
|
|
|
|
dataType: 'json'
|
2017-04-24 23:07:08 +03:00
|
|
|
}, options);
|
2015-09-14 03:29:22 +03:00
|
|
|
},
|
|
|
|
|
2016-01-28 19:07:51 +03:00
|
|
|
updateShare: function(shareId, attrs, options) {
|
2017-04-24 23:07:08 +03:00
|
|
|
return this._addOrUpdateShare({
|
2016-01-22 19:30:18 +03:00
|
|
|
type: 'PUT',
|
|
|
|
url: this._getUrl('shares/' + encodeURIComponent(shareId)),
|
|
|
|
data: attrs,
|
|
|
|
dataType: 'json'
|
2017-04-24 23:07:08 +03:00
|
|
|
}, options);
|
|
|
|
},
|
|
|
|
|
|
|
|
_addOrUpdateShare: function(ajaxSettings, options) {
|
|
|
|
var self = this;
|
|
|
|
options = options || {};
|
|
|
|
|
|
|
|
return $.ajax(
|
|
|
|
ajaxSettings
|
|
|
|
).always(function() {
|
2017-04-24 22:18:29 +03:00
|
|
|
if (_.isFunction(options.complete)) {
|
|
|
|
options.complete(self);
|
|
|
|
}
|
2016-01-22 19:30:18 +03:00
|
|
|
}).done(function() {
|
2017-04-24 23:07:08 +03:00
|
|
|
self.fetch().done(function() {
|
|
|
|
if (_.isFunction(options.success)) {
|
|
|
|
options.success(self);
|
2016-01-28 19:07:51 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}).fail(function(xhr) {
|
|
|
|
var msg = t('core', 'Error');
|
|
|
|
var result = xhr.responseJSON;
|
2017-04-24 23:07:08 +03:00
|
|
|
if (result && result.ocs && result.ocs.meta) {
|
2016-01-28 19:07:51 +03:00
|
|
|
msg = result.ocs.meta.message;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_.isFunction(options.error)) {
|
|
|
|
options.error(self, msg);
|
|
|
|
} else {
|
|
|
|
OC.dialogs.alert(msg, t('core', 'Error while sharing'));
|
|
|
|
}
|
2016-01-22 19:30:18 +03:00
|
|
|
});
|
|
|
|
},
|
2015-09-14 02:24:21 +03:00
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
/**
|
|
|
|
* Deletes the share with the given id
|
|
|
|
*
|
|
|
|
* @param {int} shareId share id
|
|
|
|
* @return {jQuery}
|
|
|
|
*/
|
2016-01-28 19:07:51 +03:00
|
|
|
removeShare: function(shareId, options) {
|
2016-01-22 19:30:18 +03:00
|
|
|
var self = this;
|
2016-01-28 19:07:51 +03:00
|
|
|
options = options || {};
|
2016-01-22 19:30:18 +03:00
|
|
|
return $.ajax({
|
|
|
|
type: 'DELETE',
|
|
|
|
url: this._getUrl('shares/' + encodeURIComponent(shareId)),
|
|
|
|
}).done(function() {
|
2016-01-28 19:07:51 +03:00
|
|
|
self.fetch({
|
|
|
|
success: function() {
|
|
|
|
if (_.isFunction(options.success)) {
|
|
|
|
options.success(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}).fail(function(xhr) {
|
|
|
|
var msg = t('core', 'Error');
|
|
|
|
var result = xhr.responseJSON;
|
|
|
|
if (result.ocs && result.ocs.meta) {
|
|
|
|
msg = result.ocs.meta.message;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_.isFunction(options.error)) {
|
|
|
|
options.error(self, msg);
|
|
|
|
} else {
|
|
|
|
OC.dialogs.alert(msg, t('core', 'Error removing share'));
|
|
|
|
}
|
2015-09-14 02:24:21 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2015-08-12 00:14:44 +03:00
|
|
|
/**
|
2015-08-13 03:38:14 +03:00
|
|
|
* @returns {boolean}
|
2015-08-12 00:14:44 +03:00
|
|
|
*/
|
2015-08-13 03:38:14 +03:00
|
|
|
isPublicUploadAllowed: function() {
|
|
|
|
return this.get('allowPublicUploadStatus');
|
|
|
|
},
|
|
|
|
|
2017-01-24 15:24:46 +03:00
|
|
|
isPublicEditingAllowed: function() {
|
|
|
|
return this.get('allowPublicEditingStatus');
|
|
|
|
},
|
|
|
|
|
2016-06-07 13:28:02 +03:00
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
isHideFileListSet: function() {
|
|
|
|
return this.get('hideFileListStatus');
|
|
|
|
},
|
|
|
|
|
2015-08-13 03:38:14 +03:00
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
isFolder: function() {
|
|
|
|
return this.get('itemType') === 'folder';
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
isFile: function() {
|
|
|
|
return this.get('itemType') === 'file';
|
2015-08-12 00:14:44 +03:00
|
|
|
},
|
|
|
|
|
2015-08-11 15:10:25 +03:00
|
|
|
/**
|
|
|
|
* whether this item has reshare information
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2015-07-31 01:07:41 +03:00
|
|
|
hasReshare: function() {
|
2015-08-21 16:00:15 +03:00
|
|
|
var reshare = this.get('reshare');
|
|
|
|
return _.isObject(reshare) && !_.isUndefined(reshare.uid_owner);
|
2015-07-31 01:07:41 +03:00
|
|
|
},
|
|
|
|
|
2015-08-11 23:36:28 +03:00
|
|
|
/**
|
2015-09-14 18:20:51 +03:00
|
|
|
* whether this item has user share information
|
2015-08-11 23:36:28 +03:00
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2015-09-14 18:20:51 +03:00
|
|
|
hasUserShares: function() {
|
2015-09-23 13:44:25 +03:00
|
|
|
return this.getSharesWithCurrentItem().length > 0;
|
2015-09-14 18:20:51 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether this item has a link share
|
|
|
|
*
|
|
|
|
* @return {bool} true if a link share exists, false otherwise
|
|
|
|
*/
|
|
|
|
hasLinkShare: function() {
|
|
|
|
var linkShare = this.get('linkShare');
|
|
|
|
if (linkShare && linkShare.isLinkShare) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2015-08-11 23:36:28 +03:00
|
|
|
},
|
|
|
|
|
2015-08-11 15:10:25 +03:00
|
|
|
/**
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2015-07-31 01:07:41 +03:00
|
|
|
getReshareOwner: function() {
|
2015-08-10 23:23:52 +03:00
|
|
|
return this.get('reshare').uid_owner;
|
2015-07-31 01:07:41 +03:00
|
|
|
},
|
|
|
|
|
2015-08-11 15:10:25 +03:00
|
|
|
/**
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2015-07-31 01:07:41 +03:00
|
|
|
getReshareOwnerDisplayname: function() {
|
2015-08-10 23:23:52 +03:00
|
|
|
return this.get('reshare').displayname_owner;
|
2015-07-31 01:07:41 +03:00
|
|
|
},
|
|
|
|
|
2018-07-20 12:22:24 +03:00
|
|
|
/**
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getReshareNote: function() {
|
|
|
|
return this.get('reshare').note;
|
|
|
|
},
|
|
|
|
|
2015-08-11 15:10:25 +03:00
|
|
|
/**
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2015-07-31 01:07:41 +03:00
|
|
|
getReshareWith: function() {
|
2015-08-10 23:23:52 +03:00
|
|
|
return this.get('reshare').share_with;
|
2015-07-31 01:07:41 +03:00
|
|
|
},
|
|
|
|
|
2016-11-30 22:56:10 +03:00
|
|
|
/**
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getReshareWithDisplayName: function() {
|
|
|
|
var reshare = this.get('reshare');
|
|
|
|
return reshare.share_with_displayname || reshare.share_with;
|
|
|
|
},
|
|
|
|
|
2015-08-11 15:10:25 +03:00
|
|
|
/**
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
2015-07-31 01:07:41 +03:00
|
|
|
getReshareType: function() {
|
2015-08-10 23:23:52 +03:00
|
|
|
return this.get('reshare').share_type;
|
2015-07-31 01:07:41 +03:00
|
|
|
},
|
|
|
|
|
2017-03-29 17:50:23 +03:00
|
|
|
getExpireDate: function(shareIndex) {
|
|
|
|
return this._shareExpireDate(shareIndex);
|
|
|
|
},
|
|
|
|
|
2018-07-18 18:42:30 +03:00
|
|
|
getNote: function(shareIndex) {
|
|
|
|
return this._shareNote(shareIndex);
|
|
|
|
},
|
|
|
|
|
2015-09-23 13:44:25 +03:00
|
|
|
/**
|
|
|
|
* Returns all share entries that only apply to the current item
|
|
|
|
* (file/folder)
|
|
|
|
*
|
|
|
|
* @return {Array.<OC.Share.Types.ShareInfo>}
|
|
|
|
*/
|
|
|
|
getSharesWithCurrentItem: function() {
|
|
|
|
var shares = this.get('shares') || [];
|
|
|
|
var fileId = this.fileInfoModel.get('id');
|
|
|
|
return _.filter(shares, function(share) {
|
|
|
|
return share.item_source === fileId;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2015-09-01 13:43:04 +03:00
|
|
|
/**
|
|
|
|
* @param shareIndex
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getShareWith: function(shareIndex) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.share_with;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param shareIndex
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getShareWithDisplayName: function(shareIndex) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.share_with_displayname;
|
|
|
|
},
|
|
|
|
|
2017-06-06 14:21:42 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param shareIndex
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getShareWithAvatar: function(shareIndex) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.share_with_avatar;
|
|
|
|
},
|
|
|
|
|
2017-04-10 18:07:45 +03:00
|
|
|
/**
|
|
|
|
* @param shareIndex
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getSharedBy: function(shareIndex) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.uid_owner;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param shareIndex
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getSharedByDisplayName: function(shareIndex) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.displayname_owner;
|
|
|
|
},
|
|
|
|
|
2016-11-29 14:51:37 +03:00
|
|
|
/**
|
|
|
|
* returns the array index of a sharee for a provided shareId
|
|
|
|
*
|
|
|
|
* @param shareId
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
findShareWithIndex: function(shareId) {
|
|
|
|
var shares = this.get('shares');
|
|
|
|
if(!_.isArray(shares)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
for(var i = 0; i < shares.length; i++) {
|
|
|
|
var shareWith = shares[i];
|
2016-12-02 14:27:15 +03:00
|
|
|
if(shareWith.id === shareId) {
|
2016-11-29 14:51:37 +03:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw "Unknown Sharee";
|
|
|
|
},
|
|
|
|
|
2015-09-01 13:43:04 +03:00
|
|
|
getShareType: function(shareIndex) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.share_type;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* whether a share from shares has the requested permission
|
|
|
|
*
|
|
|
|
* @param {number} shareIndex
|
|
|
|
* @param {number} permission
|
|
|
|
* @returns {boolean}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_shareHasPermission: function(shareIndex, permission) {
|
|
|
|
/** @type OC.Share.Types.ShareInfo **/
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return (share.permissions & permission) === permission;
|
|
|
|
},
|
|
|
|
|
2017-03-29 17:50:23 +03:00
|
|
|
|
|
|
|
_shareExpireDate: function(shareIndex) {
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
var date2 = share.expiration;
|
|
|
|
return date2;
|
|
|
|
},
|
|
|
|
|
2018-07-18 18:42:30 +03:00
|
|
|
|
|
|
|
_shareNote: function(shareIndex) {
|
|
|
|
var share = this.get('shares')[shareIndex];
|
|
|
|
if(!_.isObject(share)) {
|
|
|
|
throw "Unknown Share";
|
|
|
|
}
|
|
|
|
return share.note;
|
|
|
|
},
|
|
|
|
|
2017-03-09 15:56:27 +03:00
|
|
|
/**
|
|
|
|
* @return {int}
|
|
|
|
*/
|
|
|
|
getPermissions: function() {
|
|
|
|
return this.get('permissions');
|
|
|
|
},
|
|
|
|
|
2015-08-12 00:14:44 +03:00
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2015-09-01 13:43:04 +03:00
|
|
|
sharePermissionPossible: function() {
|
2015-08-25 00:37:04 +03:00
|
|
|
return (this.get('permissions') & OC.PERMISSION_SHARE) === OC.PERMISSION_SHARE;
|
2015-08-13 03:38:14 +03:00
|
|
|
},
|
|
|
|
|
2015-09-01 13:43:04 +03:00
|
|
|
/**
|
|
|
|
* @param {number} shareIndex
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
hasSharePermission: function(shareIndex) {
|
|
|
|
return this._shareHasPermission(shareIndex, OC.PERMISSION_SHARE);
|
|
|
|
},
|
|
|
|
|
2015-08-13 03:38:14 +03:00
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2015-09-01 13:43:04 +03:00
|
|
|
createPermissionPossible: function() {
|
2015-08-25 00:37:04 +03:00
|
|
|
return (this.get('permissions') & OC.PERMISSION_CREATE) === OC.PERMISSION_CREATE;
|
2015-08-12 00:14:44 +03:00
|
|
|
},
|
|
|
|
|
2015-09-01 13:43:04 +03:00
|
|
|
/**
|
|
|
|
* @param {number} shareIndex
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
hasCreatePermission: function(shareIndex) {
|
|
|
|
return this._shareHasPermission(shareIndex, OC.PERMISSION_CREATE);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
updatePermissionPossible: function() {
|
|
|
|
return (this.get('permissions') & OC.PERMISSION_UPDATE) === OC.PERMISSION_UPDATE;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} shareIndex
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
hasUpdatePermission: function(shareIndex) {
|
|
|
|
return this._shareHasPermission(shareIndex, OC.PERMISSION_UPDATE);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
deletePermissionPossible: function() {
|
|
|
|
return (this.get('permissions') & OC.PERMISSION_DELETE) === OC.PERMISSION_DELETE;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} shareIndex
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
hasDeletePermission: function(shareIndex) {
|
|
|
|
return this._shareHasPermission(shareIndex, OC.PERMISSION_DELETE);
|
|
|
|
},
|
|
|
|
|
2017-03-29 12:58:04 +03:00
|
|
|
hasReadPermission: function(shareIndex) {
|
|
|
|
return this._shareHasPermission(shareIndex, OC.PERMISSION_READ);
|
|
|
|
},
|
|
|
|
|
2015-09-01 13:43:04 +03:00
|
|
|
/**
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
editPermissionPossible: function() {
|
|
|
|
return this.createPermissionPossible()
|
|
|
|
|| this.updatePermissionPossible()
|
|
|
|
|| this.deletePermissionPossible();
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2018-02-15 23:10:39 +03:00
|
|
|
* @returns {string}
|
|
|
|
* The state that the 'can edit' permission checkbox should have.
|
|
|
|
* Possible values:
|
|
|
|
* - empty string: no permission
|
|
|
|
* - 'checked': all applicable permissions
|
|
|
|
* - 'indeterminate': some but not all permissions
|
|
|
|
*/
|
|
|
|
editPermissionState: function(shareIndex) {
|
|
|
|
var hcp = this.hasCreatePermission(shareIndex);
|
|
|
|
var hup = this.hasUpdatePermission(shareIndex);
|
|
|
|
var hdp = this.hasDeletePermission(shareIndex);
|
|
|
|
if (!hcp && !hup && !hdp) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
if ( (this.createPermissionPossible() && !hcp)
|
|
|
|
|| (this.updatePermissionPossible() && !hup)
|
|
|
|
|| (this.deletePermissionPossible() && !hdp) ) {
|
|
|
|
return 'indeterminate';
|
|
|
|
}
|
|
|
|
return 'checked';
|
2015-09-01 13:43:04 +03:00
|
|
|
},
|
|
|
|
|
2017-03-09 15:56:27 +03:00
|
|
|
/**
|
|
|
|
* @returns {int}
|
|
|
|
*/
|
|
|
|
linkSharePermissions: function() {
|
|
|
|
if (!this.hasLinkShare()) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return this.get('linkShare').permissions;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-01-22 19:30:18 +03:00
|
|
|
_getUrl: function(base, params) {
|
|
|
|
params = _.extend({format: 'json'}, params || {});
|
|
|
|
return OC.linkToOCS('apps/files_sharing/api/v1', 2) + base + '?' + OC.buildQueryString(params);
|
|
|
|
},
|
|
|
|
|
|
|
|
_fetchShares: function() {
|
|
|
|
var path = this.fileInfoModel.getFullPath();
|
|
|
|
return $.ajax({
|
|
|
|
type: 'GET',
|
|
|
|
url: this._getUrl('shares', {path: path, reshares: true})
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
_fetchReshare: function() {
|
|
|
|
// only fetch original share once
|
|
|
|
if (!this._reshareFetched) {
|
|
|
|
var path = this.fileInfoModel.getFullPath();
|
|
|
|
this._reshareFetched = true;
|
|
|
|
return $.ajax({
|
|
|
|
type: 'GET',
|
|
|
|
url: this._getUrl('shares', {path: path, shared_with_me: true})
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return $.Deferred().resolve([{
|
|
|
|
ocs: {
|
|
|
|
data: [this.get('reshare')]
|
|
|
|
}
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-07-13 16:46:02 +03:00
|
|
|
/**
|
|
|
|
* Group reshares into a single super share element.
|
|
|
|
* Does this by finding the most precise share and
|
|
|
|
* combines the permissions to be the most permissive.
|
|
|
|
*
|
|
|
|
* @param {Array} reshares
|
|
|
|
* @return {Object} reshare
|
|
|
|
*/
|
|
|
|
_groupReshares: function(reshares) {
|
|
|
|
if (!reshares || !reshares.length) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var superShare = reshares.shift();
|
|
|
|
var combinedPermissions = superShare.permissions;
|
|
|
|
_.each(reshares, function(reshare) {
|
|
|
|
// use share have higher priority than group share
|
|
|
|
if (reshare.share_type === OC.Share.SHARE_TYPE_USER && superShare.share_type === OC.Share.SHARE_TYPE_GROUP) {
|
|
|
|
superShare = reshare;
|
|
|
|
}
|
|
|
|
combinedPermissions |= reshare.permissions;
|
|
|
|
});
|
|
|
|
|
|
|
|
superShare.permissions = combinedPermissions;
|
|
|
|
return superShare;
|
|
|
|
},
|
|
|
|
|
2016-12-02 15:14:25 +03:00
|
|
|
fetch: function(options) {
|
2015-08-11 23:36:28 +03:00
|
|
|
var model = this;
|
2015-09-28 16:57:57 +03:00
|
|
|
this.trigger('request', this);
|
2016-01-22 19:30:18 +03:00
|
|
|
|
|
|
|
var deferred = $.when(
|
|
|
|
this._fetchShares(),
|
|
|
|
this._fetchReshare()
|
|
|
|
);
|
|
|
|
deferred.done(function(data1, data2) {
|
2015-09-28 16:57:57 +03:00
|
|
|
model.trigger('sync', 'GET', this);
|
2016-01-22 19:30:18 +03:00
|
|
|
var sharesMap = {};
|
|
|
|
_.each(data1[0].ocs.data, function(shareItem) {
|
|
|
|
sharesMap[shareItem.id] = shareItem;
|
|
|
|
});
|
|
|
|
|
|
|
|
var reshare = false;
|
|
|
|
if (data2[0].ocs.data.length) {
|
2016-07-13 16:46:02 +03:00
|
|
|
reshare = model._groupReshares(data2[0].ocs.data);
|
2016-01-22 19:30:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
model.set(model.parse({
|
|
|
|
shares: sharesMap,
|
|
|
|
reshare: reshare
|
|
|
|
}));
|
2016-12-02 15:14:25 +03:00
|
|
|
|
|
|
|
if(!_.isUndefined(options) && _.isFunction(options.success)) {
|
|
|
|
options.success();
|
|
|
|
}
|
2015-08-11 23:36:28 +03:00
|
|
|
});
|
2016-01-22 19:30:18 +03:00
|
|
|
|
|
|
|
return deferred;
|
2015-08-11 15:10:25 +03:00
|
|
|
},
|
|
|
|
|
2015-09-14 18:20:51 +03:00
|
|
|
/**
|
|
|
|
* Updates OC.Share.itemShares and OC.Share.statuses.
|
|
|
|
*
|
|
|
|
* This is required in case the user navigates away and comes back,
|
|
|
|
* the share statuses from the old arrays are still used to fill in the icons
|
|
|
|
* in the file list.
|
|
|
|
*/
|
|
|
|
_legacyFillCurrentShares: function(shares) {
|
|
|
|
var fileId = this.fileInfoModel.get('id');
|
|
|
|
if (!shares || !shares.length) {
|
|
|
|
delete OC.Share.statuses[fileId];
|
2015-09-21 14:16:50 +03:00
|
|
|
OC.Share.currentShares = {};
|
|
|
|
OC.Share.itemShares = [];
|
2015-09-14 18:20:51 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var currentShareStatus = OC.Share.statuses[fileId];
|
|
|
|
if (!currentShareStatus) {
|
|
|
|
currentShareStatus = {link: false};
|
|
|
|
OC.Share.statuses[fileId] = currentShareStatus;
|
|
|
|
}
|
|
|
|
currentShareStatus.link = false;
|
|
|
|
|
2015-09-02 17:47:25 +03:00
|
|
|
OC.Share.currentShares = {};
|
|
|
|
OC.Share.itemShares = [];
|
|
|
|
_.each(shares,
|
|
|
|
/**
|
|
|
|
* @param {OC.Share.Types.ShareInfo} share
|
|
|
|
*/
|
|
|
|
function(share) {
|
2015-09-14 18:20:51 +03:00
|
|
|
if (share.share_type === OC.Share.SHARE_TYPE_LINK) {
|
|
|
|
OC.Share.itemShares[share.share_type] = true;
|
|
|
|
currentShareStatus.link = true;
|
|
|
|
} else {
|
|
|
|
if (!OC.Share.itemShares[share.share_type]) {
|
|
|
|
OC.Share.itemShares[share.share_type] = [];
|
|
|
|
}
|
|
|
|
OC.Share.itemShares[share.share_type].push(share.share_with);
|
2015-09-02 17:47:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2015-08-11 15:10:25 +03:00
|
|
|
parse: function(data) {
|
2015-07-31 01:07:41 +03:00
|
|
|
if(data === false) {
|
|
|
|
console.warn('no data was returned');
|
2016-01-22 19:30:18 +03:00
|
|
|
this.trigger('fetchError');
|
2015-08-11 15:10:25 +03:00
|
|
|
return {};
|
2015-07-31 01:07:41 +03:00
|
|
|
}
|
2015-08-12 00:14:44 +03:00
|
|
|
|
2018-08-15 16:21:01 +03:00
|
|
|
var permissions = this.fileInfoModel.get('permissions');
|
2015-09-15 16:47:45 +03:00
|
|
|
if(!_.isUndefined(data.reshare) && !_.isUndefined(data.reshare.permissions) && data.reshare.uid_owner !== OC.currentUser) {
|
2015-08-12 00:14:44 +03:00
|
|
|
permissions = permissions & data.reshare.permissions;
|
|
|
|
}
|
|
|
|
|
|
|
|
var allowPublicUploadStatus = false;
|
|
|
|
if(!_.isUndefined(data.shares)) {
|
|
|
|
$.each(data.shares, function (key, value) {
|
|
|
|
if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
|
|
|
|
allowPublicUploadStatus = (value.permissions & OC.PERMISSION_CREATE) ? true : false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-01-24 15:24:46 +03:00
|
|
|
var allowPublicEditingStatus = true;
|
|
|
|
if(!_.isUndefined(data.shares)) {
|
|
|
|
$.each(data.shares, function (key, value) {
|
|
|
|
if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
|
|
|
|
allowPublicEditingStatus = (value.permissions & OC.PERMISSION_UPDATE) ? true : false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-07 13:28:02 +03:00
|
|
|
var hideFileListStatus = false;
|
|
|
|
if(!_.isUndefined(data.shares)) {
|
|
|
|
$.each(data.shares, function (key, value) {
|
|
|
|
if (value.share_type === OC.Share.SHARE_TYPE_LINK) {
|
|
|
|
hideFileListStatus = (value.permissions & OC.PERMISSION_READ) ? false : true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-09-03 16:53:17 +03:00
|
|
|
/** @type {OC.Share.Types.ShareInfo[]} **/
|
2015-09-23 13:14:09 +03:00
|
|
|
var shares = _.map(data.shares, function(share) {
|
|
|
|
// properly parse some values because sometimes the server
|
|
|
|
// returns integers as string...
|
|
|
|
var i;
|
|
|
|
for (i = 0; i < SHARE_RESPONSE_INT_PROPS.length; i++) {
|
|
|
|
var prop = SHARE_RESPONSE_INT_PROPS[i];
|
|
|
|
if (!_.isUndefined(share[prop])) {
|
|
|
|
share[prop] = parseInt(share[prop], 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return share;
|
|
|
|
});
|
|
|
|
|
2015-09-14 18:20:51 +03:00
|
|
|
this._legacyFillCurrentShares(shares);
|
2015-09-02 17:47:25 +03:00
|
|
|
|
2015-09-03 16:53:17 +03:00
|
|
|
var linkShare = { isLinkShare: false };
|
|
|
|
// filter out the share by link
|
|
|
|
shares = _.reject(shares,
|
|
|
|
/**
|
|
|
|
* @param {OC.Share.Types.ShareInfo} share
|
|
|
|
*/
|
|
|
|
function(share) {
|
|
|
|
var isShareLink =
|
|
|
|
share.share_type === OC.Share.SHARE_TYPE_LINK
|
|
|
|
&& ( share.file_source === this.get('itemSource')
|
|
|
|
|| share.item_source === this.get('itemSource'));
|
|
|
|
|
|
|
|
if (isShareLink) {
|
2016-02-10 18:00:55 +03:00
|
|
|
/*
|
|
|
|
* Ignore reshared link shares for now
|
|
|
|
* FIXME: Find a way to display properly
|
|
|
|
*/
|
|
|
|
if (share.uid_owner !== OC.currentUser) {
|
2016-08-28 21:59:12 +03:00
|
|
|
return;
|
2016-02-10 18:00:55 +03:00
|
|
|
}
|
|
|
|
|
2015-09-03 16:53:17 +03:00
|
|
|
var link = window.location.protocol + '//' + window.location.host;
|
|
|
|
if (!share.token) {
|
|
|
|
// pre-token link
|
|
|
|
var fullPath = this.fileInfoModel.get('path') + '/' +
|
|
|
|
this.fileInfoModel.get('name');
|
|
|
|
var location = '/' + OC.currentUser + '/files' + fullPath;
|
|
|
|
var type = this.fileInfoModel.isDirectory() ? 'folder' : 'file';
|
|
|
|
link += OC.linkTo('', 'public.php') + '?service=files&' +
|
|
|
|
type + '=' + encodeURIComponent(location);
|
|
|
|
} else {
|
|
|
|
link += OC.generateUrl('/s/') + share.token;
|
|
|
|
}
|
|
|
|
linkShare = {
|
|
|
|
isLinkShare: true,
|
2016-01-22 19:30:18 +03:00
|
|
|
id: share.id,
|
2015-09-03 16:53:17 +03:00
|
|
|
token: share.token,
|
2017-04-24 15:41:41 +03:00
|
|
|
password: share.share_with,
|
2015-09-04 16:31:45 +03:00
|
|
|
link: link,
|
2015-09-12 18:02:03 +03:00
|
|
|
permissions: share.permissions,
|
2015-09-04 16:31:45 +03:00
|
|
|
// currently expiration is only effective for link shares.
|
|
|
|
expiration: share.expiration,
|
|
|
|
stime: share.stime
|
2015-09-03 16:53:17 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
return share;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
this
|
|
|
|
);
|
|
|
|
|
2015-08-25 00:37:04 +03:00
|
|
|
return {
|
2015-08-10 23:23:52 +03:00
|
|
|
reshare: data.reshare,
|
2015-09-02 17:47:25 +03:00
|
|
|
shares: shares,
|
2015-09-03 16:53:17 +03:00
|
|
|
linkShare: linkShare,
|
2015-08-12 00:14:44 +03:00
|
|
|
permissions: permissions,
|
2016-06-07 13:28:02 +03:00
|
|
|
allowPublicUploadStatus: allowPublicUploadStatus,
|
2017-01-24 15:24:46 +03:00
|
|
|
allowPublicEditingStatus: allowPublicEditingStatus,
|
2016-06-07 13:28:02 +03:00
|
|
|
hideFileListStatus: hideFileListStatus
|
2015-08-10 23:23:52 +03:00
|
|
|
};
|
2015-09-15 16:47:45 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses a string to an valid integer (unix timestamp)
|
|
|
|
* @param time
|
|
|
|
* @returns {*}
|
|
|
|
* @internal Only used to work around a bug in the backend
|
|
|
|
*/
|
|
|
|
_parseTime: function(time) {
|
|
|
|
if (_.isString(time)) {
|
|
|
|
// skip empty strings and hex values
|
|
|
|
if (time === '' || (time.length > 1 && time[0] === '0' && time[1] === 'x')) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
time = parseInt(time, 10);
|
|
|
|
if(isNaN(time)) {
|
|
|
|
time = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return time;
|
2016-08-17 13:25:58 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a list of share types from the existing shares.
|
|
|
|
*
|
|
|
|
* @return {Array.<int>} array of share types
|
|
|
|
*/
|
|
|
|
getShareTypes: function() {
|
|
|
|
var result;
|
|
|
|
result = _.pluck(this.getSharesWithCurrentItem(), 'share_type');
|
|
|
|
if (this.hasLinkShare()) {
|
|
|
|
result.push(OC.Share.SHARE_TYPE_LINK);
|
|
|
|
}
|
|
|
|
return _.uniq(result);
|
2015-07-31 01:07:41 +03:00
|
|
|
}
|
2015-08-10 23:23:52 +03:00
|
|
|
});
|
2015-07-31 01:07:41 +03:00
|
|
|
|
|
|
|
OC.Share.ShareItemModel = ShareItemModel;
|
|
|
|
})();
|