summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.drone.yml22
m---------3rdparty0
-rw-r--r--apps/comments/css/comments.css11
-rw-r--r--apps/comments/js/commentstabview.js34
-rw-r--r--apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php4
-rw-r--r--apps/files/js/filelist.js5
-rw-r--r--apps/files_sharing/js/share.js50
-rw-r--r--apps/files_sharing/js/sharedfilelist.js47
-rw-r--r--apps/files_sharing/tests/js/shareSpec.js89
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js4
-rwxr-xr-xautotest.sh4
-rw-r--r--core/js/share.js44
-rw-r--r--core/js/tests/specs/shareSpec.js147
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/DB/ConnectionFactory.php3
-rw-r--r--lib/private/DB/OCPostgreSqlPlatform.php95
-rw-r--r--tests/lib/DB/OCPostgreSqlPlatformTest.php35
18 files changed, 320 insertions, 276 deletions
diff --git a/.drone.yml b/.drone.yml
index 2f2867a5b2b..186969ccd06 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -299,6 +299,7 @@ pipeline:
matrix:
DB: postgres
PHP: 5.6
+ POSTGRES: 9
postgres-php7.0:
image: nextcloudci/php7.0:php7.0-16
commands:
@@ -746,12 +747,19 @@ matrix:
ENABLE_REDIS: true
- DB: postgres
PHP: 5.6
+ POSTGRES: 9
ENABLE_REDIS: true
- DB: postgres
PHP: 7.0
+ POSTGRES: 9
ENABLE_REDIS: true
- DB: postgres
PHP: 7.1
+ POSTGRES: 9
+ ENABLE_REDIS: true
+ - DB: postgres
+ PHP: 7.1
+ POSTGRES: 10
ENABLE_REDIS: true
- DB: mysqlmb4
PHP: 5.6
@@ -833,7 +841,7 @@ services:
when:
matrix:
ENABLE_REDIS_CLUSTER: true
- postgres:
+ postgres-9:
image: postgres:9
environment:
- POSTGRES_USER=oc_autotest
@@ -843,6 +851,18 @@ services:
when:
matrix:
DB: postgres
+ POSTGRES: 9
+ postgres-10:
+ image: postgres:10
+ environment:
+ - POSTGRES_USER=oc_autotest
+ - POSTGRES_PASSWORD=owncloud
+ tmpfs:
+ - /var/lib/postgresql/data
+ when:
+ matrix:
+ DB: postgres
+ POSTGRES: 10
mysql:
image: mysql:5.7
environment:
diff --git a/3rdparty b/3rdparty
-Subproject ec71700daf6aab080502f67ecfca274dcb0bb3d
+Subproject f4e328bc4cc67011d206ca024483531a3b8c544
diff --git a/apps/comments/css/comments.css b/apps/comments/css/comments.css
index ccfad1d39f1..646f5f1100c 100644
--- a/apps/comments/css/comments.css
+++ b/apps/comments/css/comments.css
@@ -140,6 +140,17 @@
.atwho-view-ul * .avatar-name-wrapper,
#commentsTabView .comment .authorRow {
position: relative;
+}
+
+#commentsTabView .comment:not(.newCommentRow) .message .avatar-name-wrapper:not(.currentUser),
+#commentsTabView .comment:not(.newCommentRow) .message .avatar-name-wrapper:not(.currentUser) .avatar,
+#commentsTabView .comment .authorRow .avatar:not(.currentUser),
+#commentsTabView .comment .authorRow .author:not(.currentUser) {
+ cursor: pointer;
+}
+
+.atwho-view-ul .avatar-name-wrapper,
+.atwho-view-ul .avatar-name-wrapper .avatar {
cursor: pointer;
display: inline-flex;
align-items: center;
diff --git a/apps/comments/js/commentstabview.js b/apps/comments/js/commentstabview.js
index 5767ecfc9da..0c43e156985 100644
--- a/apps/comments/js/commentstabview.js
+++ b/apps/comments/js/commentstabview.js
@@ -23,8 +23,8 @@
var EDIT_COMMENT_TEMPLATE =
'<div class="newCommentRow comment" data-id="{{id}}">' +
' <div class="authorRow">' +
- ' <div class="avatar" data-username="{{actorId}}"></div>' +
- ' <div class="author">{{actorDisplayName}}</div>' +
+ ' <div class="avatar currentUser" data-username="{{actorId}}"></div>' +
+ ' <div class="author currentUser">{{actorDisplayName}}</div>' +
'{{#if isEditMode}}' +
' <a href="#" class="action delete icon icon-delete has-tooltip" title="{{deleteTooltip}}"></a>' +
' <div class="deleteLoading icon-loading-small hidden"></div>'+
@@ -43,8 +43,8 @@
var COMMENT_TEMPLATE =
'<li class="comment{{#if isUnread}} unread{{/if}}{{#if isLong}} collapsed{{/if}}" data-id="{{id}}">' +
' <div class="authorRow">' +
- ' <div class="avatar" {{#if actorId}}data-username="{{actorId}}"{{/if}}> </div>' +
- ' <div class="author">{{actorDisplayName}}</div>' +
+ ' <div class="avatar{{#if isUserAuthor}} currentUser{{/if}}" {{#if actorId}}data-username="{{actorId}}"{{/if}}> </div>' +
+ ' <div class="author{{#if isUserAuthor}} currentUser{{/if}}">{{actorDisplayName}}</div>' +
'{{#if isUserAuthor}}' +
' <a href="#" class="action edit icon icon-rename has-tooltip" title="{{editTooltip}}"></a>' +
'{{/if}}' +
@@ -215,13 +215,15 @@
searchKey: "label"
});
$target.on('inserted.atwho', function (je, $el) {
+ var editionMode = true;
s._postRenderItem(
// we need to pass the parent of the inserted element
// passing the whole comments form would re-apply and request
// avatars from the server
$(je.target).find(
'div[data-username="' + $el.find('[data-username]').data('username') + '"]'
- ).parent()
+ ).parent(),
+ editionMode
);
});
},
@@ -378,7 +380,7 @@
});
},
- _postRenderItem: function($el) {
+ _postRenderItem: function($el, editionMode) {
$el.find('.has-tooltip').tooltip();
$el.find('.avatar').each(function() {
var $this = $(this);
@@ -396,16 +398,23 @@
// it is the case when writing a comment and mentioning a person
$message = $el;
}
- this._postRenderMessage($message);
+ this._postRenderMessage($message, editionMode);
},
- _postRenderMessage: function($el) {
+ _postRenderMessage: function($el, editionMode) {
+ if (editionMode) {
+ return;
+ }
+
$el.find('.avatar').each(function() {
var avatar = $(this);
var strong = $(this).next();
var appendTo = $(this).parent();
- $.merge(avatar, strong).contactsMenu(avatar.data('user'), 0, appendTo);
+ var username = $(this).data('username');
+ if (username !== oc_current_user) {
+ $.merge(avatar, strong).contactsMenu(avatar.data('user'), 0, appendTo);
+ }
});
},
@@ -446,9 +455,11 @@
+ ' data-user-display-name="'
+ _.escape(displayName) + '"></div>';
+ var isCurrentUser = (uid === OC.getCurrentUser().uid);
+
return ''
+ '<span class="atwho-inserted" contenteditable="false">'
- + '<span class="avatar-name-wrapper">'
+ + '<span class="avatar-name-wrapper' + (isCurrentUser ? ' currentUser' : '') + '">'
+ avatar + ' <strong>'+ _.escape(displayName)+'</strong>'
+ '</span>'
+ '</span>';
@@ -487,7 +498,8 @@
.html(this._formatMessage(commentToEdit.get('message'), commentToEdit.get('mentions')))
.find('.avatar')
.each(function () { $(this).avatar(); });
- this._postRenderItem($message);
+ var editionMode = true;
+ this._postRenderItem($message, editionMode);
// Enable autosize
autosize($formRow.find('.message'));
diff --git a/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php b/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php
index b66cad7e8ed..68c9a1b415f 100644
--- a/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php
+++ b/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php
@@ -33,6 +33,7 @@ use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\InvalidSyncToken;
use Sabre\DAV\Exception\NotAuthenticated;
use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Exception\NotImplemented;
use Sabre\DAV\Exception\PreconditionFailed;
use Sabre\DAV\Exception\ServiceUnavailable;
@@ -57,6 +58,9 @@ class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin {
// Happens when an external storage or federated share is temporarily
// not available
StorageNotAvailableException::class => true,
+ // happens if some a client uses the wrong method for a given URL
+ // the error message itself is visible on the client side anyways
+ NotImplemented::class => true,
];
/** @var string */
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 6996e423776..10efa54496a 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -553,9 +553,6 @@
actionsWidth += $(action).outerWidth();
});
- // subtract app navigation toggle when visible
- containerWidth -= $('#app-navigation-toggle').width();
-
this.breadcrumb._resize();
this.$table.find('>thead').width($('#app-content').width() - OC.Util.getScrollBarWidth());
@@ -1369,7 +1366,7 @@
* @return new tr element (not appended to the table)
*/
add: function(fileData, options) {
- var index = -1;
+ var index;
var $tr;
var $rows;
var $insertionPoint;
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 5cd04ece446..aa0803c491b 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -46,13 +46,14 @@
tr.attr('data-share-permissions', sharePermissions);
if (fileData.shareOwner) {
tr.attr('data-share-owner', fileData.shareOwner);
+ tr.attr('data-share-owner-id', fileData.shareOwnerId);
// user should always be able to rename a mount point
if (fileData.mountType === 'shared-root') {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
}
}
- if (fileData.recipientsDisplayName) {
- tr.attr('data-share-recipients', fileData.recipientsDisplayName);
+ if (fileData.recipientData && !_.isEmpty(fileData.recipientData)) {
+ tr.attr('data-share-recipient-data', JSON.stringify(fileData.recipientData));
}
if (fileData.shareTypes) {
tr.attr('data-share-types', fileData.shareTypes.join(','));
@@ -67,8 +68,7 @@
fileInfo.shareOwner = $el.attr('data-share-owner') || undefined;
if( $el.attr('data-share-types')){
- var shareTypes = $el.attr('data-share-types').split(',');
- fileInfo.shareTypes = shareTypes;
+ fileInfo.shareTypes = $el.attr('data-share-types').split(',');
}
if( $el.attr('data-expiration')){
@@ -77,8 +77,6 @@
fileInfo.shares.push({expiration: expirationTimestamp});
}
- fileInfo.recipientsDisplayName = $el.attr('data-share-recipients') || undefined;
-
return fileInfo;
};
@@ -218,10 +216,13 @@
var recipients = _.pluck(shareModel.get('shares'), 'share_with_displayname');
// note: we only update the data attribute because updateIcon()
if (recipients.length) {
- $tr.attr('data-share-recipients', OCA.Sharing.Util.formatRecipients(recipients));
+ var recipientData = _.mapObject(shareModel.get('shares'), function (share) {
+ return {shareWith: share.share_with, shareWithDisplayName: share.share_with_displayname};
+ });
+ $tr.attr('data-share-recipient-data', JSON.stringify(recipientData));
}
else {
- $tr.removeAttr('data-share-recipients');
+ $tr.removeAttr('data-share-recipient-data');
}
},
@@ -229,15 +230,15 @@
* Update the file action share icon for the given file
*
* @param $tr file element of the file to update
- * @param {bool} hasUserShares true if a user share exists
- * @param {bool} hasLinkShare true if a link share exists
+ * @param {boolean} hasUserShares true if a user share exists
+ * @param {boolean} hasLinkShare true if a link share exists
*
- * @return {bool} true if the icon was set, false otherwise
+ * @return {boolean} true if the icon was set, false otherwise
*/
_updateFileActionIcon: function($tr, hasUserShares, hasLinkShare) {
// if the statuses are loaded already, use them for the icon
// (needed when scrolling to the next page)
- if (hasUserShares || hasLinkShare || $tr.attr('data-share-recipients') || $tr.attr('data-share-owner')) {
+ if (hasUserShares || hasLinkShare || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) {
OC.Share.markFileAsShared($tr, true, hasLinkShare);
return true;
}
@@ -245,31 +246,6 @@
},
/**
- * Formats a recipients array to be displayed.
- * The first four recipients will be shown and the
- * other ones will be shown as "+x" where "x" is the number of
- * remaining recipients.
- *
- * @param {Array.<String>} recipients recipients array
- * @param {int} count optional total recipients count (in case the array was shortened)
- * @return {String} formatted recipients display text
- */
- formatRecipients: function(recipients, count) {
- var maxRecipients = 4;
- var text;
- if (!_.isNumber(count)) {
- count = recipients.length;
- }
- // TODO: use natural sort
- recipients = _.first(recipients, maxRecipients).sort();
- text = recipients.join(', ');
- if (count > maxRecipients) {
- text += ', +' + (count - maxRecipients);
- }
- return text;
- },
-
- /**
* @param {Array} fileData
* @returns {String}
*/
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index b11b302c6c2..ad818d91413 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -153,6 +153,27 @@
// storage info like free space / used space
},
+ updateRow: function($tr, fileInfo, options) {
+ if(!fileInfo instanceof OCA.Sharing.SharedFileInfo) {
+ // recycle SharedFileInfo values if something tries to overwrite it
+ var oldModel = this.getModelForFile($tr);
+
+ if(_.isUndefined(fileInfo.recipientData) && oldModel.recipientData) {
+ fileInfo.recipientData = oldModel.recipientData;
+ }
+ if(_.isUndefined(fileInfo.recipients) && oldModel.recipientData) {
+ fileInfo.recipientData = oldModel.recipientData;
+ }
+ if(_.isUndefined(fileInfo.shares) && oldModel.shares) {
+ fileInfo.shares = oldModel.shares;
+ }
+ if(_.isUndefined(fileInfo.shareOwner) && oldModel.shareOwner) {
+ fileInfo.shareOwner = oldModel.shareOwner;
+ }
+ }
+ OCA.Files.FileList.prototype._createRow.updateRow(this, arguments);
+ },
+
reload: function() {
this.showMask();
if (this._reloadCall) {
@@ -225,7 +246,6 @@
},
_makeFilesFromRemoteShares: function(data) {
- var self = this;
var files = data;
files = _.chain(files)
@@ -297,6 +317,7 @@
};
if (self._sharedWithUser) {
file.shareOwner = share.displayname_owner;
+ file.shareOwnerId = share.uid_owner;
file.name = OC.basename(share.file_target);
file.path = OC.dirname(share.file_target);
file.permissions = share.permissions;
@@ -307,6 +328,7 @@
else {
if (share.share_type !== OC.Share.SHARE_TYPE_LINK) {
file.share.targetDisplayName = share.share_with_displayname;
+ file.share.targetShareWithId = share.share_with;
}
file.name = OC.basename(share.path);
file.path = OC.dirname(share.path);
@@ -325,12 +347,14 @@
.reduce(function(memo, file) {
var data = memo[file.id];
var recipient = file.share.targetDisplayName;
+ var recipientId = file.share.targetShareWithId;
if (!data) {
data = memo[file.id] = file;
data.shares = [file.share];
// using a hash to make them unique,
// this is only a list to be displayed
data.recipients = {};
+ data.recipientData = {};
// share types
data.shareTypes = {};
// counter is cheaper than calling _.keys().length
@@ -351,6 +375,10 @@
// only store the first ones, they will be the only ones
// displayed
data.recipients[recipient] = true;
+ data.recipientData[data.recipientsCount] = {
+ 'shareWith': recipientId,
+ 'shareWithDisplayName': recipient
+ };
}
data.recipientsCount++;
}
@@ -367,11 +395,6 @@
// convert the recipients map to a flat
// array of sorted names
data.mountType = 'shared';
- data.recipients = _.keys(data.recipients);
- data.recipientsDisplayName = OCA.Sharing.Util.formatRecipients(
- data.recipients,
- data.recipientsCount
- );
delete data.recipientsCount;
if (self._sharedWithUser) {
// only for outgoing shres
@@ -405,7 +428,16 @@
* @property {int} stime share timestamp in milliseconds
* @property {String} [targetDisplayName] display name of the recipient
* (only when shared with others)
+ * @property {String} [targetShareWithId] id of the recipient
+ *
+ */
+
+ /**
+ * Recipient attributes
*
+ * @typedef {Object} OCA.Sharing.RecipientInfo
+ * @property {String} shareWith the id of the recipient
+ * @property {String} shareWithDisplayName the display name of the recipient
*/
/**
@@ -419,7 +451,8 @@
* @property {String} shareOwner name of the share owner
* @property {Array.<String>} recipients name of the first 4 recipients
* (this is mostly for display purposes)
- * @property {String} recipientsDisplayName display name
+ * @property {Object.<OCA.Sharing.RecipientInfo>} recipientData (as object for easier
+ * passing to HTML data attributes with jQuery)
*/
OCA.Sharing.FileList = FileList;
diff --git a/apps/files_sharing/tests/js/shareSpec.js b/apps/files_sharing/tests/js/shareSpec.js
index 5b0a78c9c64..893525f7566 100644
--- a/apps/files_sharing/tests/js/shareSpec.js
+++ b/apps/files_sharing/tests/js/shareSpec.js
@@ -140,6 +140,7 @@ describe('OCA.Sharing.Util tests', function() {
size: 12,
permissions: OC.PERMISSION_ALL,
shareOwner: 'User One',
+ shareOwnerId: 'User One',
etag: 'abc',
shareTypes: []
}]);
@@ -161,6 +162,16 @@ describe('OCA.Sharing.Util tests', function() {
size: 12,
permissions: OC.PERMISSION_ALL,
recipientsDisplayName: 'User One, User Two',
+ recipientData: {
+ 0: {
+ shareWith: 'User One',
+ shareWithDisplayName: 'User One'
+ },
+ 1: {
+ shareWith: 'User Two',
+ shareWithDisplayName: 'User Two'
+ }
+ },
etag: 'abc',
shareTypes: [OC.Share.SHARE_TYPE_USER]
}]);
@@ -264,15 +275,13 @@ describe('OCA.Sharing.Util tests', function() {
// simulate updating shares
shareTab._dialog.model.set({
shares: [
- {share_with_displayname: 'User One'},
- {share_with_displayname: 'User Two'},
- {share_with_displayname: 'Group One'},
- {share_with_displayname: 'Group Two'}
+ {share_with_displayname: 'User One', share_with: 'User One'},
+ {share_with_displayname: 'User Two', share_with: 'User Two'},
+ {share_with_displayname: 'Group One', share_with: 'Group One'},
+ {share_with_displayname: 'Group Two', share_with: 'Group Two'}
]
});
- expect($tr.attr('data-share-recipients')).toEqual('Group One, Group Two, User One, User Two');
-
expect($action.text().trim()).toEqual('Shared with Group One Shared with Group Two Shared with User One Shared with User Two');
expect($action.find('.icon').hasClass('icon-shared')).toEqual(true);
expect($action.find('.icon').hasClass('icon-public')).toEqual(false);
@@ -298,14 +307,12 @@ describe('OCA.Sharing.Util tests', function() {
// simulate updating shares
shareTab._dialog.model.set({
shares: [
- {share_with_displayname: 'User One'},
- {share_with_displayname: 'User Two'},
- {share_with_displayname: 'User Three'}
+ {share_with_displayname: 'User One', share_with: 'User One'},
+ {share_with_displayname: 'User Two', share_with: 'User Two'},
+ {share_with_displayname: 'User Three', share_with: 'User Three'}
]
});
- expect($tr.attr('data-share-recipients')).toEqual('User One, User Three, User Two');
-
expect($action.text().trim()).toEqual('Shared with User One Shared with User Three Shared with User Two');
expect($action.find('.icon').hasClass('icon-shared')).toEqual(true);
expect($action.find('.icon').hasClass('icon-public')).toEqual(false);
@@ -334,7 +341,7 @@ describe('OCA.Sharing.Util tests', function() {
shares: []
});
- expect($tr.attr('data-share-recipients')).not.toBeDefined();
+ expect($tr.attr('data-share-recipient-data')).not.toBeDefined();
});
it('keep share text after updating reshare', function() {
var $action, $tr;
@@ -348,7 +355,8 @@ describe('OCA.Sharing.Util tests', function() {
size: 12,
permissions: OC.PERMISSION_ALL,
etag: 'abc',
- shareOwner: 'User One'
+ shareOwner: 'User One',
+ shareOwnerId: 'User One'
}]);
$action = fileList.$el.find('tbody tr:first .action-share');
$tr = fileList.$el.find('tr:first');
@@ -360,8 +368,6 @@ describe('OCA.Sharing.Util tests', function() {
shares: [{share_with_displayname: 'User Two'}]
});
- expect($tr.attr('data-share-recipients')).toEqual('User Two');
-
expect($action.find('>span').text().trim()).toEqual('Shared by User One');
expect($action.find('.icon').hasClass('icon-shared')).toEqual(true);
expect($action.find('.icon').hasClass('icon-public')).toEqual(false);
@@ -379,7 +385,9 @@ describe('OCA.Sharing.Util tests', function() {
permissions: OC.PERMISSION_ALL,
etag: 'abc',
shareOwner: 'User One',
- recipients: 'User Two'
+ shareOwnerId: 'User One',
+ recipients: 'User Two',
+ recipientData: {'User Two': 'User Two'}
}]);
$action = fileList.$el.find('tbody tr:first .action-share');
$tr = fileList.$el.find('tr:first');
@@ -391,60 +399,13 @@ describe('OCA.Sharing.Util tests', function() {
shares: []
});
- expect($tr.attr('data-share-recipients')).not.toBeDefined();
+ expect($tr.attr('data-share-recipient-data')).not.toBeDefined();
expect($action.find('>span').text().trim()).toEqual('Shared by User One');
expect($action.find('.icon').hasClass('icon-shared')).toEqual(true);
expect($action.find('.icon').hasClass('icon-public')).toEqual(false);
});
});
- describe('formatRecipients', function() {
- it('returns a single recipient when one passed', function() {
- expect(OCA.Sharing.Util.formatRecipients(['User one']))
- .toEqual('User one');
- });
- it('returns two recipients when two passed', function() {
- expect(OCA.Sharing.Util.formatRecipients(['User one', 'User two']))
- .toEqual('User one, User two');
- });
- it('returns four recipients with plus when five passed', function() {
- var recipients = [
- 'User one',
- 'User two',
- 'User three',
- 'User four',
- 'User five'
- ];
- expect(OCA.Sharing.Util.formatRecipients(recipients))
- .toEqual('User four, User one, User three, User two, +1');
- });
- it('returns four recipients with plus when ten passed', function() {
- var recipients = [
- 'User one',
- 'User two',
- 'User three',
- 'User four',
- 'User five',
- 'User six',
- 'User seven',
- 'User eight',
- 'User nine',
- 'User ten'
- ];
- expect(OCA.Sharing.Util.formatRecipients(recipients))
- .toEqual('User four, User one, User three, User two, +6');
- });
- it('returns four recipients with plus when four passed with counter', function() {
- var recipients = [
- 'User one',
- 'User two',
- 'User three',
- 'User four'
- ];
- expect(OCA.Sharing.Util.formatRecipients(recipients, 10))
- .toEqual('User four, User one, User three, User two, +6');
- });
- });
describe('Excluded lists', function() {
function createListThenAttach(listId) {
var fileActions = new OCA.Files.FileActions();
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
index 3efbb8fcea3..903234947bd 100644
--- a/apps/files_sharing/tests/js/sharedfilelistSpec.js
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -628,7 +628,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
expect($tr.attr('data-mime')).toEqual('text/plain');
expect($tr.attr('data-mtime')).toEqual('11111000');
- expect($tr.attr('data-share-recipients')).not.toBeDefined();
+ expect($tr.attr('data-share-recipient-data')).not.toBeDefined();
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.attr('data-favorite')).toEqual('true');
@@ -681,7 +681,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
expect($tr.attr('data-mime')).toEqual('text/plain');
expect($tr.attr('data-mtime')).toEqual('11111000');
- expect($tr.attr('data-share-recipients')).not.toBeDefined();
+ expect($tr.attr('data-share-recipient-data')).not.toBeDefined();
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.attr('data-favorite')).toEqual('true');
diff --git a/autotest.sh b/autotest.sh
index e7300363c3a..da9661f067b 100755
--- a/autotest.sh
+++ b/autotest.sh
@@ -308,11 +308,11 @@ function execute_tests {
echo "Postgres is up."
else
if [ ! -z "$DRONE" ] ; then
- DATABASEHOST=postgres
+ DATABASEHOST="postgres-$POSTGRES"
fi
echo "Waiting for Postgres to be available ..."
if ! apps/files_external/tests/env/wait-for-connection $DATABASEHOST 5432 60; then
- echo "[ERROR] Waited 60 seconds, no response" >&2
+ echo "[ERROR] Waited 60 seconds for $DATABASEHOST, no response" >&2
exit 1
fi
echo "Give it 10 additional seconds ..."
diff --git a/core/js/share.js b/core/js/share.js
index 25d59b46fb4..7662d6cffb9 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -161,7 +161,6 @@ OC.Share = _.extend(OC.Share || {}, {
updateIcon:function(itemType, itemSource) {
var shares = false;
var link = false;
- var image = OC.imagePath('core', 'actions/share');
var iconClass = '';
$.each(OC.Share.itemShares, function(index) {
if (OC.Share.itemShares[index]) {
@@ -200,15 +199,17 @@ OC.Share = _.extend(OC.Share || {}, {
/**
* Format a remote address
*
- * @param {String} remoteAddress full remote share
+ * @param {String} shareWith userid, full remote share, or whatever
+ * @param {String} shareWithDisplayName
+ * @param {String} message
* @return {String} HTML code to display
*/
- _formatRemoteShare: function(remoteAddress, message) {
- var parts = this._REMOTE_OWNER_REGEXP.exec(remoteAddress);
+ _formatRemoteShare: function(shareWith, shareWithDisplayName, message) {
+ var parts = this._REMOTE_OWNER_REGEXP.exec(shareWith);
if (!parts) {
// display avatar of the user
- var avatar = '<span class="avatar" data-userName="' + escapeHTML(remoteAddress) + '" title="' + message + " " + escapeHTML(remoteAddress) + '"></span>';
- var hidden = '<span class="hidden-visually">' + message + ' ' + escapeHTML(remoteAddress) + '</span> ';
+ var avatar = '<span class="avatar" data-username="' + escapeHTML(shareWith) + '" title="' + message + " " + escapeHTML(shareWithDisplayName) + '"></span>';
+ var hidden = '<span class="hidden-visually">' + message + ' ' + escapeHTML(shareWithDisplayName) + '</span> ';
return avatar + hidden;
}
@@ -238,14 +239,17 @@ OC.Share = _.extend(OC.Share || {}, {
* Loop over all recipients in the list and format them using
* all kind of fancy magic.
*
- * @param {String[]} recipients array of all the recipients
+ * @param {Object} recipients array of all the recipients
* @return {String[]} modified list of recipients
*/
_formatShareList: function(recipients) {
var _parent = this;
+ recipients = _.toArray(recipients);
+ recipients.sort(function(a, b) {
+ return a.shareWithDisplayName.localeCompare(b.shareWithDisplayName);
+ });
return $.map(recipients, function(recipient) {
- recipient = _parent._formatRemoteShare(recipient, t('core', 'Shared with'));
- return recipient;
+ return _parent._formatRemoteShare(recipient.shareWith, recipient.shareWithDisplayName, t('core', 'Shared with'));
});
},
/**
@@ -261,12 +265,13 @@ OC.Share = _.extend(OC.Share || {}, {
var type = $tr.data('type');
var icon = action.find('.icon');
var message, recipients, avatars;
+ var ownerId = $tr.attr('data-share-owner-id');
var owner = $tr.attr('data-share-owner');
var shareFolderIcon;
var iconClass = 'icon-shared';
action.removeClass('shared-style');
// update folder icon
- if (type === 'dir' && (hasShares || hasLink || owner)) {
+ if (type === 'dir' && (hasShares || hasLink || ownerId)) {
if (hasLink) {
shareFolderIcon = OC.MimeType.getIconUrl('dir-public');
}
@@ -290,25 +295,26 @@ OC.Share = _.extend(OC.Share || {}, {
$tr.find('.filename .thumbnail').css('background-image', 'url(' + shareFolderIcon + ')');
}
// update share action text / icon
- if (hasShares || owner) {
- recipients = $tr.attr('data-share-recipients');
+ if (hasShares || ownerId) {
+ recipients = $tr.data('share-recipient-data');
action.addClass('shared-style');
avatars = '<span>' + t('core', 'Shared') + '</span>';
// even if reshared, only show "Shared by"
- if (owner) {
+ if (ownerId) {
message = t('core', 'Shared by');
- avatars = this._formatRemoteShare(owner, message);
+ avatars = this._formatRemoteShare(ownerId, owner, message);
} else if (recipients) {
- avatars = this._formatShareList(recipients.split(', ')).join('');
+ avatars = this._formatShareList(recipients);
}
action.html(avatars).prepend(icon);
- if (owner || recipients) {
+ if (ownerId || recipients) {
var avatarElement = action.find('.avatar');
- avatarElement.avatar(avatarElement.data('username'), 32);
-
- action.find('.icon-shared + span').tooltip({placement: 'top'});
+ avatarElement.each(function () {
+ $(this).avatar($(this).data('username'), 32);
+ });
+ action.find('span[title]').tooltip({placement: 'top'});
}
} else {
action.html('<span class="hidden-visually">' + t('core', 'Shared') + '</span>').prepend(icon);
diff --git a/core/js/tests/specs/shareSpec.js b/core/js/tests/specs/shareSpec.js
index 70c698c99a2..05057692e98 100644
--- a/core/js/tests/specs/shareSpec.js
+++ b/core/js/tests/specs/shareSpec.js
@@ -45,6 +45,7 @@ describe('OC.Share tests', function() {
var $action;
$file.attr('data-share-owner', input);
+ $file.attr('data-share-owner-id', input);
OC.Share.markFileAsShared($file);
$action = $file.find('.action-share>span').parent();
@@ -119,6 +120,7 @@ describe('OC.Share tests', function() {
it('shows a shared folder icon for folders shared with the current user', function() {
$file.attr('data-type', 'dir');
$file.attr('data-share-owner', 'someoneelse');
+ $file.attr('data-share-owner-id', 'someoneelse');
OC.Share.markFileAsShared($file);
checkIcon('filetypes/folder-shared');
@@ -155,7 +157,7 @@ describe('OC.Share tests', function() {
function checkRecipients(input, output, title) {
var $action;
- $file.attr('data-share-recipients', input);
+ $file.attr('data-share-recipient-data', JSON.stringify(input));
OC.Share.markFileAsShared($file, true);
$action = $file.find('.action-share>span').parent();
@@ -177,66 +179,187 @@ describe('OC.Share tests', function() {
}
it('displays the local share owner as is', function() {
- checkRecipients('User One', 'Shared with User One', null);
+ var input = {
+ 0: {
+ shareWith: 'User One',
+ shareWithDisplayName: 'User One'
+ }
+ };
+ checkRecipients(input, 'Shared with User One', null);
});
it('displays the user name part of a remote recipient', function() {
+ var input = {
+ 0: {
+ shareWith: 'User One@someserver.com',
+ shareWithDisplayName: 'User One@someserver.com'
+ }
+ };
checkRecipients(
- 'User One@someserver.com',
+ input,
'User One@…',
'Shared with User One@someserver.com'
);
+
+ input = {
+ 0: {
+ shareWith: 'User One@someserver.com/',
+ shareWithDisplayName: 'User One@someserver.com/'
+ }
+ };
checkRecipients(
- 'User One@someserver.com/',
+ input,
'User One@…',
'Shared with User One@someserver.com'
);
+
+ input = {
+ 0: {
+ shareWith: 'User One@someserver.com/root/of/nextcloud',
+ shareWithDisplayName: 'User One@someserver.com/root/of/nextcloud'
+ }
+ };
checkRecipients(
- 'User One@someserver.com/root/of/owncloud',
+ input,
'User One@…',
'Shared with User One@someserver.com'
);
});
it('displays the user name part with domain of a remote share owner', function() {
+ var input = {
+ 0: {
+ shareWith: 'User One@example.com@someserver.com',
+ shareWithDisplayName: 'User One@example.com@someserver.com'
+ }
+ };
checkRecipients(
- 'User One@example.com@someserver.com',
+ input,
'User One@example.com',
'Shared with User One@example.com@someserver.com'
);
+
+ input = {
+ 0: {
+ shareWith: 'User One@example.com@someserver.com/',
+ shareWithDisplayName: 'User One@example.com@someserver.com/'
+ }
+ };
checkRecipients(
- 'User One@example.com@someserver.com/',
+ input,
'User One@example.com',
'Shared with User One@example.com@someserver.com'
);
+
+ input = {
+ 0: {
+ shareWith: 'User One@example.com@someserver.com/root/of/nextcloud',
+ shareWithDisplayName: 'User One@example.com@someserver.com/root/of/nextcloud'
+ }
+ };
checkRecipients(
- 'User One@example.com@someserver.com/root/of/owncloud',
+ input,
'User One@example.com',
'Shared with User One@example.com@someserver.com'
);
});
it('display multiple remote recipients', function() {
+ var input = {
+ 0: {
+ shareWith: 'One@someserver.com',
+ shareWithDisplayName: 'One@someserver.com'
+ },
+ 1: {
+ shareWith: 'two@otherserver.com',
+ shareWithDisplayName: 'two@otherserver.com'
+ }
+ };
checkRecipients(
- 'One@someserver.com, two@otherserver.com',
+ input,
'One@… two@…',
['Shared with One@someserver.com', 'Shared with two@otherserver.com']
);
+
+ input = {
+ 0: {
+ shareWith: 'One@someserver.com/',
+ shareWithDisplayName: 'One@someserver.com/'
+ },
+ 1: {
+ shareWith: 'two@someserver.com',
+ shareWithDisplayName: 'two@someserver.com'
+ }
+ };
checkRecipients(
- 'One@someserver.com/, two@otherserver.com',
+ input,
'One@… two@…',
['Shared with One@someserver.com', 'Shared with two@otherserver.com']
);
+
+ input = {
+ 0: {
+ shareWith: 'One@someserver.com/root/of/nextcloud',
+ shareWithDisplayName: 'One@someserver.com/root/of/nextcloud'
+ },
+ 1: {
+ shareWith: 'two@someserver.com',
+ shareWithDisplayName: 'two@someserver.com'
+ }
+ };
checkRecipients(
- 'One@someserver.com/root/of/owncloud, two@otherserver.com',
+ input,
'One@… two@…',
['Shared with One@someserver.com', 'Shared with two@otherserver.com']
);
});
it('display mixed recipients', function() {
checkRecipients(
- 'One, two@otherserver.com',
+ {
+ 0: {
+ shareWith: 'One',
+ shareWithDisplayName: 'One'
+ },
+ 1: {
+ shareWith: 'two@otherserver.com',
+ shareWithDisplayName: 'two@otherserver.com'
+ }
+ },
'Shared with One two@…',
['Shared with two@otherserver.com']
);
});
+ it('display multiple with divergent displaynames', function() {
+ var recipients = {
+ 0: {
+ shareWith: 'One',
+ shareWithDisplayName: 'Yoko Ono',
+ _output: 'Shared with Yoko Ono'
+ },
+ 1: {
+ shareWith: 'two@otherserver.com',
+ shareWithDisplayName: 'two@othererver.com',
+ _output: 'two@…'
+ },
+ 2: {
+ shareWith: 'Three',
+ shareWithDisplayName: 'Green, Mina',
+ _output: 'Shared with Green, Mina'
+ }
+ };
+
+ // we cannot assume the locale, also because PhantomJS has a bug.
+ var sortArray = _.toArray(recipients)
+ .sort(function(a, b) {
+ return a.shareWithDisplayName.localeCompare(b.shareWithDisplayName);
+ });
+ var sortedOutput = _.map(sortArray, function(recipient) {
+ return recipient._output;
+ }).join(' ');
+
+ checkRecipients(
+ recipients,
+ sortedOutput,
+ ['Shared with two@otherserver.com']
+ );
+ });
});
});
});
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 93c139b7bbe..81dad9890b5 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -540,7 +540,6 @@ return array(
'OC\\DB\\Migrator' => $baseDir . '/lib/private/DB/Migrator.php',
'OC\\DB\\MySQLMigrator' => $baseDir . '/lib/private/DB/MySQLMigrator.php',
'OC\\DB\\MySqlTools' => $baseDir . '/lib/private/DB/MySqlTools.php',
- 'OC\\DB\\OCPostgreSqlPlatform' => $baseDir . '/lib/private/DB/OCPostgreSqlPlatform.php',
'OC\\DB\\OCSqlitePlatform' => $baseDir . '/lib/private/DB/OCSqlitePlatform.php',
'OC\\DB\\OracleConnection' => $baseDir . '/lib/private/DB/OracleConnection.php',
'OC\\DB\\OracleMigrator' => $baseDir . '/lib/private/DB/OracleMigrator.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index c073d43ca14..b926100365b 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -570,7 +570,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\DB\\Migrator' => __DIR__ . '/../../..' . '/lib/private/DB/Migrator.php',
'OC\\DB\\MySQLMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/MySQLMigrator.php',
'OC\\DB\\MySqlTools' => __DIR__ . '/../../..' . '/lib/private/DB/MySqlTools.php',
- 'OC\\DB\\OCPostgreSqlPlatform' => __DIR__ . '/../../..' . '/lib/private/DB/OCPostgreSqlPlatform.php',
'OC\\DB\\OCSqlitePlatform' => __DIR__ . '/../../..' . '/lib/private/DB/OCSqlitePlatform.php',
'OC\\DB\\OracleConnection' => __DIR__ . '/../../..' . '/lib/private/DB/OracleConnection.php',
'OC\\DB\\OracleMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/OracleMigrator.php',
diff --git a/lib/private/DB/ConnectionFactory.php b/lib/private/DB/ConnectionFactory.php
index 082e81dfa74..fcb0117a0db 100644
--- a/lib/private/DB/ConnectionFactory.php
+++ b/lib/private/DB/ConnectionFactory.php
@@ -139,9 +139,6 @@ class ConnectionFactory {
unset($additionalConnectionParams['host']);
break;
- case 'pgsql':
- $additionalConnectionParams['platform'] = new OCPostgreSqlPlatform();
- break;
case 'sqlite3':
$journalMode = $additionalConnectionParams['sqlite.journal_mode'];
$additionalConnectionParams['platform'] = new OCSqlitePlatform();
diff --git a/lib/private/DB/OCPostgreSqlPlatform.php b/lib/private/DB/OCPostgreSqlPlatform.php
deleted file mode 100644
index e66ab84252a..00000000000
--- a/lib/private/DB/OCPostgreSqlPlatform.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2017, ownCloud GmbH
- *
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\DB;
-
-use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
-use Doctrine\DBAL\Schema\ColumnDiff;
-use Doctrine\DBAL\Schema\TableDiff;
-use Doctrine\DBAL\Types\Type;
-
-class OCPostgreSqlPlatform extends PostgreSqlPlatform {
-
- /**
- * {@inheritDoc}
- */
- public function getAlterTableSQL(TableDiff $diff){
- $queries = parent::getAlterTableSQL($diff);
- foreach ($queries as $index => $sql){
- // BIGSERIAL could not be used in statements altering column type
- // That's why we replace it with BIGINT
- // see https://github.com/owncloud/core/pull/28364#issuecomment-315006853
- if (preg_match('|(ALTER TABLE\s+\S+\s+ALTER\s+\S+\s+TYPE\s+)(BIGSERIAL)|i', $sql, $matches)) {
- $alterTable = $matches[1];
- $queries[$index] = $alterTable . 'BIGINT';
- }
-
- // Changing integer to bigint kills next autoincrement value
- // see https://github.com/owncloud/core/pull/28364#issuecomment-315006853
- if (preg_match('|ALTER TABLE\s+(\S+)\s+ALTER\s+(\S+)\s+DROP DEFAULT|i', $sql, $matches)) {
- $queryColumnName = $matches[2];
- $columnDiff = $this->findColumnDiffByName($diff, $queryColumnName);
- if ($columnDiff && $this->shouldSkipDropDefault($columnDiff)) {
- unset($queries[$index]);
- continue;
- }
- }
- }
-
- return $queries;
- }
-
- /**
- * We should NOT drop next sequence value if
- * - type was changed from INTEGER to BIGINT
- * - column keeps an autoincrement
- * - default value is kept NULL
- *
- * @param ColumnDiff $columnDiff
- * @return bool
- */
- private function shouldSkipDropDefault(ColumnDiff $columnDiff) {
- $column = $columnDiff->column;
- $fromColumn = $columnDiff->fromColumn;
- return $fromColumn->getType()->getName() === Type::INTEGER
- && $column->getType()->getName() === Type::BIGINT
- && $fromColumn->getDefault() === null
- && $column->getDefault() === null
- && $fromColumn->getAutoincrement()
- && $column->getAutoincrement();
- }
-
- /**
- * @param TableDiff $diff
- * @param string $name
- * @return ColumnDiff | false
- */
- private function findColumnDiffByName(TableDiff $diff, $name) {
- foreach ($diff->changedColumns as $columnDiff) {
- $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($this);
- if ($oldColumnName === $name) {
- return $columnDiff;
- }
- }
- return false;
- }
-}
diff --git a/tests/lib/DB/OCPostgreSqlPlatformTest.php b/tests/lib/DB/OCPostgreSqlPlatformTest.php
index 56fab621cfc..54701bdcec9 100644
--- a/tests/lib/DB/OCPostgreSqlPlatformTest.php
+++ b/tests/lib/DB/OCPostgreSqlPlatformTest.php
@@ -18,33 +18,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-
+
namespace Test\DB;
+use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Schema;
-use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
-use OC\DB\OCPostgreSqlPlatform;
-
- /**
+
+/**
* Class OCPostgreSqlPlatformTest
*
+ * custom OCPostgreSqlPlatform behavior has been upstreamed, test is left to
+ * ensure behavior stays correct.
+ *
* @group DB
*
* @package Test\DB
*/
-
class OCPostgreSqlPlatformTest extends \Test\TestCase {
- public function testAlterBigint(){
- $platform = new OCPostgreSqlPlatform();
+ public function testAlterBigint() {
+ $platform = new PostgreSqlPlatform();
$sourceSchema = new Schema();
$targetSchema = new Schema();
-
+
$this->createTableAndColumn($sourceSchema, Type::INTEGER);
$this->createTableAndColumn($targetSchema, Type::BIGINT);
-
+
$comparator = new Comparator();
$diff = $comparator->compare($sourceSchema, $targetSchema);
$sqlStatements = $diff->toSql($platform);
@@ -53,22 +54,22 @@ class OCPostgreSqlPlatformTest extends \Test\TestCase {
$sqlStatements,
true
);
-
+
$this->assertNotContains(
'ALTER TABLE poor_yorick ALTER id DROP DEFAULT',
$sqlStatements,
true
);
}
-
- protected function createTableAndColumn($schema, $type){
+
+ protected function createTableAndColumn($schema, $type) {
$table = $schema->createTable("poor_yorick");
$table->addColumn('id', $type, [
'autoincrement' => true,
- 'unsigned' => true,
- 'notnull' => true,
- 'length' => 11,
+ 'unsigned' => true,
+ 'notnull' => true,
+ 'length' => 11,
]);
}
-
+
}