}
});
},
- setPermissions:function(itemType, itemSource, shareType, shareWith, permissions) {
- $.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'setPermissions', itemType: itemType, itemSource: itemSource, shareType: shareType, shareWith: shareWith, permissions: permissions }, function(result) {
- if (!result || result.status !== 'success') {
- OC.dialogs.alert(t('core', 'Error while changing permissions'), t('core', 'Error'));
- }
- });
- },
showDropDown:function(itemType, itemSource, appendTo, link, possiblePermissions, filename) {
var configModel = new OC.Share.ShareConfigModel();
var attributes = {itemType: itemType, itemSource: itemSource, possiblePermissions: possiblePermissions};
this.$el.find('.expirationDateContainer').toggleClass('hidden', !state);
if (!state) {
// discard expiration date
- this.model.setExpirationDate('');
- this.model.saveLinkShare();
+ this.model.saveLinkShare({
+ expireDate: ''
+ });
}
},
$target.tooltip('hide');
$target.removeClass('error');
- this.model.setExpirationDate($target.val());
- this.model.saveLinkShare(null, {
+ this.model.saveLinkShare({
+ expiration: moment($target.val(), 'DD-MM-YYYY').format('YYYY-MM-DD')
+ }, {
error: function(model, message) {
if (!message) {
$target.attr('title', t('core', 'Error setting expiration date'));
onShowPasswordClick: function() {
this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
if(!this.$el.find('.showPasswordCheckbox').is(':checked')) {
- this.model.setPassword('');
- this.model.saveLinkShare();
+ this.model.saveLinkShare({
+ password: ''
+ });
} else {
this.$el.find('.linkPassText').focus();
}
},
onPasswordEntered: function() {
- var self = this;
var $loading = this.$el.find('.linkPass .icon-loading-small');
if (!$loading.hasClass('hidden')) {
// still in process
.removeClass('hidden')
.addClass('inlineblock');
- this.model.setPassword(password);
- this.model.saveLinkShare({}, {
+ this.model.saveLinkShare({
+ password: password
+ }, {
error: function(model, msg) {
$loading.removeClass('inlineblock').addClass('hidden');
$input.addClass('error');
onAllowPublicUploadChange: function() {
var $checkbox = this.$('.publicUploadCheckbox');
$checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
- this.model.setPublicUpload($checkbox.is(':checked'));
- this.model.saveLinkShare();
+
+ var permissions = OC.PERMISSION_READ;
+ if($checkbox.is(':checked')) {
+ permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ;
+ }
+
+ this.model.saveLinkShare({
+ permissions: permissions
+ });
},
_onEmailPrivateLink: function(event) {
var TEMPLATE =
'<ul id="shareWithList" class="shareWithList">' +
'{{#each sharees}}' +
- ' {{#if isCollection}}' +
- ' <li data-collection="{{collectionID}}">{{text}}</li>' +
- ' {{/if}}' +
- ' {{#unless isCollection}}' +
- ' <li data-share-type="{{shareType}}" data-share-with="{{shareWith}}" title="{{shareWith}}">' +
+ ' <li data-share-id="{{shareId}}" data-share-type="{{shareType}}" data-share-with="{{shareWith}}" title="{{shareWith}}">' +
' <a href="#" class="unshare"><span class="icon-loading-small hidden"></span><img class="svg" alt="{{unshareLabel}}" title="{{unshareLabel}}" src="{{unshareImage}}" /></a>' +
' {{#if avatarEnabled}}' +
' <div class="avatar {{#if modSeed}}imageplaceholderseed{{/if}}" data-username="{{shareWith}}" {{#if modSeed}}data-seed="{{shareWith}} {{shareType}}"{{/if}}></div>' +
' </div>' +
' {{/unless}}' +
' </li>' +
- ' {{/unless}}' +
'{{/each}}' +
'</ul>'
;
/** @type {Function} **/
_template: undefined,
- /** @type {boolean} **/
- showLink: true,
-
- /** @type {object} **/
- _collections: {},
-
events: {
'click .unshare': 'onUnshare',
'click .permissions': 'onPermissionChange',
});
},
- processCollectionShare: function(shareIndex) {
- var type = this.model.getCollectionType(shareIndex);
- var id = this.model.getCollectionPath(shareIndex);
- if(type !== 'file' && type !== 'folder') {
- id = this.model.getCollectionSource(shareIndex);
- }
- var displayName = this.model.getShareWithDisplayName(shareIndex);
- if(!_.isUndefined(this._collections[id])) {
- this._collections[id].text = this._collections[id].text + ", " + displayName;
- } else {
- this._collections[id] = {};
- this._collections[id].text = t('core', 'Shared in {item} with {user}', {'item': id, user: displayName});
- this._collections[id].id = id;
- this._collections[id].isCollection = true;
- }
- },
-
/**
*
* @param {OC.Share.Types.ShareInfo} shareInfo
shareWith: shareWith,
shareWithDisplayName: shareWithDisplayName,
shareType: shareType,
+ shareId: this.model.get('shares')[shareIndex].id,
modSeed: shareType !== OC.Share.SHARE_TYPE_USER,
isRemoteShare: shareType === OC.Share.SHARE_TYPE_REMOTE
});
deletePermission: OC.PERMISSION_DELETE
};
- this._collections = {};
-
if(!this.model.hasUserShares()) {
return [];
}
var shares = this.model.get('shares');
var list = [];
for(var index = 0; index < shares.length; index++) {
- if(this.model.isCollection(index)) {
- this.processCollectionShare(index);
- } else {
- // first empty {} is necessary, otherwise we get in trouble
- // with references
- list.push(_.extend({}, universal, this.getShareeObject(index)));
- }
+ // first empty {} is necessary, otherwise we get in trouble
+ // with references
+ list.push(_.extend({}, universal, this.getShareeObject(index)));
}
- list = _.union(_.values(this._collections), list);
return list;
},
},
onUnshare: function(event) {
+ var self = this;
var $element = $(event.target);
if (!$element.is('a')) {
$element = $element.closest('a');
$loading.removeClass('hidden');
var $li = $element.closest('li');
- var shareType = $li.data('share-type');
- var shareWith = $li.attr('data-share-with');
- this.model.removeShare(shareType, shareWith);
+ var shareId = $li.data('share-id');
+ self.model.removeShare(shareId)
+ .done(function() {
+ $li.remove();
+ })
+ .fail(function() {
+ $loading.addClass('hidden');
+ OC.Notification.showTemporary(t('core', 'Could not unshare'));
+ });
return false;
},
onPermissionChange: function(event) {
var $element = $(event.target);
var $li = $element.closest('li');
+ var shareId = $li.data('share-id');
var shareType = $li.data('share-type');
var shareWith = $li.attr('data-share-with');
permissions |= $(checkbox).data('permissions');
});
- this.model.setPermissions(shareType, shareWith, permissions);
+ this.model.updateShare(shareId, {permissions: permissions});
},
onCrudsToggle: function(event) {
* @property {number} stime share time
*/
- /**
- * @typedef {object} OC.Share.Types.Collection
- * @property {string} item_type
- * @property {string} path
- * @property {string} item_source TODO: verify
- */
-
/**
* @typedef {object} OC.Share.Types.Reshare
* @property {string} uid_owner
* @property {string} share_with
* @property {string} share_with_displayname
* @property {string} mail_send
- * @property {OC.Share.Types.Collection|undefined} collection
* @property {Date} expiration optional?
* @property {number} stime optional?
*/
* where the link share is one of them
*/
var ShareItemModel = OC.Backbone.Model.extend({
+ /**
+ * @type share id of the link share, if applicable
+ */
+ _linkShareId: null,
+
initialize: function(attributes, options) {
if(!_.isUndefined(options.configModel)) {
this.configModel = options.configModel;
* TODO: this should be a separate model
*/
saveLinkShare: function(attributes, options) {
- var model = this;
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
-
- // TODO: use backbone's default value mechanism once this is a separate model
- var requiredAttributes = [
- { name: 'password', defaultValue: '' },
- { name: 'passwordChanged', defaultValue: false },
- { name: 'permissions', defaultValue: OC.PERMISSION_READ },
- { name: 'expiration', defaultValue: this.configModel.getDefaultExpirationDateString() }
- ];
-
- attributes = attributes || {};
-
- // get attributes from the model and fill in with default values
- _.each(requiredAttributes, function(attribute) {
- // a provided options overrides a present value of the link
- // share. If neither is given, the default value is used.
- if(_.isUndefined(attribute[attribute.name])) {
- attributes[attribute.name] = attribute.defaultValue;
- var currentValue = model.get('linkShare')[attribute.name];
- if(!_.isUndefined(currentValue)) {
- attributes[attribute.name] = currentValue;
- }
- }
- });
+ options = options || {};
+ attributes = _.extend({}, attributes);
- var password = {
- password: attributes.password,
- passwordChanged: attributes.passwordChanged
- };
+ var shareId = null;
+ var call;
- OC.Share.share(
- itemType,
- itemSource,
- OC.Share.SHARE_TYPE_LINK,
- password,
- attributes.permissions,
- this.fileInfoModel.get('name'),
- attributes.expiration,
- function(result) {
- if (!result || result.status !== 'success') {
- model.fetch({
- success: function() {
- if (options && _.isFunction(options.success)) {
- options.success(model);
- }
- }
- });
- } else {
- if (options && _.isFunction(options.error)) {
- options.error(model);
- }
- }
- },
- function(result) {
- var msg = t('core', 'Error');
- if (result.data && result.data.message) {
- msg = result.data.message;
- }
+ // oh yeah...
+ if (attributes.expiration) {
+ attributes.expireDate = attributes.expiration;
+ delete attributes.expiration;
+ }
- if (options && _.isFunction(options.error)) {
- options.error(model, msg);
- } else {
- OC.dialogs.alert(msg, t('core', 'Error while sharing'));
- }
- }
- );
- },
+ if (this.get('linkShare') && this.get('linkShare').isLinkShare) {
+ shareId = this.get('linkShare').id;
- removeLinkShare: function() {
- this.removeShare(OC.Share.SHARE_TYPE_LINK, '');
- },
+ // note: update can only update a single value at a time
+ call = this.updateShare(shareId, attributes);
+ } else {
+ attributes = _.defaults(attributes, {
+ password: '',
+ passwordChanged: false,
+ permissions: OC.PERMISSION_READ,
+ expireDate: this.configModel.getDefaultExpirationDateString(),
+ shareType: OC.Share.SHARE_TYPE_LINK
+ });
- /**
- * Sets the public upload flag
- *
- * @param {bool} allow whether public upload is allowed
- */
- setPublicUpload: function(allow) {
- var permissions = OC.PERMISSION_READ;
- if(allow) {
- permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ;
+ call = this.addShare(attributes);
}
- this.get('linkShare').permissions = permissions;
+ return call;
},
- /**
- * Sets the expiration date of the public link
- *
- * @param {string} expiration expiration date
- */
- setExpirationDate: function(expiration) {
- this.get('linkShare').expiration = expiration;
- },
-
- /**
- * Set password of the public link share
- *
- * @param {string} password
- */
- setPassword: function(password) {
- this.get('linkShare').password = password;
- this.get('linkShare').passwordChanged = true;
+ removeLinkShare: function() {
+ if (this.get('linkShare')) {
+ return this.removeShare(this.get('linkShare').id);
+ }
},
addShare: function(attributes, options) {
var shareType = attributes.shareType;
- var shareWith = attributes.shareWith;
- var fileName = this.fileInfoModel.get('name');
options = options || {};
+ attributes = _.extend({}, attributes);
// Default permissions are Edit (CRUD) and Share
// Check if these permissions are possible
}
}
- var model = this;
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
- OC.Share.share(itemType, itemSource, shareType, shareWith, permissions, fileName, options.expiration, function() {
- model.fetch();
- });
- },
+ attributes.permissions = permissions;
+ if (_.isUndefined(attributes.path)) {
+ attributes.path = this.fileInfoModel.getFullPath();
+ }
- setPermissions: function(shareType, shareWith, permissions) {
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
+ var self = this;
+ return $.ajax({
+ type: 'POST',
+ url: this._getUrl('shares'),
+ data: attributes,
+ dataType: 'json'
+ }).done(function() {
+ self.fetch({
+ success: function() {
+ if (_.isFunction(options.success)) {
+ options.success(self);
+ }
+ }
+ });
+ }).fail(function(result) {
+ var msg = t('core', 'Error');
+ if (result.ocs && result.ocs.meta) {
+ msg = result.ocs.meta.message;
+ }
- // TODO: in the future, only set the permissions on the model but don't save directly
- OC.Share.setPermissions(itemType, itemSource, shareType, shareWith, permissions);
+ if (_.isFunction(options.error)) {
+ options.error(self, msg);
+ } else {
+ OC.dialogs.alert(msg, t('core', 'Error while sharing'));
+ }
+ });
},
- removeShare: function(shareType, shareWith) {
- var model = this;
- var itemType = this.get('itemType');
- var itemSource = this.get('itemSource');
+ updateShare: function(shareId, attrs) {
+ var self = this;
+ return $.ajax({
+ type: 'PUT',
+ url: this._getUrl('shares/' + encodeURIComponent(shareId)),
+ data: attrs,
+ dataType: 'json'
+ }).done(function() {
+ self.fetch();
+ });
+ },
- OC.Share.unshare(itemType, itemSource, shareType, shareWith, function() {
- model.fetch();
+ /**
+ * Deletes the share with the given id
+ *
+ * @param {int} shareId share id
+ * @return {jQuery}
+ */
+ removeShare: function(shareId) {
+ var self = this;
+ return $.ajax({
+ type: 'DELETE',
+ url: this._getUrl('shares/' + encodeURIComponent(shareId)),
+ }).done(function() {
+ self.fetch();
});
},
return false;
},
- /**
- * @param {number} shareIndex
- * @returns {string}
- */
- getCollectionType: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- } else if(_.isUndefined(share.collection)) {
- throw "Share is not a collection";
- }
-
- return share.collection.item_type;
- },
-
- /**
- * @param {number} shareIndex
- * @returns {string}
- */
- getCollectionPath: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- } else if(_.isUndefined(share.collection)) {
- throw "Share is not a collection";
- }
-
- return share.collection.path;
- },
-
- /**
- * @param {number} shareIndex
- * @returns {string}
- */
- getCollectionSource: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- } else if(_.isUndefined(share.collection)) {
- throw "Share is not a collection";
- }
-
- return share.collection.item_source;
- },
-
- /**
- * @param {number} shareIndex
- * @returns {boolean}
- */
- isCollection: function(shareIndex) {
- /** @type OC.Share.Types.ShareInfo **/
- var share = this.get('shares')[shareIndex];
- if(!_.isObject(share)) {
- throw "Unknown Share";
- }
- if(_.isUndefined(share.collection)) {
- return false;
- }
- return true;
- },
-
-
/**
* @returns {string}
*/
|| this.hasDeletePermission(shareIndex);
},
+ _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')]
+ }
+ }]);
+ }
+ },
+
fetch: function() {
var model = this;
this.trigger('request', this);
- OC.Share.loadItem(this.get('itemType'), this.get('itemSource'), function(data) {
+
+ var deferred = $.when(
+ this._fetchShares(),
+ this._fetchReshare()
+ );
+ deferred.done(function(data1, data2) {
model.trigger('sync', 'GET', this);
- model.set(model.parse(data));
+ var sharesMap = {};
+ _.each(data1[0].ocs.data, function(shareItem) {
+ sharesMap[shareItem.id] = shareItem;
+ });
+
+ var reshare = false;
+ if (data2[0].ocs.data.length) {
+ reshare = data2[0].ocs.data[0];
+ }
+
+ model.set(model.parse({
+ shares: sharesMap,
+ reshare: reshare
+ }));
});
+
+ return deferred;
},
/**
parse: function(data) {
if(data === false) {
console.warn('no data was returned');
- trigger('fetchError');
+ this.trigger('fetchError');
return {};
}
}
linkShare = {
isLinkShare: true,
+ id: share.id,
token: share.token,
password: share.share_with,
link: link,
var configModel;
var shareModel;
var listView;
- var setPermissionsStub;
+ var updateShareStub;
beforeEach(function () {
/* jshint camelcase:false */
oldCurrentUser = OC.currentUser;
OC.currentUser = 'user0';
- setPermissionsStub = sinon.stub(listView.model, 'setPermissions');
+ updateShareStub = sinon.stub(OC.Share.ShareItemModel.prototype, 'updateShare');
});
afterEach(function () {
/* jshint camelcase:false */
oc_appconfig.core = oldAppConfig;
listView.remove();
- setPermissionsStub.restore();
+ updateShareStub.restore();
});
describe('Manages checkbox events correctly', function () {
listView.render();
listView.$el.find("input[name='edit']").click();
expect(listView.$el.find("input[name='update']").is(':checked')).toEqual(true);
- expect(setPermissionsStub.called).toEqual(true);
+ expect(updateShareStub.calledOnce).toEqual(true);
});
it('Checks edit box when create/update/delete are checked', function () {
listView.render();
listView.$el.find("input[name='update']").click();
expect(listView.$el.find("input[name='edit']").is(':checked')).toEqual(true);
- expect(setPermissionsStub.called).toEqual(true);
+ expect(updateShareStub.calledOnce).toEqual(true);
});
it('shows cruds checkboxes when toggled', function () {
var avatarStub;
var placeholderStub;
var oldCurrentUser;
+ var saveLinkShareStub;
var fetchStub;
+ var notificationStub;
var configModel;
var shareModel;
oc_appconfig.core.enforcePasswordForPublicLink = false;
fetchStub = sinon.stub(OC.Share.ShareItemModel.prototype, 'fetch');
+ saveLinkShareStub = sinon.stub(OC.Share.ShareItemModel.prototype, 'saveLinkShare');
fileInfoModel = new OCA.Files.FileInfoModel({
id: 123,
dialog.remove();
fetchStub.restore();
+ saveLinkShareStub.restore();
autocompleteStub.restore();
avatarStub.restore();
it('update password on focus out', function() {
$('#allowShareWithLink').val('yes');
+ dialog.model.set('linkShare', {
+ isLinkShare: true
+ });
dialog.render();
- // Toggle linkshare
- dialog.$el.find('.linkCheckbox').click();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
// Enable password, enter password and focusout
dialog.$el.find('[name=showPassword]').click();
dialog.$el.find('.linkPassText').focus();
dialog.$el.find('.linkPassText').val('foo');
dialog.$el.find('.linkPassText').focusout();
- expect(fakeServer.requests[1].method).toEqual('POST');
- var body = OC.parseQueryString(fakeServer.requests[1].requestBody);
- expect(body['shareWith[password]']).toEqual('foo');
- expect(body['shareWith[passwordChanged]']).toEqual('true');
-
- fetchStub.reset();
-
- // Set password response
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
- expect(fetchStub.calledOnce).toEqual(true);
- // fetching the model will rerender the view
- dialog.render();
-
- expect(dialog.$el.find('.linkPassText').val()).toEqual('');
- expect(dialog.$el.find('.linkPassText').attr('placeholder')).toEqual('**********');
+ expect(saveLinkShareStub.calledOnce).toEqual(true);
+ expect(saveLinkShareStub.firstCall.args[0]).toEqual({
+ password: 'foo'
+ });
});
it('update password on enter', function() {
$('#allowShareWithLink').val('yes');
+ dialog.model.set('linkShare', {
+ isLinkShare: true
+ });
dialog.render();
// Toggle linkshare
dialog.$el.find('.linkCheckbox').click();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
// Enable password and enter password
dialog.$el.find('[name=showPassword]').click();
dialog.$el.find('.linkPassText').val('foo');
dialog.$el.find('.linkPassText').trigger(new $.Event('keyup', {keyCode: 13}));
- expect(fakeServer.requests[1].method).toEqual('POST');
- var body = OC.parseQueryString(fakeServer.requests[1].requestBody);
- expect(body['shareWith[password]']).toEqual('foo');
- expect(body['shareWith[passwordChanged]']).toEqual('true');
-
- fetchStub.reset();
-
- // Set password response
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
- expect(fetchStub.calledOnce).toEqual(true);
- // fetching the model will rerender the view
- dialog.render();
-
- expect(dialog.$el.find('.linkPassText').val()).toEqual('');
- expect(dialog.$el.find('.linkPassText').attr('placeholder')).toEqual('**********');
+ expect(saveLinkShareStub.calledOnce).toEqual(true);
+ expect(saveLinkShareStub.firstCall.args[0]).toEqual({
+ password: 'foo'
+ });
});
it('shows share with link checkbox when allowed', function() {
$('#allowShareWithLink').val('yes');
it('autofocus link text when clicked', function() {
$('#allowShareWithLink').val('yes');
+ dialog.model.set('linkShare', {
+ isLinkShare: true
+ });
dialog.render();
- // Toggle linkshare
- dialog.$el.find('.linkCheckbox').click();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({data: {token: 'xyz'}, status: 'success'})
- );
-
var focusStub = sinon.stub($.fn, 'focus');
var selectStub = sinon.stub($.fn, 'select');
dialog.$el.find('.linkText').click();
});
});
});
- describe('share permissions', function() {
- beforeEach(function() {
- oc_appconfig.core.resharingAllowed = true;
- });
-
- /**
- * Tests sharing with the given possible permissions
- *
- * @param {int} possiblePermissions
- * @return {int} permissions sent to the server
- */
- function testWithPermissions(possiblePermissions) {
- shareModel.set({
- permissions: possiblePermissions,
- possiblePermissions: possiblePermissions
- });
- dialog.render();
- var autocompleteOptions = autocompleteStub.getCall(0).args[0];
- // simulate autocomplete selection
- autocompleteOptions.select(new $.Event('select'), {
- item: {
- label: 'User Two',
- value: {
- shareType: OC.Share.SHARE_TYPE_USER,
- shareWith: 'user2'
- }
- }
- });
- autocompleteStub.reset();
- var requestBody = OC.parseQueryString(_.last(fakeServer.requests).requestBody);
- return parseInt(requestBody.permissions, 10);
- }
-
- describe('regular sharing', function() {
- it('shares with given permissions with default config', function() {
- shareModel.set({
- reshare: {},
- shares: []
- });
- expect(
- testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE);
- expect(
- testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_SHARE);
- });
- it('removes share permission when not allowed', function() {
- configModel.set('isResharingAllowed', false);
- shareModel.set({
- reshare: {},
- shares: []
- });
- expect(
- testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE);
- });
- it('automatically adds READ permission even when not specified', function() {
- configModel.set('isResharingAllowed', false);
- shareModel.set({
- reshare: {},
- shares: []
- });
- expect(
- testWithPermissions(OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
- ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_UPDATE);
- });
- it('does not show sharing options when sharing not allowed', function() {
- shareModel.set({
- reshare: {},
- shares: [],
- permissions: OC.PERMISSION_READ
- });
- dialog.render();
- expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
- });
- it('shows reshare owner', function() {
- shareModel.set({
- reshare: {
- uid_owner: 'user1'
- },
- shares: [],
- permissions: OC.PERMISSION_READ
- });
- dialog.render();
- expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(1);
- });
- it('does not show reshare owner if owner is current user', function() {
- shareModel.set({
- reshare: {
- uid_owner: OC.currentUser
- },
- shares: [],
- permissions: OC.PERMISSION_READ
- });
- dialog.render();
- expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(0);
- });
- });
- });
-
describe('remote sharing', function() {
it('shows remote share info when allowed', function() {
configModel.set({
expect(el.hasClass('user')).toEqual(true);
});
});
+
+ it('calls addShare after selection', function() {
+ dialog.render();
+ var addShareStub = sinon.stub(shareModel, 'addShare');
+ var autocompleteOptions = autocompleteStub.getCall(0).args[0];
+ autocompleteOptions.select(new $.Event('select'), {
+ item: {
+ label: 'User Two',
+ value: {
+ shareType: OC.Share.SHARE_TYPE_USER,
+ shareWith: 'user2'
+ }
+ }
+ });
+
+ expect(addShareStub.calledOnce).toEqual(true);
+ expect(addShareStub.firstCall.args[0]).toEqual({
+ shareType: OC.Share.SHARE_TYPE_USER,
+ shareWith: 'user2'
+ });
+
+ addShareStub.restore();
+ });
+ });
+ describe('reshare permissions', function() {
+ it('does not show sharing options when sharing not allowed', function() {
+ shareModel.set({
+ reshare: {},
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+ dialog.render();
+ expect(dialog.$el.find('.shareWithField').prop('disabled')).toEqual(true);
+ });
+ it('shows reshare owner', function() {
+ shareModel.set({
+ reshare: {
+ uid_owner: 'user1'
+ },
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+ dialog.render();
+ expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(1);
+ });
+ it('does not show reshare owner if owner is current user', function() {
+ shareModel.set({
+ reshare: {
+ uid_owner: OC.currentUser
+ },
+ shares: [],
+ permissions: OC.PERMISSION_READ
+ });
+ dialog.render();
+ expect(dialog.$el.find('.resharerInfoView .reshare').length).toEqual(0);
+ });
});
});
/* global oc_appconfig */
describe('OC.Share.ShareItemModel', function() {
- var loadItemStub;
+ var fetchSharesStub, fetchReshareStub;
+ var fetchSharesDeferred, fetchReshareDeferred;
var fileInfoModel, configModel, model;
var oldCurrentUser;
beforeEach(function() {
oldCurrentUser = OC.currentUser;
- loadItemStub = sinon.stub(OC.Share, 'loadItem');
+ fetchSharesDeferred = new $.Deferred();
+ fetchSharesStub = sinon.stub(OC.Share.ShareItemModel.prototype, '_fetchShares')
+ .returns(fetchSharesDeferred.promise());
+ fetchReshareDeferred = new $.Deferred();
+ fetchReshareStub = sinon.stub(OC.Share.ShareItemModel.prototype, '_fetchReshare')
+ .returns(fetchReshareDeferred.promise());
fileInfoModel = new OCA.Files.FileInfoModel({
id: 123,
});
});
afterEach(function() {
- loadItemStub.restore();
+ if (fetchSharesStub) {
+ fetchSharesStub.restore();
+ }
+ if (fetchReshareStub) {
+ fetchReshareStub.restore();
+ }
OC.currentUser = oldCurrentUser;
});
+ function makeOcsResponse(data) {
+ return [{
+ ocs: {
+ data: data
+ }
+ }];
+ }
+
describe('Fetching and parsing', function() {
- it('fetching calls loadItem with the correct arguments', function() {
+ it('fetches both outgoing shares and the current incoming share', function() {
model.fetch();
- expect(loadItemStub.calledOnce).toEqual(true);
- expect(loadItemStub.calledWith('file', 123)).toEqual(true);
+ expect(fetchSharesStub.calledOnce).toEqual(true);
+ expect(fetchReshareStub.calledOnce).toEqual(true);
+ });
+ it('fetches shares for the current path', function() {
+ fetchSharesStub.restore();
+
+ model._fetchShares();
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('GET');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares?format=json&path=%2Fsubdir%2Fshared_file_name.txt&reshares=true'
+ );
+
+ fetchSharesStub = null;
+ });
+ it('fetches reshare for the current path', function() {
+ fetchReshareStub.restore();
+
+ model._fetchReshare();
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('GET');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares?format=json&path=%2Fsubdir%2Fshared_file_name.txt&shared_with_me=true'
+ );
+
+ fetchReshareStub = null;
});
it('populates attributes with parsed response', function() {
- loadItemStub.yields({
- /* jshint camelcase: false */
- reshare: {
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([
+ {
share_type: OC.Share.SHARE_TYPE_USER,
uid_owner: 'owner',
displayname_owner: 'Owner',
permissions: 31
- },
- shares: [{
+ }
+ ]));
+ fetchSharesDeferred.resolve(makeOcsResponse([
+ {
id: 100,
item_source: 123,
permissions: 31,
storage: 1,
token: 'tehtoken',
uid_owner: 'root'
- }]
- });
+ }
+ ]));
+
model.fetch();
var shares = model.get('shares');
// TODO: check more attributes
});
it('does not parse link share when for a different file', function() {
- loadItemStub.yields({
- reshare: [],
- /* jshint camelcase: false */
- shares: [{
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
displayname_owner: 'root',
expiration: null,
file_source: 456,
token: 'tehtoken',
uid_owner: 'root'
}]
- });
+ ));
model.fetch();
expect(linkShare.isLinkShare).toEqual(false);
});
it('parses correct link share when a nested link share exists along with parent one', function() {
- loadItemStub.yields({
- reshare: [],
- /* jshint camelcase: false */
- shares: [{
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
displayname_owner: 'root',
expiration: '2015-10-12 00:00:00',
file_source: 123,
token: 'anothertoken',
uid_owner: 'root'
}]
- });
+ ));
model.fetch();
// TODO: check child too
});
it('reduces reshare permissions to the ones from the original share', function() {
- loadItemStub.yields({
- reshare: {
- permissions: OC.PERMISSION_READ,
- uid_owner: 'user1'
- },
- shares: []
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([{
+ id: 123,
+ permissions: OC.PERMISSION_READ,
+ uid_owner: 'user1'
+ }]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.fetch();
// no resharing allowed
expect(model.get('permissions')).toEqual(OC.PERMISSION_READ);
});
it('reduces reshare permissions to possible permissions', function() {
- loadItemStub.yields({
- reshare: {
- permissions: OC.PERMISSION_ALL,
- uid_owner: 'user1'
- },
- shares: []
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([{
+ id: 123,
+ permissions: OC.PERMISSION_ALL,
+ uid_owner: 'user1'
+ }]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.set('possiblePermissions', OC.PERMISSION_READ);
model.fetch();
});
it('allows owner to share their own share when they are also the recipient', function() {
OC.currentUser = 'user1';
- loadItemStub.yields({
- reshare: {},
- shares: []
- });
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.fetch();
expect(model.get('permissions') & OC.PERMISSION_SHARE).toEqual(OC.PERMISSION_SHARE);
});
it('properly parses integer values when the server is in the mood of returning ints as string', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
displayname_owner: 'root',
expiration: '2015-10-12 00:00:00',
file_source: '123',
token: 'tehtoken',
uid_owner: 'root'
}]
- });
+ ));
model.fetch();
});
describe('hasUserShares', function() {
it('returns false when no user shares exist', function() {
- loadItemStub.yields({
- reshare: {},
- shares: []
- });
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([]));
model.fetch();
expect(model.hasUserShares()).toEqual(false);
});
it('returns true when user shares exist on the current item', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
- id: 1,
- share_type: OC.Share.SHARE_TYPE_USER,
- share_with: 'user1',
- item_source: '123'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user1',
+ item_source: '123'
+ }]));
model.fetch();
expect(model.hasUserShares()).toEqual(true);
});
it('returns true when group shares exist on the current item', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
- id: 1,
- share_type: OC.Share.SHARE_TYPE_GROUP,
- share_with: 'group1',
- item_source: '123'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group1',
+ item_source: '123'
+ }]));
model.fetch();
expect(model.hasUserShares()).toEqual(true);
});
it('returns false when share exist on parent item', function() {
- loadItemStub.yields({
- reshare: {},
- shares: [{
- id: 1,
- share_type: OC.Share.SHARE_TYPE_GROUP,
- share_with: 'group1',
- item_source: '111'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ id: 1,
+ share_type: OC.Share.SHARE_TYPE_GROUP,
+ share_with: 'group1',
+ item_source: '111'
+ }]));
model.fetch();
describe('sendEmailPrivateLink', function() {
it('succeeds', function() {
- loadItemStub.yields({
- shares: [{
- displayname_owner: 'root',
- expiration: null,
- file_source: 123,
- file_target: '/folder',
- id: 20,
- item_source: '123',
- item_type: 'folder',
- mail_send: '0',
- parent: null,
- path: '/folder',
- permissions: OC.PERMISSION_READ,
- share_type: OC.Share.SHARE_TYPE_LINK,
- share_with: null,
- stime: 1403884258,
- storage: 1,
- token: 'tehtoken',
- uid_owner: 'root'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ displayname_owner: 'root',
+ expiration: null,
+ file_source: 123,
+ file_target: '/folder',
+ id: 20,
+ item_source: '123',
+ item_type: 'folder',
+ mail_send: '0',
+ parent: null,
+ path: '/folder',
+ permissions: OC.PERMISSION_READ,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ stime: 1403884258,
+ storage: 1,
+ token: 'tehtoken',
+ uid_owner: 'root'
+ }]));
+
model.fetch();
var res = model.sendEmailPrivateLink('foo@bar.com');
});
it('fails', function() {
- loadItemStub.yields({
- shares: [{
- displayname_owner: 'root',
- expiration: null,
- file_source: 123,
- file_target: '/folder',
- id: 20,
- item_source: '123',
- item_type: 'folder',
- mail_send: '0',
- parent: null,
- path: '/folder',
- permissions: OC.PERMISSION_READ,
- share_type: OC.Share.SHARE_TYPE_LINK,
- share_with: null,
- stime: 1403884258,
- storage: 1,
- token: 'tehtoken',
- uid_owner: 'root'
- }]
- });
+ /* jshint camelcase: false */
+ fetchReshareDeferred.resolve(makeOcsResponse([]));
+ fetchSharesDeferred.resolve(makeOcsResponse([{
+ displayname_owner: 'root',
+ expiration: null,
+ file_source: 123,
+ file_target: '/folder',
+ id: 20,
+ item_source: '123',
+ item_type: 'folder',
+ mail_send: '0',
+ parent: null,
+ path: '/folder',
+ permissions: OC.PERMISSION_READ,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ stime: 1403884258,
+ storage: 1,
+ token: 'tehtoken',
+ uid_owner: 'root'
+ }]));
+
model.fetch();
var res = model.sendEmailPrivateLink('foo@bar.com');
expect(res.state()).toEqual('rejected');
});
});
+ describe('share permissions', function() {
+ beforeEach(function() {
+ oc_appconfig.core.resharingAllowed = true;
+ });
+
+ /**
+ * Tests sharing with the given possible permissions
+ *
+ * @param {int} possiblePermissions
+ * @return {int} permissions sent to the server
+ */
+ function testWithPermissions(possiblePermissions) {
+ model.set({
+ permissions: possiblePermissions,
+ possiblePermissions: possiblePermissions
+ });
+ model.addShare({
+ shareType: OC.Share.SHARE_TYPE_USER,
+ shareWith: 'user2'
+ });
+
+ var requestBody = OC.parseQueryString(_.last(fakeServer.requests).requestBody);
+ return parseInt(requestBody.permissions, 10);
+ }
+
+ describe('regular sharing', function() {
+ it('shares with given permissions with default config', function() {
+ configModel.set('isResharingAllowed', true);
+ model.set({
+ reshare: {},
+ shares: []
+ });
+ expect(
+ testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE);
+ expect(
+ testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_SHARE);
+ });
+ it('removes share permission when not allowed', function() {
+ configModel.set('isResharingAllowed', false);
+ model.set({
+ reshare: {},
+ shares: []
+ });
+ expect(
+ testWithPermissions(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE);
+ });
+ it('automatically adds READ permission even when not specified', function() {
+ configModel.set('isResharingAllowed', false);
+ model.set({
+ reshare: {},
+ shares: []
+ });
+ expect(
+ testWithPermissions(OC.PERMISSION_UPDATE | OC.PERMISSION_SHARE)
+ ).toEqual(OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_UPDATE);
+ });
+ });
+ });
+
+ describe('saveLinkShare', function() {
+ var addShareStub;
+ var updateShareStub;
+
+ beforeEach(function() {
+ addShareStub = sinon.stub(model, 'addShare');
+ updateShareStub = sinon.stub(model, 'updateShare');
+ });
+ afterEach(function() {
+ addShareStub.restore();
+ updateShareStub.restore();
+ });
+
+ it('creates a new share if no link share exists', function() {
+ model.set({
+ linkShare: {
+ isLinkShare: false
+ }
+ });
+
+ model.saveLinkShare();
+
+ expect(addShareStub.calledOnce).toEqual(true);
+ expect(addShareStub.firstCall.args[0]).toEqual({
+ password: '',
+ passwordChanged: false,
+ permissions: OC.PERMISSION_READ,
+ expireDate: '',
+ shareType: OC.Share.SHARE_TYPE_LINK
+ });
+ expect(updateShareStub.notCalled).toEqual(true);
+ });
+ it('creates a new share with default expiration date', function() {
+ var clock = sinon.useFakeTimers(Date.UTC(2015, 6, 17, 1, 2, 0, 3));
+ configModel.set({
+ isDefaultExpireDateEnabled: true,
+ defaultExpireDate: 7
+ });
+ model.set({
+ linkShare: {
+ isLinkShare: false
+ }
+ });
+
+ model.saveLinkShare();
+
+ expect(addShareStub.calledOnce).toEqual(true);
+ expect(addShareStub.firstCall.args[0]).toEqual({
+ password: '',
+ passwordChanged: false,
+ permissions: OC.PERMISSION_READ,
+ expireDate: '2015-7-24 00:00:00',
+ shareType: OC.Share.SHARE_TYPE_LINK
+ });
+ expect(updateShareStub.notCalled).toEqual(true);
+ clock.restore();
+ });
+ it('updates link share if it exists', function() {
+ model.set({
+ linkShare: {
+ isLinkShare: true,
+ id: 123
+ }
+ });
+
+ model.saveLinkShare({
+ password: 'test'
+ });
+
+ expect(addShareStub.notCalled).toEqual(true);
+ expect(updateShareStub.calledOnce).toEqual(true);
+ expect(updateShareStub.firstCall.args[0]).toEqual(123);
+ expect(updateShareStub.firstCall.args[1]).toEqual({
+ password: 'test'
+ });
+ });
+ });
+ describe('creating shares', function() {
+ it('sends POST method to endpoint with passed values', function() {
+ model.addShare({
+ shareType: OC.Share.SHARE_TYPE_GROUP,
+ shareWith: 'group1'
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares?format=json'
+ );
+ expect(OC.parseQueryString(fakeServer.requests[0].requestBody)).toEqual({
+ path: '/subdir/shared_file_name.txt',
+ permissions: '' + OC.PERMISSION_READ,
+ shareType: '' + OC.Share.SHARE_TYPE_GROUP,
+ shareWith: 'group1'
+ });
+ });
+ });
+ describe('updating shares', function() {
+ it('sends PUT method to endpoint with passed values', function() {
+ model.updateShare(123, {
+ permissions: OC.PERMISSION_READ | OC.PERMISSION_SHARE
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('PUT');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares/123?format=json'
+ );
+ expect(OC.parseQueryString(fakeServer.requests[0].requestBody)).toEqual({
+ permissions: '' + (OC.PERMISSION_READ | OC.PERMISSION_SHARE)
+ });
+ });
+ });
+ describe('removing shares', function() {
+ it('sends DELETE method to endpoint with share id', function() {
+ model.removeShare(123);
+
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('DELETE');
+ expect(fakeServer.requests[0].url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1', 2) +
+ 'shares/123?format=json'
+ );
+ });
+ });
});