diff options
60 files changed, 650 insertions, 469 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/README.md b/README.md index 9b7aa4298bc..bc962444913 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ More information how to contribute: [https://nextcloud.com/contribute/](https:// Third-party components are handled as git submodules which have to be initialized first. So aside from the regular git checkout invoking `git submodule update --init` or a similar command is needed, for details see Git documentation. -Several apps by default included in regular releases like [firstrunwizard](https://github.com/nextcloud/firstrunwizard) or [gallery](https://github.com/nextcloud/gallery) are missing in `master` and have to be installed manually as required. +Several apps that are included by default in regular releases such as [firstrunwizard](https://github.com/nextcloud/firstrunwizard) or [gallery](https://github.com/nextcloud/gallery) are missing in `master` and have to be installed manually. That aside Git checkouts can be handled the same as release archives. diff --git a/apps/comments/css/comments.css b/apps/comments/css/comments.css index 6b0452da1fd..646f5f1100c 100644 --- a/apps/comments/css/comments.css +++ b/apps/comments/css/comments.css @@ -42,6 +42,20 @@ #commentsTabView .newCommentForm .submitLoading { background-position: left; + + /* Match rules for '#commentsTabView .newCommentForm .submit' to place the + loading icon at the same position as the confirm icon */ + position: absolute; + bottom: 0px; + right: 8px; + width: 30px; + margin: 0; + padding: 7px 9px; + + /* Match rules for 'input[type="submit"]' to place the loading icon at the + same position as the confirm icon */ + min-height: 34px; + box-sizing: border-box; } #commentsTabView .newCommentForm .cancel { @@ -69,6 +83,7 @@ width: 32px; height: 32px; line-height: 32px; + margin-right: 5px; } #commentsTabView .comment .message .avatar, @@ -112,7 +127,7 @@ background-repeat: no-repeat; } -#commentsTabView .authorRow>div { +#commentsTabView .authorRow>div:not(.contactsmenu-popover) { display: inline-block; vertical-align: middle; } @@ -125,7 +140,25 @@ .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; + width: 100%; +} + +#commentsTabView .comments li .message .atwho-inserted { + margin-left: 5px; } .atwho-view-ul * .avatar-name-wrapper { @@ -136,23 +169,20 @@ #commentsTabView .comment .date { opacity: .5; } -#commentsTabView .comment .author { - margin-left: 5px; -} #commentsTabView .comment .date { - position: absolute; - right: 0; - top: 5px; + margin-left: auto; } #commentsTabView .comments li .message { padding-left: 40px; + display: inline-flex; + flex-wrap: wrap; + align-items: center; } #commentsTabView .comment .action { opacity: 0; - vertical-align: middle; - display: inline-block; + padding: 5px; } #commentsTabView .comment:hover .action { @@ -163,7 +193,8 @@ opacity: 1; } -#commentsTabView .comment .action.delete { +#commentsTabView .comment .action.delete, +#commentsTabView .comment .deleteLoading { position: absolute; right: 0; } diff --git a/apps/comments/js/commentstabview.js b/apps/comments/js/commentstabview.js index 0d2d0b0b81f..0c43e156985 100644 --- a/apps/comments/js/commentstabview.js +++ b/apps/comments/js/commentstabview.js @@ -23,10 +23,11 @@ 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>'+ '{{/if}}' + ' </div>' + ' <form class="newCommentForm">' + @@ -42,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}}' + @@ -214,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 ); }); }, @@ -320,7 +323,7 @@ this.$container.append($comment); } this._postRenderItem($comment); - $('#commentsTabView').find('.newCommentForm div.message').text('').prop('disabled', false); + $('#commentsTabView').find('.newCommentForm div.message').text('').prop('contenteditable', true); // we need to update the model, because it consists of client data // only, but the server might add meta data, e.g. about mentions @@ -377,7 +380,7 @@ }); }, - _postRenderItem: function($el) { + _postRenderItem: function($el, editionMode) { $el.find('.has-tooltip').tooltip(); $el.find('.avatar').each(function() { var $this = $(this); @@ -395,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); + } }); }, @@ -445,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>'; @@ -486,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')); @@ -543,7 +556,7 @@ ev.preventDefault(); var $comment = $(ev.target).closest('.comment'); var commentId = $comment.data('id'); - var $loading = $comment.find('.submitLoading'); + var $loading = $comment.find('.deleteLoading'); var $commentField = $comment.find('.message'); var $submit = $comment.find('.submit'); var $cancel = $comment.find('.cancel'); @@ -631,7 +644,7 @@ return; } - $commentField.prop('disabled', true); + $commentField.prop('contenteditable', false); $submit.addClass('hidden'); $loading.removeClass('hidden'); @@ -684,7 +697,7 @@ _onSubmitError: function($form, commentId) { $form.find('.submit').removeClass('hidden'); $form.find('.submitLoading').addClass('hidden'); - $form.find('.message').prop('disabled', false); + $form.find('.message').prop('contenteditable', true); if(!_.isUndefined(commentId)) { OC.Notification.show(t('comments', 'Error occurred while updating comment with id {id}', {id: commentId}), {type: 'error'}); diff --git a/apps/dav/appinfo/v1/caldav.php b/apps/dav/appinfo/v1/caldav.php index e96c3f28064..d9851bf92c8 100644 --- a/apps/dav/appinfo/v1/caldav.php +++ b/apps/dav/appinfo/v1/caldav.php @@ -49,8 +49,9 @@ $principalBackend = new Principal( $db = \OC::$server->getDatabaseConnection(); $userManager = \OC::$server->getUserManager(); $random = \OC::$server->getSecureRandom(); +$logger = \OC::$server->getLogger(); $dispatcher = \OC::$server->getEventDispatcher(); -$calDavBackend = new CalDavBackend($db, $principalBackend, $userManager, \OC::$server->getGroupManager(), $random, $dispatcher, true); +$calDavBackend = new CalDavBackend($db, $principalBackend, $userManager, \OC::$server->getGroupManager(), $random, $logger, $dispatcher, true); $debugging = \OC::$server->getConfig()->getSystemValue('debug', false); $sendInvitations = \OC::$server->getConfig()->getAppValue('dav', 'sendInvitations', 'yes') === 'yes'; diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 9045a62cde4..2f591a262a2 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -37,6 +37,7 @@ use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\DAV\Sharing\Backend; use OCP\IDBConnection; use OCP\IGroupManager; +use OCP\ILogger; use OCP\IUser; use OCP\IUserManager; use OCP\Security\ISecureRandom; @@ -56,6 +57,8 @@ use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Component\VEvent; use Sabre\VObject\Component\VTimeZone; use Sabre\VObject\DateTimeParser; +use Sabre\VObject\InvalidDataException; +use Sabre\VObject\ParseException; use Sabre\VObject\Property; use Sabre\VObject\Reader; use Sabre\VObject\Recur\EventIterator; @@ -152,6 +155,9 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription /** @var ISecureRandom */ private $random; + /** @var ILogger */ + private $logger; + /** @var EventDispatcherInterface */ private $dispatcher; @@ -169,6 +175,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription * @param IUserManager $userManager * @param IGroupManager $groupManager * @param ISecureRandom $random + * @param ILogger $logger * @param EventDispatcherInterface $dispatcher * @param bool $legacyEndpoint */ @@ -177,6 +184,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription IUserManager $userManager, IGroupManager $groupManager, ISecureRandom $random, + ILogger $logger, EventDispatcherInterface $dispatcher, $legacyEndpoint = false) { $this->db = $db; @@ -184,6 +192,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $this->userManager = $userManager; $this->sharingBackend = new Backend($this->db, $this->userManager, $groupManager, $principalBackend, 'calendar'); $this->random = $random; + $this->logger = $logger; $this->dispatcher = $dispatcher; $this->legacyEndpoint = $legacyEndpoint; } @@ -1219,7 +1228,25 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $result = []; while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { if ($requirePostFilter) { - if (!$this->validateFilterForObject($row, $filters)) { + // validateFilterForObject will parse the calendar data + // catch parsing errors + try { + $matches = $this->validateFilterForObject($row, $filters); + } catch(ParseException $ex) { + $this->logger->logException($ex, [ + 'app' => 'dav', + 'message' => 'Caught parsing exception for calendar data. This usually indicates invalid calendar data. calendar-id:'.$calendarId.' uri:'.$row['uri'] + ]); + continue; + } catch (InvalidDataException $ex) { + $this->logger->logException($ex, [ + 'app' => 'dav', + 'message' => 'Caught invalid data exception for calendar data. This usually indicates invalid calendar data. calendar-id:'.$calendarId.' uri:'.$row['uri'] + ]); + continue; + } + + if (!$matches) { continue; } } diff --git a/apps/dav/lib/Command/CreateCalendar.php b/apps/dav/lib/Command/CreateCalendar.php index 1ef859e0631..190e4aa339f 100644 --- a/apps/dav/lib/Command/CreateCalendar.php +++ b/apps/dav/lib/Command/CreateCalendar.php @@ -78,10 +78,11 @@ class CreateCalendar extends Command { $this->groupManager ); $random = \OC::$server->getSecureRandom(); + $logger = \OC::$server->getLogger(); $dispatcher = \OC::$server->getEventDispatcher(); $name = $input->getArgument('name'); - $caldav = new CalDavBackend($this->dbConnection, $principalBackend, $this->userManager, $this->groupManager, $random, $dispatcher); + $caldav = new CalDavBackend($this->dbConnection, $principalBackend, $this->userManager, $this->groupManager, $random, $logger, $dispatcher); $caldav->createCalendar("principals/users/$user", $name, []); } } diff --git a/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php b/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php index 5721f483832..68c9a1b415f 100644 --- a/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php +++ b/apps/dav/lib/Connector/Sabre/ExceptionLoggerPlugin.php @@ -30,8 +30,10 @@ use OCA\DAV\Connector\Sabre\Exception\PasswordLoginForbidden; use OCP\Files\StorageNotAvailableException; use OCP\ILogger; 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; @@ -41,6 +43,8 @@ class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin { // If tokenauth can throw this exception (which is basically as // NotAuthenticated. So not fatal. PasswordLoginForbidden::class => true, + // basically a NotAuthenticated + InvalidSyncToken::class => true, // the sync client uses this to find out whether files exist, // so it is not always an error, log it as debug NotFound::class => true, @@ -54,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/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index e4ba1f2c02a..7af1745cd74 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -40,6 +40,7 @@ class RootCollection extends SimpleCollection { public function __construct() { $config = \OC::$server->getConfig(); $random = \OC::$server->getSecureRandom(); + $logger = \OC::$server->getLogger(); $userManager = \OC::$server->getUserManager(); $groupManager = \OC::$server->getGroupManager(); $db = \OC::$server->getDatabaseConnection(); @@ -61,7 +62,7 @@ class RootCollection extends SimpleCollection { $systemPrincipals->disableListing = $disableListing; $filesCollection = new Files\RootCollection($userPrincipalBackend, 'principals/users'); $filesCollection->disableListing = $disableListing; - $caldavBackend = new CalDavBackend($db, $userPrincipalBackend, $userManager, $groupManager, $random, $dispatcher); + $caldavBackend = new CalDavBackend($db, $userPrincipalBackend, $userManager, $groupManager, $random, $logger, $dispatcher); $calendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; $publicCalendarRoot = new PublicCalendarRoot($caldavBackend); diff --git a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php index 90bf860b24d..2a01bd425c0 100644 --- a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php +++ b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php @@ -28,6 +28,7 @@ namespace OCA\DAV\Tests\unit\CalDAV; use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\Connector\Sabre\Principal; use OCP\IGroupManager; +use OCP\ILogger; use OCP\IUserManager; use OCP\Security\ISecureRandom; use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; @@ -57,6 +58,8 @@ abstract class AbstractCalDavBackend extends TestCase { /** @var ISecureRandom */ private $random; + /** @var ILogger */ + private $logger; const UNIT_TEST_USER = 'principals/users/caldav-unit-test'; const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1'; @@ -84,7 +87,8 @@ abstract class AbstractCalDavBackend extends TestCase { $db = \OC::$server->getDatabaseConnection(); $this->random = \OC::$server->getSecureRandom(); - $this->backend = new CalDavBackend($db, $this->principal, $this->userManager, $this->groupManager, $this->random, $this->dispatcher); + $this->logger = $this->createMock(ILogger::class); + $this->backend = new CalDavBackend($db, $this->principal, $this->userManager, $this->groupManager, $this->random, $this->logger, $this->dispatcher); $this->cleanUpBackend(); } diff --git a/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php b/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php index 82f4161c206..57707c6c0a4 100644 --- a/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php +++ b/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php @@ -34,6 +34,7 @@ use OCP\IGroupManager; use OCP\IL10N; use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\PublicCalendarRoot; +use OCP\ILogger; use OCP\IUserManager; use OCP\Security\ISecureRandom; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -64,6 +65,8 @@ class PublicCalendarRootTest extends TestCase { /** @var ISecureRandom */ private $random; + /** @var ILogger */ + private $logger; public function setUp() { parent::setUp(); @@ -73,6 +76,7 @@ class PublicCalendarRootTest extends TestCase { $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); $this->random = \OC::$server->getSecureRandom(); + $this->logger = $this->createMock(ILogger::class); $dispatcher = $this->createMock(EventDispatcherInterface::class); $this->principal->expects($this->any())->method('getGroupMembership') @@ -85,6 +89,7 @@ class PublicCalendarRootTest extends TestCase { $this->userManager, $this->groupManager, $this->random, + $this->logger, $dispatcher ); 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/templates/public.php b/apps/files_sharing/templates/public.php index 5417809b908..e17595d548b 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -97,6 +97,12 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size); <source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" /> </video> </div> + <?php elseif ($_['previewEnabled'] && substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'audio'): ?> + <div id="imgframe"> + <audio tabindex="0" controls="" preload="none" style="width: 100%; max-width: <?php p($_['previewMaxX']); ?>px; max-height: <?php p($_['previewMaxY']); ?>px"> + <source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" /> + </audio> + </div> <?php else: ?> <!-- Preview frame is filled via JS to support SVG images for modern browsers --> <div id="imgframe"></div> 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/apps/updatenotification/lib/Notification/BackgroundJob.php b/apps/updatenotification/lib/Notification/BackgroundJob.php index 08baa35664f..3c0cac60cde 100644 --- a/apps/updatenotification/lib/Notification/BackgroundJob.php +++ b/apps/updatenotification/lib/Notification/BackgroundJob.php @@ -53,6 +53,9 @@ class BackgroundJob extends TimedJob { /** @var IClientService */ protected $client; + /** @var Installer */ + protected $installer; + /** @var string[] */ protected $users; @@ -64,8 +67,9 @@ class BackgroundJob extends TimedJob { * @param IGroupManager $groupManager * @param IAppManager $appManager * @param IClientService $client + * @param Installer $installer */ - public function __construct(IConfig $config, IManager $notificationManager, IGroupManager $groupManager, IAppManager $appManager, IClientService $client) { + public function __construct(IConfig $config, IManager $notificationManager, IGroupManager $groupManager, IAppManager $appManager, IClientService $client, Installer $installer) { // Run once a day $this->setInterval(60 * 60 * 24); @@ -74,6 +78,7 @@ class BackgroundJob extends TimedJob { $this->groupManager = $groupManager; $this->appManager = $appManager; $this->client = $client; + $this->installer = $installer; } protected function run($argument) { @@ -257,6 +262,6 @@ class BackgroundJob extends TimedJob { * @return string|false */ protected function isUpdateAvailable($app) { - return Installer::isUpdateAvailable($app, \OC::$server->getAppFetcher()); + return $this->installer->isUpdateAvailable($app); } } diff --git a/apps/updatenotification/tests/Notification/BackgroundJobTest.php b/apps/updatenotification/tests/Notification/BackgroundJobTest.php index 92a8a687f5a..0355b10a09c 100644 --- a/apps/updatenotification/tests/Notification/BackgroundJobTest.php +++ b/apps/updatenotification/tests/Notification/BackgroundJobTest.php @@ -23,6 +23,7 @@ namespace OCA\UpdateNotification\Tests\Notification; +use OC\Installer; use OCA\UpdateNotification\Notification\BackgroundJob; use OCP\App\IAppManager; use OCP\Http\Client\IClientService; @@ -47,6 +48,8 @@ class BackgroundJobTest extends TestCase { protected $appManager; /** @var IClientService|\PHPUnit_Framework_MockObject_MockObject */ protected $client; + /** @var Installer|\PHPUnit_Framework_MockObject_MockObject */ + protected $installer; public function setUp() { parent::setUp(); @@ -56,6 +59,7 @@ class BackgroundJobTest extends TestCase { $this->groupManager = $this->createMock(IGroupManager::class); $this->appManager = $this->createMock(IAppManager::class); $this->client = $this->createMock(IClientService::class); + $this->installer = $this->createMock(Installer::class); } /** @@ -69,7 +73,8 @@ class BackgroundJobTest extends TestCase { $this->notificationManager, $this->groupManager, $this->appManager, - $this->client + $this->client, + $this->installer ); } { return $this->getMockBuilder(BackgroundJob::class) @@ -79,6 +84,7 @@ class BackgroundJobTest extends TestCase { $this->groupManager, $this->appManager, $this->client, + $this->installer, ]) ->setMethods($methods) ->getMock(); diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 82e61cd5dcd..42bbaaf78ca 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -55,7 +55,7 @@ style('user_ldap', 'settings'); ?> <form id="ldap" class="section" action="#" method="post"> - <h2><?php p($l->t('LDAP')); ?></h2> + <h2><?php p($l->t('LDAP / AD integration')); ?></h2> <div id="ldapSettings"> <ul> 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/build/.phan/config.php b/build/.phan/config.php index 47bcb87acdd..1bdaddc0e05 100644 --- a/build/.phan/config.php +++ b/build/.phan/config.php @@ -106,32 +106,32 @@ return [ // an analysis. You should consider setting this // to true only when you wish you had more issues // to fix in your code base. - 'quick_mode' => true, + 'quick_mode' => false, // If enabled, check all methods that override a // parent method to make sure its signature is // compatible with the parent's. This check // can add quite a bit of time to the analysis. - 'analyze_signature_compatibility' => false, + 'analyze_signature_compatibility' => true, // The minimum severity level to report on. This can be // set to Issue::SEVERITY_LOW, Issue::SEVERITY_NORMAL or // Issue::SEVERITY_CRITICAL. Setting it to only // critical issues is a good place to start on a big // sloppy mature code base. - 'minimum_severity' => 10, + 'minimum_severity' => \Phan\Issue::SEVERITY_CRITICAL, // If true, missing properties will be created when // they are first seen. If false, we'll report an // error message if there is an attempt to write // to a class property that wasn't explicitly // defined. - 'allow_missing_properties' => true, + 'allow_missing_properties' => false, // Allow null to be cast as any type and for any // type to be cast to null. Setting this to false // will cut down on false positives. - 'null_casts_as_any_type' => true, + 'null_casts_as_any_type' => false, // Allow null to be cast as any array-like type (Requires 0.9.3+) // This is an incremental step in migrating away from null_casts_as_any_type. diff --git a/build/integration/federation_features/federated.feature b/build/integration/federation_features/federated.feature index 8bf8e921b0f..c7b20cf86a7 100644 --- a/build/integration/federation_features/federated.feature +++ b/build/integration/federation_features/federated.feature @@ -113,7 +113,7 @@ Feature: federated | permissions | 19 | | stime | A_NUMBER | | storage | A_NUMBER | - | mail_send | 0 | + | mail_send | 1 | | uid_owner | user1 | | file_parent | A_NUMBER | | displayname_owner | user1 | diff --git a/core/Command/App/Install.php b/core/Command/App/Install.php index c8c4652d7ba..8f530975be9 100644 --- a/core/Command/App/Install.php +++ b/core/Command/App/Install.php @@ -51,13 +51,7 @@ class Install extends Command { } try { - $installer = new Installer( - \OC::$server->getAppFetcher(), - \OC::$server->getHTTPClientService(), - \OC::$server->getTempManager(), - \OC::$server->getLogger(), - \OC::$server->getConfig() - ); + $installer = \OC::$server->query(Installer::class); $installer->downloadApp($appId); $result = $installer->installApp($appId); } catch(\Exception $e) { diff --git a/core/Command/Maintenance/Install.php b/core/Command/Maintenance/Install.php index 755d3d386c1..be6a2da22c8 100644 --- a/core/Command/Maintenance/Install.php +++ b/core/Command/Maintenance/Install.php @@ -30,6 +30,7 @@ namespace OC\Core\Command\Maintenance; use InvalidArgumentException; +use OC\Installer; use OC\Setup; use OC\SystemConfig; use OCP\Defaults; @@ -73,9 +74,15 @@ class Install extends Command { // validate the environment $server = \OC::$server; - $setupHelper = new Setup($this->config, $server->getIniWrapper(), - $server->getL10N('lib'), $server->query(Defaults::class), $server->getLogger(), - $server->getSecureRandom()); + $setupHelper = new Setup( + $this->config, + $server->getIniWrapper(), + $server->getL10N('lib'), + $server->query(Defaults::class), + $server->getLogger(), + $server->getSecureRandom(), + \OC::$server->query(Installer::class) + ); $sysInfo = $setupHelper->getSystemInfo(true); $errors = $sysInfo['errors']; if (count($errors) > 0) { diff --git a/core/Command/Upgrade.php b/core/Command/Upgrade.php index 0877c19bc01..2a502dbe921 100644 --- a/core/Command/Upgrade.php +++ b/core/Command/Upgrade.php @@ -35,6 +35,7 @@ namespace OC\Core\Command; use OC\Console\TimestampFormatter; +use OC\Installer; use OC\Updater; use OCP\IConfig; use OCP\ILogger; @@ -63,11 +64,13 @@ class Upgrade extends Command { /** * @param IConfig $config * @param ILogger $logger + * @param Installer $installer */ - public function __construct(IConfig $config, ILogger $logger) { + public function __construct(IConfig $config, ILogger $logger, Installer $installer) { parent::__construct(); $this->config = $config; $this->logger = $logger; + $this->installer = $installer; } protected function configure() { @@ -101,7 +104,8 @@ class Upgrade extends Command { $updater = new Updater( $this->config, \OC::$server->getIntegrityCodeChecker(), - $this->logger + $this->logger, + $this->installer ); if ($input->getOption('no-app-disable')) { diff --git a/core/ajax/update.php b/core/ajax/update.php index 71d60f5c432..2a29d1e536c 100644 --- a/core/ajax/update.php +++ b/core/ajax/update.php @@ -116,7 +116,8 @@ if (OC::checkUpgrade(false)) { $updater = new \OC\Updater( $config, \OC::$server->getIntegrityCodeChecker(), - $logger + $logger, + \OC::$server->query(\OC\Installer::class) ); $incompatibleApps = []; $disabledThirdPartyApps = []; diff --git a/core/css/inputs.scss b/core/css/inputs.scss index 20e8cbf08e0..00e0e47f9a8 100644 --- a/core/css/inputs.scss +++ b/core/css/inputs.scss @@ -13,7 +13,7 @@ */ /* Specifically override browser styles */ -input, textarea, select, button, div[contenteditable=true] { +input, textarea, select, button, div[contenteditable=true], div[contenteditable=false] { font-family: 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif; } .select2-container-multi .select2-choices .select2-search-field input, .select2-search input, .ui-widget { @@ -25,7 +25,8 @@ select, button, input, textarea, -div[contenteditable=true] { +div[contenteditable=true], +div[contenteditable=false] { width: 130px; min-height: 32px; box-sizing: border-box; @@ -88,6 +89,23 @@ div[contenteditable=true], } } +div[contenteditable=false] { + margin: 3px 3px 3px 0; + padding: 7px 6px; + font-size: 13px; + background-color: $color-main-background; + color: nc-lighten($color-main-text, 33%); + border: 1px solid nc-darken($color-main-background, 14%); + outline: none; + border-radius: $border-radius; + cursor: text; + + background-color: nc-darken($color-main-background, 8%); + color: rgba($color-main-text, 0.4); + cursor: default; + opacity: 0.5; +} + /* Specific override */ input { &:not([type='radio']):not([type='checkbox']):not([type='range']):not([type='submit']):not([type='button']):not([type='reset']):not([type='color']):not([type='file']):not([type='image']) { @@ -171,6 +189,13 @@ textarea, div[contenteditable=true] { } } +div[contenteditable=false] { + color: nc-lighten($color-main-text, 33%); + cursor: text; + font-family: inherit; + height: auto; +} + /* Override the ugly select arrow */ select { -webkit-appearance: none; diff --git a/core/css/share.scss b/core/css/share.scss index 37217fa926a..68b601bcb65 100644 --- a/core/css/share.scss +++ b/core/css/share.scss @@ -177,9 +177,11 @@ } .contactsmenu-popover { - left: -8px; + left: -6px; right: auto; padding: 3px 6px; + top: 100%; + margin-top: 0; li.hidden { display: none !important; } 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/core/register_command.php b/core/register_command.php index 3f7fbf508e5..60e151a5f2c 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -137,7 +137,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { $application->add(new OC\Core\Command\Maintenance\UpdateHtaccess()); $application->add(new OC\Core\Command\Maintenance\UpdateTheme(\OC::$server->getMimeTypeDetector(), \OC::$server->getMemCacheFactory())); - $application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger())); + $application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->query(\OC\Installer::class))); $application->add(new OC\Core\Command\Maintenance\Repair( new \OC\Repair(\OC\Repair::getRepairSteps(), \OC::$server->getEventDispatcher()), \OC::$server->getConfig(), \OC::$server->getEventDispatcher(), \OC::$server->getAppManager())); diff --git a/lib/base.php b/lib/base.php index 6193b591ab5..f6b4f5555eb 100644 --- a/lib/base.php +++ b/lib/base.php @@ -923,9 +923,15 @@ class OC { // Check if Nextcloud is installed or in maintenance (update) mode if (!$systemConfig->getValue('installed', false)) { \OC::$server->getSession()->clear(); - $setupHelper = new OC\Setup(\OC::$server->getSystemConfig(), \OC::$server->getIniWrapper(), - \OC::$server->getL10N('lib'), \OC::$server->query(\OCP\Defaults::class), \OC::$server->getLogger(), - \OC::$server->getSecureRandom()); + $setupHelper = new OC\Setup( + \OC::$server->getSystemConfig(), + \OC::$server->getIniWrapper(), + \OC::$server->getL10N('lib'), + \OC::$server->query(\OCP\Defaults::class), + \OC::$server->getLogger(), + \OC::$server->getSecureRandom(), + \OC::$server->query(\OC\Installer::class) + ); $controller = new OC\Core\Controller\SetupController($setupHelper); $controller->run($_POST); exit(); 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/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index 3fca122d287..36a8b1d5464 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -97,6 +97,7 @@ class DefaultTokenProvider implements IProvider { $dbToken->setType($type); $dbToken->setRemember($remember); $dbToken->setLastActivity($this->time->getTime()); + $dbToken->setLastCheck($this->time->getTime()); $this->mapper->insert($dbToken); 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/lib/private/Installer.php b/lib/private/Installer.php index 45bec26831e..48bd57f4c10 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -67,6 +67,10 @@ class Installer { private $logger; /** @var IConfig */ private $config; + /** @var array - for caching the result of app fetcher */ + private $apps = null; + /** @var bool|null - for caching the result of the ready status */ + private $isInstanceReadyForUpdates = null; /** * @param AppFetcher $appFetcher @@ -187,7 +191,7 @@ class Installer { * @return bool */ public function updateAppstoreApp($appId) { - if(self::isUpdateAvailable($appId, $this->appFetcher)) { + if($this->isUpdateAvailable($appId)) { try { $this->downloadApp($appId); } catch (\Exception $e) { @@ -375,27 +379,26 @@ class Installer { * Check if an update for the app is available * * @param string $appId - * @param AppFetcher $appFetcher * @return string|false false or the version number of the update */ - public static function isUpdateAvailable($appId, - AppFetcher $appFetcher) { - static $isInstanceReadyForUpdates = null; - - if ($isInstanceReadyForUpdates === null) { + public function isUpdateAvailable($appId) { + if ($this->isInstanceReadyForUpdates === null) { $installPath = OC_App::getInstallPath(); if ($installPath === false || $installPath === null) { - $isInstanceReadyForUpdates = false; + $this->isInstanceReadyForUpdates = false; } else { - $isInstanceReadyForUpdates = true; + $this->isInstanceReadyForUpdates = true; } } - if ($isInstanceReadyForUpdates === false) { + if ($this->isInstanceReadyForUpdates === false) { return false; } - $apps = $appFetcher->get(); + if ($this->apps === null) { + $apps = $this->appFetcher->get(); + } + foreach($apps as $app) { if($app['id'] === $appId) { $currentVersion = OC_App::getAppVersion($appId); diff --git a/lib/private/Log.php b/lib/private/Log.php index a41c728df0d..bed0321bef3 100644 --- a/lib/private/Log.php +++ b/lib/private/Log.php @@ -351,6 +351,7 @@ class Log implements ILogger { $msg = isset($context['message']) ? $context['message'] : 'Exception'; $msg .= ': ' . json_encode($data); $this->log($level, $msg, $context); + $context['level'] = $level; if (!is_null($this->crashReporters)) { $this->crashReporters->delegateReport($exception, $context); } diff --git a/lib/private/Server.php b/lib/private/Server.php index faa0ce2f2ac..0c6338f6a4c 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1099,6 +1099,16 @@ class Server extends ServerContainer implements IServerContainer { $c->query(\OCP\Share\IManager::class) ); }); + + $this->registerService(Installer::class, function(Server $c) { + return new Installer( + $c->getAppFetcher(), + $c->getHTTPClientService(), + $c->getTempManager(), + $c->getLogger(), + $c->getConfig() + ); + }); } /** diff --git a/lib/private/Setup.php b/lib/private/Setup.php index 8214db2d4ef..92246e8322e 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -65,6 +65,8 @@ class Setup { protected $logger; /** @var ISecureRandom */ protected $random; + /** @var Installer */ + protected $installer; /** * @param SystemConfig $config @@ -73,13 +75,15 @@ class Setup { * @param Defaults $defaults * @param ILogger $logger * @param ISecureRandom $random + * @param Installer $installer */ public function __construct(SystemConfig $config, IniGetWrapper $iniWrapper, IL10N $l10n, Defaults $defaults, ILogger $logger, - ISecureRandom $random + ISecureRandom $random, + Installer $installer ) { $this->config = $config; $this->iniWrapper = $iniWrapper; @@ -87,6 +91,7 @@ class Setup { $this->defaults = $defaults; $this->logger = $logger; $this->random = $random; + $this->installer = $installer; } static protected $dbSetupClasses = [ @@ -371,18 +376,11 @@ class Setup { // Install shipped apps and specified app bundles Installer::installShippedApps(); - $installer = new Installer( - \OC::$server->getAppFetcher(), - \OC::$server->getHTTPClientService(), - \OC::$server->getTempManager(), - \OC::$server->getLogger(), - \OC::$server->getConfig() - ); $bundleFetcher = new BundleFetcher(\OC::$server->getL10N('lib')); $defaultInstallationBundles = $bundleFetcher->getDefaultInstallationBundle(); foreach($defaultInstallationBundles as $bundle) { try { - $installer->installAppBundle($bundle); + $this->installer->installAppBundle($bundle); } catch (Exception $e) {} } @@ -444,9 +442,15 @@ class Setup { $webRoot = !empty(\OC::$WEBROOT) ? \OC::$WEBROOT : '/'; } - $setupHelper = new \OC\Setup($config, \OC::$server->getIniWrapper(), - \OC::$server->getL10N('lib'), \OC::$server->query(Defaults::class), \OC::$server->getLogger(), - \OC::$server->getSecureRandom()); + $setupHelper = new \OC\Setup( + $config, + \OC::$server->getIniWrapper(), + \OC::$server->getL10N('lib'), + \OC::$server->query(Defaults::class), + \OC::$server->getLogger(), + \OC::$server->getSecureRandom(), + \OC::$server->query(Installer::class) + ); $htaccessContent = file_get_contents($setupHelper->pathToHtaccess()); $content = "#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####\n"; diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index a440c36406b..844b36b2994 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -183,6 +183,9 @@ class DefaultShareProvider implements IShareProvider { throw new ShareNotFound(); } + $mailSendValue = $share->getMailSend(); + $data['mail_send'] = ($mailSendValue === null) ? true : $mailSendValue; + $share = $this->createShare($data); return $share; } diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 83fe4ec0d19..b22bfbc3878 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -669,26 +669,31 @@ class Manager implements IManager { $this->eventDispatcher->dispatch('OCP\Share::postShare', $event); if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { - $user = $this->userManager->get($share->getSharedWith()); - if ($user !== null) { - $emailAddress = $user->getEMailAddress(); - if ($emailAddress !== null && $emailAddress !== '') { - $userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null); - $l = $this->l10nFactory->get('lib', $userLang); - $this->sendMailNotification( - $l, - $share->getNode()->getName(), - $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', [ 'fileid' => $share->getNode()->getId() ]), - $share->getSharedBy(), - $emailAddress, - $share->getExpirationDate() - ); - $this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']); + $mailSend = $share->getMailSend(); + if($mailSend === true) { + $user = $this->userManager->get($share->getSharedWith()); + if ($user !== null) { + $emailAddress = $user->getEMailAddress(); + if ($emailAddress !== null && $emailAddress !== '') { + $userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null); + $l = $this->l10nFactory->get('lib', $userLang); + $this->sendMailNotification( + $l, + $share->getNode()->getName(), + $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]), + $share->getSharedBy(), + $emailAddress, + $share->getExpirationDate() + ); + $this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']); + } else { + $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']); + } } else { - $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']); + $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']); } } else { - $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']); + $this->logger->debug('Share notification not send because mailsend is false.', ['app' => 'share']); } } diff --git a/lib/private/Updater.php b/lib/private/Updater.php index 4f5bb45ae15..996163daacc 100644 --- a/lib/private/Updater.php +++ b/lib/private/Updater.php @@ -63,6 +63,9 @@ class Updater extends BasicEmitter { /** @var Checker */ private $checker; + /** @var Installer */ + private $installer; + /** @var bool */ private $skip3rdPartyAppsDisable; @@ -78,13 +81,16 @@ class Updater extends BasicEmitter { * @param IConfig $config * @param Checker $checker * @param ILogger $log + * @param Installer $installer */ public function __construct(IConfig $config, Checker $checker, - ILogger $log = null) { + ILogger $log = null, + Installer $installer) { $this->log = $log; $this->config = $config; $this->checker = $checker; + $this->installer = $installer; // If at least PHP 7.0.0 is used we don't need to disable apps as we catch // fatal errors and exceptions and disable the app just instead. @@ -461,17 +467,10 @@ class Updater extends BasicEmitter { private function upgradeAppStoreApps(array $disabledApps) { foreach($disabledApps as $app) { try { - $installer = new Installer( - \OC::$server->getAppFetcher(), - \OC::$server->getHTTPClientService(), - \OC::$server->getTempManager(), - $this->log, - \OC::$server->getConfig() - ); $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]); - if (Installer::isUpdateAvailable($app, \OC::$server->getAppFetcher())) { + if ($this->installer->isUpdateAvailable($app)) { $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]); - $installer->updateAppstoreApp($app); + $this->installer->updateAppstoreApp($app); } $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]); } catch (\Exception $ex) { diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php index d2b0f96d593..1b9fc28873e 100644 --- a/lib/private/legacy/app.php +++ b/lib/private/legacy/app.php @@ -375,13 +375,7 @@ class OC_App { self::$enabledAppsCache = []; // flush // Check if app is already downloaded - $installer = new Installer( - \OC::$server->getAppFetcher(), - \OC::$server->getHTTPClientService(), - \OC::$server->getTempManager(), - \OC::$server->getLogger(), - \OC::$server->getConfig() - ); + $installer = \OC::$server->query(Installer::class); $isDownloaded = $installer->isDownloaded($appId); if(!$isDownloaded) { @@ -415,13 +409,7 @@ class OC_App { return false; } - $installer = new Installer( - \OC::$server->getAppFetcher(), - \OC::$server->getHTTPClientService(), - \OC::$server->getTempManager(), - \OC::$server->getLogger(), - \OC::$server->getConfig() - ); + $installer = \OC::$server->query(Installer::class); return $installer->removeApp($app); } diff --git a/lib/private/legacy/image.php b/lib/private/legacy/image.php index fe9f054f5d4..a7d702ac032 100644 --- a/lib/private/legacy/image.php +++ b/lib/private/legacy/image.php @@ -63,22 +63,6 @@ class OC_Image implements \OCP\IImage { private $exif; /** - * Get mime type for an image file. - * - * @param string|null $filePath The path to a local image file. - * @return string The mime type if the it could be determined, otherwise an empty string. - */ - static public function getMimeTypeForFile($filePath) { - // exif_imagetype throws "read error!" if file is less than 12 byte - if ($filePath !== null && filesize($filePath) > 11) { - $imageType = exif_imagetype($filePath); - } else { - $imageType = false; - } - return $imageType ? image_type_to_mime_type($imageType) : ''; - } - - /** * Constructor. * * @param resource|string $imageRef The path to a local file, a base64 encoded string or a resource created by diff --git a/lib/private/legacy/util.php b/lib/private/legacy/util.php index 1e9090960c1..3ce11746672 100644 --- a/lib/private/legacy/util.php +++ b/lib/private/legacy/util.php @@ -708,8 +708,15 @@ class OC_Util { } $webServerRestart = false; - $setup = new \OC\Setup($config, \OC::$server->getIniWrapper(), \OC::$server->getL10N('lib'), - \OC::$server->query(\OCP\Defaults::class), \OC::$server->getLogger(), \OC::$server->getSecureRandom()); + $setup = new \OC\Setup( + $config, + \OC::$server->getIniWrapper(), + \OC::$server->getL10N('lib'), + \OC::$server->query(\OCP\Defaults::class), + \OC::$server->getLogger(), + \OC::$server->getSecureRandom(), + \OC::$server->query(\OC\Installer::class) + ); $urlGenerator = \OC::$server->getURLGenerator(); diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 26858eabcf3..f2a92b52f6d 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -37,6 +37,7 @@ use OC\App\AppStore\Fetcher\CategoryFetcher; use OC\App\AppStore\Version\VersionParser; use OC\App\DependencyAnalyzer; use OC\App\Platform; +use OC\Installer; use OCP\App\IAppManager; use \OCP\AppFramework\Controller; use OCP\AppFramework\Http\ContentSecurityPolicy; @@ -74,6 +75,8 @@ class AppSettingsController extends Controller { private $l10nFactory; /** @var BundleFetcher */ private $bundleFetcher; + /** @var Installer */ + private $installer; /** * @param string $appName @@ -86,6 +89,7 @@ class AppSettingsController extends Controller { * @param AppFetcher $appFetcher * @param IFactory $l10nFactory * @param BundleFetcher $bundleFetcher + * @param Installer $installer */ public function __construct($appName, IRequest $request, @@ -96,7 +100,8 @@ class AppSettingsController extends Controller { CategoryFetcher $categoryFetcher, AppFetcher $appFetcher, IFactory $l10nFactory, - BundleFetcher $bundleFetcher) { + BundleFetcher $bundleFetcher, + Installer $installer) { parent::__construct($appName, $request); $this->l10n = $l10n; $this->config = $config; @@ -106,6 +111,7 @@ class AppSettingsController extends Controller { $this->appFetcher = $appFetcher; $this->l10nFactory = $l10nFactory; $this->bundleFetcher = $bundleFetcher; + $this->installer = $installer; } /** @@ -270,8 +276,7 @@ class AppSettingsController extends Controller { ]; - $appFetcher = \OC::$server->getAppFetcher(); - $newVersion = \OC\Installer::isUpdateAvailable($app['id'], $appFetcher); + $newVersion = $this->installer->isUpdateAvailable($app['id']); if($newVersion && $this->appManager->isInstalled($app['id'])) { $formattedApps[count($formattedApps)-1]['update'] = $newVersion; } @@ -284,7 +289,7 @@ class AppSettingsController extends Controller { $appClass = new \OC_App(); $apps = $appClass->listAllApps(); foreach($apps as $key => $app) { - $newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher); + $newVersion = $this->installer->isUpdateAvailable($app['id']); if($newVersion !== false) { $apps[$key]['update'] = $newVersion; } else { @@ -317,7 +322,7 @@ class AppSettingsController extends Controller { $apps = $appClass->listAllApps(); foreach($apps as $key => $app) { - $newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher); + $newVersion = $this->installer->isUpdateAvailable($app['id']); $apps[$key]['update'] = $newVersion; } @@ -342,7 +347,7 @@ class AppSettingsController extends Controller { }); foreach($apps as $key => $app) { - $newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher); + $newVersion = $this->installer->isUpdateAvailable($app['id']); $apps[$key]['update'] = $newVersion; } @@ -363,7 +368,7 @@ class AppSettingsController extends Controller { }); $apps = array_map(function ($app) { - $newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher); + $newVersion = $this->installer->isUpdateAvailable($app['id']); if ($newVersion !== false) { $app['update'] = $newVersion; } diff --git a/settings/Controller/UsersController.php b/settings/Controller/UsersController.php index 68c920dde17..53ffd62a06d 100644 --- a/settings/Controller/UsersController.php +++ b/settings/Controller/UsersController.php @@ -339,7 +339,9 @@ class UsersController extends Controller { // Batch all groups the user is subadmin of when a group is specified $batch = []; - if ($gid === '') { + if ($gid !== '' && $gid !== '_disabledUsers' && $gid !== '_everyone') { + $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset); + } else { foreach ($subAdminOfGroups as $group) { $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset); @@ -347,8 +349,6 @@ class UsersController extends Controller { $batch[$uid] = $displayName; } } - } else { - $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset); } $batch = $this->getUsersForUID($batch); diff --git a/settings/ajax/updateapp.php b/settings/ajax/updateapp.php index 7b615cb56bb..3431c68dbd7 100644 --- a/settings/ajax/updateapp.php +++ b/settings/ajax/updateapp.php @@ -41,13 +41,7 @@ $appId = OC_App::cleanAppId($appId); $config = \OC::$server->getConfig(); $config->setSystemValue('maintenance', true); try { - $installer = new \OC\Installer( - \OC::$server->getAppFetcher(), - \OC::$server->getHTTPClientService(), - \OC::$server->getTempManager(), - \OC::$server->getLogger(), - \OC::$server->getConfig() - ); + $installer = \OC::$server->query(\OC\Installer::class); $result = $installer->updateAppstoreApp($appId); $config->setSystemValue('maintenance', false); } catch(Exception $ex) { diff --git a/tests/Settings/Controller/AppSettingsControllerTest.php b/tests/Settings/Controller/AppSettingsControllerTest.php index e264d0dfbfe..6631873d8ad 100644 --- a/tests/Settings/Controller/AppSettingsControllerTest.php +++ b/tests/Settings/Controller/AppSettingsControllerTest.php @@ -25,6 +25,7 @@ namespace Tests\Settings\Controller; use OC\App\AppStore\Bundles\BundleFetcher; use OC\App\AppStore\Fetcher\AppFetcher; use OC\App\AppStore\Fetcher\CategoryFetcher; +use OC\Installer; use OC\Settings\Controller\AppSettingsController; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\JSONResponse; @@ -63,6 +64,8 @@ class AppSettingsControllerTest extends TestCase { private $l10nFactory; /** @var BundleFetcher|\PHPUnit_Framework_MockObject_MockObject */ private $bundleFetcher; + /** @var Installer|\PHPUnit_Framework_MockObject_MockObject */ + private $installer; public function setUp() { parent::setUp(); @@ -79,6 +82,7 @@ class AppSettingsControllerTest extends TestCase { $this->appFetcher = $this->createMock(AppFetcher::class); $this->l10nFactory = $this->createMock(IFactory::class); $this->bundleFetcher = $this->createMock(BundleFetcher::class); + $this->installer = $this->createMock(Installer::class); $this->appSettingsController = new AppSettingsController( 'settings', @@ -90,11 +94,15 @@ class AppSettingsControllerTest extends TestCase { $this->categoryFetcher, $this->appFetcher, $this->l10nFactory, - $this->bundleFetcher + $this->bundleFetcher, + $this->installer ); } public function testListCategories() { + $this->installer->expects($this->any()) + ->method('isUpdateAvailable') + ->willReturn(false); $expected = new JSONResponse([ [ 'id' => 2, diff --git a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php index 96fdbaa176f..08c74961c0d 100644 --- a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php +++ b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php @@ -91,6 +91,7 @@ class DefaultTokenProviderTest extends TestCase { $toInsert->setType($type); $toInsert->setRemember(IToken::DO_NOT_REMEMBER); $toInsert->setLastActivity($this->time); + $toInsert->setLastCheck($this->time); $this->config->expects($this->any()) ->method('getSystemValue') 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, ]); } - + } diff --git a/tests/lib/ImageTest.php b/tests/lib/ImageTest.php index b7255ccdbd6..b4cb57f3787 100644 --- a/tests/lib/ImageTest.php +++ b/tests/lib/ImageTest.php @@ -19,20 +19,6 @@ class ImageTest extends \Test\TestCase { parent::tearDownAfterClass(); } - public function testGetMimeTypeForFile() { - $mimetype = \OC_Image::getMimeTypeForFile(OC::$SERVERROOT.'/tests/data/testimage.png'); - $this->assertEquals('image/png', $mimetype); - - $mimetype = \OC_Image::getMimeTypeForFile(OC::$SERVERROOT.'/tests/data/testimage.jpg'); - $this->assertEquals('image/jpeg', $mimetype); - - $mimetype = \OC_Image::getMimeTypeForFile(OC::$SERVERROOT.'/tests/data/testimage.gif'); - $this->assertEquals('image/gif', $mimetype); - - $mimetype = \OC_Image::getMimeTypeForFile(null); - $this->assertEquals('', $mimetype); - } - public function testConstructDestruct() { $img = new \OC_Image(OC::$SERVERROOT.'/tests/data/testimage.png'); $this->assertInstanceOf('\OC_Image', $img); @@ -337,7 +323,6 @@ class ImageTest extends \Test\TestCase { $tempFile = tempnam(sys_get_temp_dir(), 'img-test'); $img->save($tempFile, $mimeType); - $actualMimeType = \OC_Image::getMimeTypeForFile($tempFile); - $this->assertEquals($mimeType, $actualMimeType); + $this->assertEquals($mimeType, image_type_to_mime_type(exif_imagetype($tempFile))); } } diff --git a/tests/lib/InstallerTest.php b/tests/lib/InstallerTest.php index 107b9dcb41f..897bc472103 100644 --- a/tests/lib/InstallerTest.php +++ b/tests/lib/InstallerTest.php @@ -40,9 +40,6 @@ class InstallerTest extends TestCase { /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ private $config; - /** @var Installer */ - private $installer; - protected function setUp() { parent::setUp(); @@ -51,13 +48,6 @@ class InstallerTest extends TestCase { $this->tempManager = $this->createMock(ITempManager::class); $this->logger = $this->createMock(ILogger::class); $this->config = $this->createMock(IConfig::class); - $this->installer = new Installer( - $this->appFetcher, - $this->clientService, - $this->tempManager, - $this->logger, - $this->config - ); $config = \OC::$server->getConfig(); $this->appstore = $config->setSystemValue('appstoreenabled', true); @@ -72,6 +62,16 @@ class InstallerTest extends TestCase { $installer->removeApp(self::$appid); } + protected function getInstaller() { + return new Installer( + $this->appFetcher, + $this->clientService, + $this->tempManager, + $this->logger, + $this->config + ); + } + protected function tearDown() { $installer = new Installer( \OC::$server->getAppFetcher(), @@ -154,7 +154,8 @@ class InstallerTest extends TestCase { ->method('get') ->willReturn($appArray); - $this->assertSame($updateAvailable, Installer::isUpdateAvailable('files', $this->appFetcher)); + $installer = $this->getInstaller(); + $this->assertSame($updateAvailable, $installer->isUpdateAvailable('files')); } /** @@ -197,7 +198,8 @@ gLgK8d8sKL60JMmKHN3boHrsThKBVA== ->willReturn($appArray); - $this->installer->downloadApp('news'); + $installer = $this->getInstaller(); + $installer->downloadApp('news'); } /** @@ -239,7 +241,8 @@ YSu356M= ->method('get') ->willReturn($appArray); - $this->installer->downloadApp('news'); + $installer = $this->getInstaller(); + $installer->downloadApp('news'); } /** @@ -281,7 +284,8 @@ cR92p/PYCFXkAKP3OO0RPlf6dXNKTw== ->method('get') ->willReturn($appArray); - $this->installer->downloadApp('news'); + $installer = $this->getInstaller(); + $installer->downloadApp('news'); } /** @@ -348,7 +352,8 @@ cR92p/PYCFXkAKP3OO0RPlf6dXNKTw== ->method('newClient') ->willReturn($client); - $this->installer->downloadApp('passman'); + $installer = $this->getInstaller(); + $installer->downloadApp('passman'); } /** @@ -431,7 +436,8 @@ YwDVP+QmNRzx72jtqAN/Kc3CvQ9nkgYhU65B95aX0xA=', ->method('newClient') ->willReturn($client); - $this->installer->downloadApp('testapp'); + $installer = $this->getInstaller(); + $installer->downloadApp('testapp'); } /** @@ -513,7 +519,8 @@ YwDVP+QmNRzx72jtqAN/Kc3CvQ9nkgYhU65B95aX0xA=', ->method('newClient') ->willReturn($client); - $this->installer->downloadApp('testapp'); + $installer = $this->getInstaller(); + $installer->downloadApp('testapp'); } public function testDownloadAppSuccessful() { @@ -591,7 +598,8 @@ MPLX6f5V9tCJtlH6ztmEcDROfvuVc0U3rEhqx2hphoyo+MZrPFpdcJL8KkIdMKbY ->method('newClient') ->willReturn($client); - $this->installer->downloadApp('testapp'); + $installer = $this->getInstaller(); + $installer->downloadApp('testapp'); $this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml')); $this->assertEquals('0.9', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/')); @@ -679,7 +687,8 @@ JXhrdaWDZ8fzpUjugrtC3qslsqL0dzgU37anS3HwrT8=', $this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml')); $this->assertEquals('0.9', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/')); - $this->installer->downloadApp('testapp'); + $installer = $this->getInstaller(); + $installer->downloadApp('testapp'); $this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml')); $this->assertEquals('0.8', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/')); } diff --git a/tests/lib/LoggerTest.php b/tests/lib/LoggerTest.php index 54336da105c..6f528bd6fab 100644 --- a/tests/lib/LoggerTest.php +++ b/tests/lib/LoggerTest.php @@ -90,7 +90,7 @@ class LoggerTest extends TestCase { $e = new \Exception('test'); $this->registry->expects($this->once()) ->method('delegateReport') - ->with($e, []); + ->with($e, ['level' => 3]); $this->logger->logException($e); @@ -109,7 +109,7 @@ class LoggerTest extends TestCase { $e = new \Exception('test'); $this->registry->expects($this->once()) ->method('delegateReport') - ->with($e, []); + ->with($e, ['level' => 3]); $this->logger->logException($e); @@ -128,7 +128,7 @@ class LoggerTest extends TestCase { $e = new \Exception('test'); $this->registry->expects($this->once()) ->method('delegateReport') - ->with($e, []); + ->with($e, ['level' => 3]); $this->logger->logException($e); @@ -147,7 +147,7 @@ class LoggerTest extends TestCase { $e = new \Exception('test'); $this->registry->expects($this->once()) ->method('delegateReport') - ->with($e, []); + ->with($e, ['level' => 3]); $this->logger->logException($e); diff --git a/tests/lib/SetupTest.php b/tests/lib/SetupTest.php index 78c35a5b0bb..e6e9fb5c56c 100644 --- a/tests/lib/SetupTest.php +++ b/tests/lib/SetupTest.php @@ -9,6 +9,7 @@ namespace Test; use bantu\IniGetWrapper\IniGetWrapper; +use OC\Installer; use OC\SystemConfig; use OCP\Defaults; use OCP\IL10N; @@ -31,6 +32,8 @@ class SetupTest extends \Test\TestCase { protected $logger; /** @var \OCP\Security\ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */ protected $random; + /** @var Installer|\PHPUnit_Framework_MockObject_MockObject */ + protected $installer; protected function setUp() { parent::setUp(); @@ -41,9 +44,10 @@ class SetupTest extends \Test\TestCase { $this->defaults = $this->createMock(Defaults::class); $this->logger = $this->createMock(ILogger::class); $this->random = $this->createMock(ISecureRandom::class); + $this->installer = $this->createMock(Installer::class); $this->setupClass = $this->getMockBuilder('\OC\Setup') ->setMethods(['class_exists', 'is_callable', 'getAvailableDbDriversForPdo']) - ->setConstructorArgs([$this->config, $this->iniWrapper, $this->l10n, $this->defaults, $this->logger, $this->random]) + ->setConstructorArgs([$this->config, $this->iniWrapper, $this->l10n, $this->defaults, $this->logger, $this->random, $this->installer]) ->getMock(); } diff --git a/tests/lib/UpdaterTest.php b/tests/lib/UpdaterTest.php index afa0635768d..a6a8224ac34 100644 --- a/tests/lib/UpdaterTest.php +++ b/tests/lib/UpdaterTest.php @@ -22,6 +22,7 @@ namespace Test; +use OC\Installer; use OC\Updater; use OCP\IConfig; use OCP\ILogger; @@ -36,6 +37,8 @@ class UpdaterTest extends TestCase { private $updater; /** @var Checker | \PHPUnit_Framework_MockObject_MockObject */ private $checker; + /** @var Installer|\PHPUnit_Framework_MockObject_MockObject */ + private $installer; public function setUp() { parent::setUp(); @@ -46,13 +49,17 @@ class UpdaterTest extends TestCase { ->disableOriginalConstructor() ->getMock(); $this->checker = $this->getMockBuilder(Checker::class) - ->disableOriginalConstructor() - ->getMock(); + ->disableOriginalConstructor() + ->getMock(); + $this->installer = $this->getMockBuilder(Installer::class) + ->disableOriginalConstructor() + ->getMock(); $this->updater = new Updater( $this->config, $this->checker, - $this->logger + $this->logger, + $this->installer ); } |