diff options
45 files changed, 1541 insertions, 219 deletions
diff --git a/apps/comments/css/comments.css b/apps/comments/css/comments.css index 5e247aaeb71..b86ed38efe7 100644 --- a/apps/comments/css/comments.css +++ b/apps/comments/css/comments.css @@ -50,6 +50,33 @@ right: 0; } +#commentsTabView .comment .action { + opacity: 0; + vertical-align: middle; + display: inline-block; +} + +#commentsTabView .comment:hover .action { + opacity: 0.3; +} + +#commentsTabView .comment .action:hover { + opacity: 1; +} + +#commentsTabView .comment .action.delete { + position: absolute; + right: 0; +} + +#commentsTabView .comment.disabled { + opacity: 0.3; +} + +#commentsTabView .comment.disabled .action { + visibility: hidden; +} + .app-files .action-comment>img { margin-right: 5px; } diff --git a/apps/comments/js/commentmodel.js b/apps/comments/js/commentmodel.js index ba04fd61de3..89492707b61 100644 --- a/apps/comments/js/commentmodel.js +++ b/apps/comments/js/commentmodel.js @@ -39,8 +39,17 @@ }, parse: function(data) { - data.isUnread = (data.isUnread === 'true'); - return data; + return { + id: data.id, + message: data.message, + actorType: data.actorType, + actorId: data.actorId, + actorDisplayName: data.actorDisplayName, + creationDateTime: data.creationDateTime, + objectType: data.objectType, + objectId: data.objectId, + isUnread: (data.isUnread === 'true') + }; } }); diff --git a/apps/comments/js/commentstabview.js b/apps/comments/js/commentstabview.js index 188d8c5943c..2c5e9414751 100644 --- a/apps/comments/js/commentstabview.js +++ b/apps/comments/js/commentstabview.js @@ -8,27 +8,37 @@ * */ +/* global Handlebars */ + (function(OC, OCA) { var TEMPLATE = - '<div class="newCommentRow comment">' + + '<ul class="comments">' + + '</ul>' + + '<div class="empty hidden">{{emptyResultLabel}}</div>' + + '<input type="button" class="showMore hidden" value="{{moreLabel}}"' + + ' name="show-more" id="show-more" />' + + '<div class="loading hidden" style="height: 50px"></div>'; + + var EDIT_COMMENT_TEMPLATE = + '<div class="newCommentRow comment" data-id="{{id}}">' + ' <div class="authorRow">' + ' {{#if avatarEnabled}}' + - ' <div class="avatar" data-username="{{userId}}"></div>' + + ' <div class="avatar" data-username="{{actorId}}"></div>' + ' {{/if}}' + - ' <div class="author">{{userDisplayName}}</div>' + + ' <div class="author">{{actorDisplayName}}</div>' + + '{{#if isEditMode}}' + + ' <a href="#" class="action delete icon icon-delete has-tooltip" title="{{deleteTooltip}}"></a>' + + '{{/if}}' + ' </div>' + ' <form class="newCommentForm">' + - ' <textarea class="message" placeholder="{{newMessagePlaceholder}}"></textarea>' + + ' <textarea class="message" placeholder="{{newMessagePlaceholder}}">{{{message}}}</textarea>' + ' <input class="submit" type="submit" value="{{submitText}}" />' + + '{{#if isEditMode}}' + + ' <input class="cancel" type="button" value="{{cancelText}}" />' + + '{{/if}}' + ' <div class="submitLoading icon-loading-small hidden"></div>'+ ' </form>' + - ' <ul class="comments">' + - ' </ul>' + - '</div>' + - '<div class="empty hidden">{{emptyResultLabel}}</div>' + - '<input type="button" class="showMore hidden" value="{{moreLabel}}"' + - ' name="show-more" id="show-more" />' + - '<div class="loading hidden" style="height: 50px"></div>'; + '</div>'; var COMMENT_TEMPLATE = '<li class="comment{{#if isUnread}} unread{{/if}}" data-id="{{id}}">' + @@ -37,6 +47,9 @@ ' <div class="avatar" data-username="{{actorId}}"> </div>' + ' {{/if}}' + ' <div class="author">{{actorDisplayName}}</div>' + + '{{#if isUserAuthor}}' + + ' <a href="#" class="action edit icon icon-rename has-tooltip" title="{{editTooltip}}"></a>' + + '{{/if}}' + ' <div class="date has-tooltip" title="{{altDate}}">{{date}}</div>' + ' </div>' + ' <div class="message">{{{formattedMessage}}}</div>' + @@ -52,7 +65,10 @@ events: { 'submit .newCommentForm': '_onSubmitComment', - 'click .showMore': '_onClickShowMore' + 'click .showMore': '_onClickShowMore', + 'click .action.edit': '_onClickEditComment', + 'click .action.delete': '_onClickDeleteComment', + 'click .cancel': '_onClickCloseComment' }, initialize: function() { @@ -65,7 +81,6 @@ this._avatarsEnabled = !!OC.config.enable_avatars; // TODO: error handling - _.bindAll(this, '_onSubmitComment'); }, template: function(params) { @@ -75,10 +90,24 @@ var currentUser = OC.getCurrentUser(); return this._template(_.extend({ avatarEnabled: this._avatarsEnabled, - userId: currentUser.uid, - userDisplayName: currentUser.displayName, + actorId: currentUser.uid, + actorDisplayName: currentUser.displayName + }, params)); + }, + + editCommentTemplate: function(params) { + if (!this._editCommentTemplate) { + this._editCommentTemplate = Handlebars.compile(EDIT_COMMENT_TEMPLATE); + } + var currentUser = OC.getCurrentUser(); + return this._editCommentTemplate(_.extend({ + avatarEnabled: this._avatarsEnabled, + actorId: currentUser.uid, + actorDisplayName: currentUser.displayName, newMessagePlaceholder: t('comments', 'Type in a new comment...'), - submitText: t('comments', 'Post') + deleteTooltip: t('comments', 'Delete comment'), + submitText: t('comments', 'Post'), + cancelText: t('comments', 'Cancel') }, params)); }, @@ -87,7 +116,9 @@ this._commentTemplate = Handlebars.compile(COMMENT_TEMPLATE); } return this._commentTemplate(_.extend({ - avatarEnabled: this._avatarsEnabled + avatarEnabled: this._avatarsEnabled, + editTooltip: t('comments', 'Edit comment'), + isUserAuthor: OC.getCurrentUser().uid === params.actorId }, params)); }, @@ -115,6 +146,7 @@ emptyResultLabel: t('comments', 'No other comments available'), moreLabel: t('comments', 'More comments...') })); + this.$el.find('.comments').before(this.editCommentTemplate({})); this.$el.find('.has-tooltip').tooltip(); this.$container = this.$el.find('ul.comments'); this.$el.find('.avatar').avatar(OC.getCurrentUser().uid, 28); @@ -136,9 +168,11 @@ this.$el.find('.loading').toggleClass('hidden', !state); }, - _onRequest: function() { - this._toggleLoading(true); - this.$el.find('.showMore').addClass('hidden'); + _onRequest: function(type) { + if (type === 'REPORT') { + this._toggleLoading(true); + this.$el.find('.showMore').addClass('hidden'); + } }, _onEndRequest: function(type) { @@ -203,13 +237,69 @@ this.collection.fetchNext(); }, + _onClickEditComment: function(ev) { + ev.preventDefault(); + var $comment = $(ev.target).closest('.comment'); + var commentId = $comment.data('id'); + var commentToEdit = this.collection.get(commentId); + var $formRow = $(this.editCommentTemplate(_.extend({ + isEditMode: true, + submitText: t('comments', 'Save') + }, commentToEdit.attributes))); + + $comment.addClass('hidden'); + // spawn form + $comment.after($formRow); + $formRow.data('commentEl', $comment); + + // copy avatar element from original to avoid flickering + $formRow.find('.avatar').replaceWith($comment.find('.avatar').clone()); + $formRow.find('.has-tooltip').tooltip(); + + return false; + }, + + _onClickCloseComment: function(ev) { + ev.preventDefault(); + var $row = $(ev.target).closest('.comment'); + $row.data('commentEl').removeClass('hidden'); + $row.remove(); + return false; + }, + + _onClickDeleteComment: function(ev) { + ev.preventDefault(); + var $comment = $(ev.target).closest('.comment'); + var commentId = $comment.data('id'); + var $loading = $comment.find('.submitLoading'); + + $comment.addClass('disabled'); + $loading.removeClass('hidden'); + this.collection.get(commentId).destroy({ + success: function() { + $comment.data('commentEl').remove(); + $comment.remove(); + }, + error: function(msg) { + $loading.addClass('hidden'); + $comment.removeClass('disabled'); + OC.Notification.showTemporary(msg); + } + }); + + + return false; + }, + _onClickShowMore: function(ev) { ev.preventDefault(); this.nextPage(); }, _onSubmitComment: function(e) { + var self = this; var $form = $(e.target); + var commentId = $form.closest('.comment').data('id'); var currentUser = OC.getCurrentUser(); var $submit = $form.find('.submit'); var $loading = $form.find('.submitLoading'); @@ -225,28 +315,56 @@ $submit.addClass('hidden'); $loading.removeClass('hidden'); - this.collection.create({ - actorId: currentUser.uid, - actorDisplayName: currentUser.displayName, - actorType: 'users', - verb: 'comment', - message: $textArea.val(), - creationDateTime: (new Date()).toUTCString() - }, { - at: 0, - success: function() { - $submit.removeClass('hidden'); - $loading.addClass('hidden'); - $textArea.val('').prop('disabled', false); - }, - error: function(msg) { - $submit.removeClass('hidden'); - $loading.addClass('hidden'); - $textArea.prop('disabled', false); - - OC.Notification.showTemporary(msg); - } - }); + if (commentId) { + // edit mode + var comment = this.collection.get(commentId); + comment.save({ + message: $textArea.val() + }, { + success: function(model) { + var $row = $form.closest('.comment'); + $submit.removeClass('hidden'); + $loading.addClass('hidden'); + $row.data('commentEl') + .removeClass('hidden') + .find('.message') + .html(self._formatMessage(model.get('message'))); + $row.remove(); + }, + error: function(msg) { + $submit.removeClass('hidden'); + $loading.addClass('hidden'); + $textArea.prop('disabled', false); + + OC.Notification.showTemporary(msg); + } + }); + } else { + this.collection.create({ + actorId: currentUser.uid, + actorDisplayName: currentUser.displayName, + actorType: 'users', + verb: 'comment', + message: $textArea.val(), + creationDateTime: (new Date()).toUTCString() + }, { + at: 0, + // wait for real creation before adding + wait: true, + success: function() { + $submit.removeClass('hidden'); + $loading.addClass('hidden'); + $textArea.val('').prop('disabled', false); + }, + error: function(msg) { + $submit.removeClass('hidden'); + $loading.addClass('hidden'); + $textArea.prop('disabled', false); + + OC.Notification.showTemporary(msg); + } + }); + } return false; } diff --git a/apps/comments/tests/js/commentstabviewSpec.js b/apps/comments/tests/js/commentstabviewSpec.js index 432fa5ddc4c..4c3d38290ba 100644 --- a/apps/comments/tests/js/commentstabviewSpec.js +++ b/apps/comments/tests/js/commentstabviewSpec.js @@ -195,6 +195,140 @@ describe('OCA.Comments.CommentsTabView tests', function() { }); }); + describe('editing comments', function() { + var saveStub; + var currentUserStub; + + beforeEach(function() { + saveStub = sinon.stub(OCA.Comments.CommentModel.prototype, 'save'); + currentUserStub = sinon.stub(OC, 'getCurrentUser'); + currentUserStub.returns({ + uid: 'testuser', + displayName: 'Test User' + }); + view.collection.add({ + id: 1, + actorId: 'testuser', + actorDisplayName: 'Test User', + actorType: 'users', + verb: 'comment', + message: 'New message', + creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString() + }); + view.collection.add({ + id: 2, + actorId: 'anotheruser', + actorDisplayName: 'Another User', + actorType: 'users', + verb: 'comment', + message: 'New message from another user', + creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString() + }); + }); + afterEach(function() { + saveStub.restore(); + currentUserStub.restore(); + }); + + it('shows edit link for owner comments', function() { + var $comment = view.$el.find('.comment[data-id=1]'); + expect($comment.length).toEqual(1); + expect($comment.find('.action.edit').length).toEqual(1); + }); + + it('does not show edit link for other user\'s comments', function() { + var $comment = view.$el.find('.comment[data-id=2]'); + expect($comment.length).toEqual(1); + expect($comment.find('.action.edit').length).toEqual(0); + }); + + it('shows edit form when clicking edit', function() { + var $comment = view.$el.find('.comment[data-id=1]'); + $comment.find('.action.edit').click(); + + expect($comment.hasClass('hidden')).toEqual(true); + var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(1); + }); + + it('saves message and updates comment item when clicking save', function() { + var $comment = view.$el.find('.comment[data-id=1]'); + $comment.find('.action.edit').click(); + + var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(1); + + $formRow.find('textarea').val('modified\nmessage'); + $formRow.find('form').submit(); + + expect(saveStub.calledOnce).toEqual(true); + expect(saveStub.lastCall.args[0]).toEqual({ + message: 'modified\nmessage' + }); + + var model = view.collection.get(1); + // simulate the fact that save sets the attribute + model.set('message', 'modified\nmessage'); + saveStub.yieldTo('success', model); + + // original comment element is visible again + expect($comment.hasClass('hidden')).toEqual(false); + // and its message was updated + expect($comment.find('.message').html()).toEqual('modified<br>message'); + + // form row is gone + $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(0); + }); + + it('restores original comment when cancelling', function() { + var $comment = view.$el.find('.comment[data-id=1]'); + $comment.find('.action.edit').click(); + + var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(1); + + $formRow.find('textarea').val('modified\nmessage'); + $formRow.find('.cancel').click(); + + expect(saveStub.notCalled).toEqual(true); + + // original comment element is visible again + expect($comment.hasClass('hidden')).toEqual(false); + // and its message was not updated + expect($comment.find('.message').html()).toEqual('New message'); + + // form row is gone + $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(0); + }); + + it('destroys model when clicking delete', function() { + var destroyStub = sinon.stub(OCA.Comments.CommentModel.prototype, 'destroy'); + var $comment = view.$el.find('.comment[data-id=1]'); + $comment.find('.action.edit').click(); + + var $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(1); + + $formRow.find('.delete').click(); + + expect(destroyStub.calledOnce).toEqual(true); + expect(destroyStub.thisValues[0].id).toEqual(1); + + destroyStub.yieldTo('success'); + + // original comment element is gone + $comment = view.$el.find('.comment[data-id=1]'); + expect($comment.length).toEqual(0); + + // form row is gone + $formRow = view.$el.find('.newCommentRow.comment[data-id=1]'); + expect($formRow.length).toEqual(0); + + destroyStub.restore(); + }); + }); describe('read marker', function() { var updateMarkerStub; diff --git a/apps/dav/appinfo/register_command.php b/apps/dav/appinfo/register_command.php index e8fea5daf23..e8ca370f84f 100644 --- a/apps/dav/appinfo/register_command.php +++ b/apps/dav/appinfo/register_command.php @@ -36,7 +36,7 @@ $app = new Application(); /** @var Symfony\Component\Console\Application $application */ $application->add(new CreateAddressBook($userManager, $groupManager, $dbConnection, $logger)); -$application->add(new CreateCalendar($userManager, $dbConnection)); +$application->add(new CreateCalendar($userManager, $groupManager, $dbConnection)); $application->add(new SyncSystemAddressBook($app->getSyncService())); // the occ tool is *for now* only available in debug mode for developers to test diff --git a/apps/dav/command/createcalendar.php b/apps/dav/command/createcalendar.php index 34bc061c45b..d7f82dd0e52 100644 --- a/apps/dav/command/createcalendar.php +++ b/apps/dav/command/createcalendar.php @@ -21,7 +21,9 @@ namespace OCA\DAV\Command; use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\Connector\Sabre\Principal; use OCP\IDBConnection; +use OCP\IGroupManager; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -33,6 +35,9 @@ class CreateCalendar extends Command { /** @var IUserManager */ protected $userManager; + /** @var IGroupManager $groupManager */ + private $groupManager; + /** @var \OCP\IDBConnection */ protected $dbConnection; @@ -40,9 +45,10 @@ class CreateCalendar extends Command { * @param IUserManager $userManager * @param IDBConnection $dbConnection */ - function __construct(IUserManager $userManager, IDBConnection $dbConnection) { + function __construct(IUserManager $userManager, IGroupManager $groupManager, IDBConnection $dbConnection) { parent::__construct(); $this->userManager = $userManager; + $this->groupManager = $groupManager; $this->dbConnection = $dbConnection; } @@ -63,8 +69,13 @@ class CreateCalendar extends Command { if (!$this->userManager->userExists($user)) { throw new \InvalidArgumentException("User <$user> in unknown."); } + $principalBackend = new Principal( + $this->userManager, + $this->groupManager + ); + $name = $input->getArgument('name'); - $caldav = new CalDavBackend($this->dbConnection); + $caldav = new CalDavBackend($this->dbConnection, $principalBackend); $caldav->createCalendar("principals/users/$user", $name, []); } } diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php index 0b70b37967f..3aa493e5087 100644 --- a/apps/dav/lib/caldav/caldavbackend.php +++ b/apps/dav/lib/caldav/caldavbackend.php @@ -23,6 +23,8 @@ namespace OCA\DAV\CalDAV; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCA\DAV\Connector\Sabre\Principal; +use OCA\DAV\DAV\Sharing\Backend; use Sabre\CalDAV\Backend\AbstractBackend; use Sabre\CalDAV\Backend\SchedulingSupport; use Sabre\CalDAV\Backend\SubscriptionSupport; @@ -32,6 +34,7 @@ use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp; use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; use Sabre\DAV; use Sabre\DAV\Exception\Forbidden; +use Sabre\HTTP\URLUtil; use Sabre\VObject\DateTimeParser; use Sabre\VObject\Reader; use Sabre\VObject\RecurrenceIterator; @@ -86,8 +89,24 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription '{http://calendarserver.org/ns/}subscribed-strip-attachments' => 'stripattachments', ]; - public function __construct(\OCP\IDBConnection $db) { + /** @var \OCP\IDBConnection */ + private $db; + + /** @var Backend */ + private $sharingBackend; + + /** @var Principal */ + private $principalBackend; + + /** + * CalDavBackend constructor. + * + * @param \OCP\IDBConnection $db + */ + public function __construct(\OCP\IDBConnection $db, Principal $principalBackend) { $this->db = $db; + $this->principalBackend = $principalBackend; + $this->sharingBackend = new Backend($this->db, 'calendar'); } /** @@ -153,10 +172,60 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $calendar[$xmlName] = $row[$dbName]; } - $calendars[] = $calendar; + $calendars[$calendar['id']] = $calendar; + } + + $stmt->closeCursor(); + + // query for shared calendars + $principals = $this->principalBackend->getGroupMembership($principalUri); + $principals[]= $principalUri; + + $fields = array_values($this->propertyMap); + $fields[] = 'a.id'; + $fields[] = 'a.uri'; + $fields[] = 'a.synctoken'; + $fields[] = 'a.components'; + $fields[] = 'a.principaluri'; + $fields[] = 'a.transparent'; + $query = $this->db->getQueryBuilder(); + $result = $query->select($fields) + ->from('dav_shares', 's') + ->join('s', 'calendars', 'a', $query->expr()->eq('s.resourceid', 'a.id')) + ->where($query->expr()->in('s.principaluri', $query->createParameter('principaluri'))) + ->andWhere($query->expr()->eq('s.type', $query->createParameter('type'))) + ->setParameter('type', 'calendar') + ->setParameter('principaluri', $principals, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY) + ->execute(); + + while($row = $result->fetch()) { + list(, $name) = URLUtil::splitPath($row['principaluri']); + $uri = $row['uri'] . '_shared_by_' . $name; + $row['displayname'] = $row['displayname'] . "($name)"; + $components = []; + if ($row['components']) { + $components = explode(',',$row['components']); + } + $calendar = [ + 'id' => $row['id'], + 'uri' => $uri, + 'principaluri' => $principalUri, + '{' . Plugin::NS_CALENDARSERVER . '}getctag' => 'http://sabre.io/ns/sync/' . ($row['synctoken']?$row['synctoken']:'0'), + '{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0', + '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components), + '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'), + '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $row['principaluri'], + ]; + + foreach($this->propertyMap as $xmlName=>$dbName) { + $calendar[$xmlName] = $row[$dbName]; + } + + $calendars[$calendar['id']] = $calendar; } + $result->closeCursor(); - return $calendars; + return array_values($calendars); } /** @@ -271,6 +340,8 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription $stmt = $this->db->prepare('DELETE FROM `*PREFIX*calendarchanges` WHERE `calendarid` = ?'); $stmt->execute([$calendarId]); + + $this->sharingBackend->deleteAllShares($calendarId); } /** @@ -1173,4 +1244,17 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription return $cardData; } + + public function updateShares($shareable, $add, $remove) { + $this->sharingBackend->updateShares($shareable, $add, $remove); + } + + public function getShares($resourceId) { + return $this->sharingBackend->getShares($resourceId); + } + + public function applyShareAcl($addressBookId, $acl) { + return $this->sharingBackend->applyShareAcl($addressBookId, $acl); + } + } diff --git a/apps/dav/lib/caldav/calendar.php b/apps/dav/lib/caldav/calendar.php new file mode 100644 index 00000000000..8ed5b6563d0 --- /dev/null +++ b/apps/dav/lib/caldav/calendar.php @@ -0,0 +1,102 @@ +<?php + +namespace OCA\DAV\CalDAV; + +use OCA\DAV\DAV\Sharing\IShareable; +use Sabre\DAV\Exception\Forbidden; + +class Calendar extends \Sabre\CalDAV\Calendar implements IShareable { + + /** + * Updates the list of shares. + * + * The first array is a list of people that are to be added to the + * resource. + * + * Every element in the add array has the following properties: + * * href - A url. Usually a mailto: address + * * commonName - Usually a first and last name, or false + * * summary - A description of the share, can also be false + * * readOnly - A boolean value + * + * Every element in the remove array is just the address string. + * + * @param array $add + * @param array $remove + * @return void + */ + function updateShares(array $add, array $remove) { + /** @var CalDavBackend $calDavBackend */ + $calDavBackend = $this->caldavBackend; + $calDavBackend->updateShares($this, $add, $remove); + } + + /** + * Returns the list of people whom this resource is shared with. + * + * Every element in this array should have the following properties: + * * href - Often a mailto: address + * * commonName - Optional, for example a first + last name + * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. + * * readOnly - boolean + * * summary - Optional, a description for the share + * + * @return array + */ + function getShares() { + /** @var CalDavBackend $calDavBackend */ + $calDavBackend = $this->caldavBackend; + return $calDavBackend->getShares($this->getResourceId()); + } + + /** + * @return int + */ + public function getResourceId() { + return $this->calendarInfo['id']; + } + + function getACL() { + $acl = parent::getACL(); + + /** @var CalDavBackend $calDavBackend */ + $calDavBackend = $this->caldavBackend; + return $calDavBackend->applyShareAcl($this->getResourceId(), $acl); + } + + function getChildACL() { + $acl = parent::getChildACL(); + + /** @var CalDavBackend $calDavBackend */ + $calDavBackend = $this->caldavBackend; + return $calDavBackend->applyShareAcl($this->getResourceId(), $acl); + } + + function getOwner() { + if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) { + return $this->calendarInfo['{http://owncloud.org/ns}owner-principal']; + } + return parent::getOwner(); + } + + function delete() { + if (isset($this->calendarInfo['{http://owncloud.org/ns}owner-principal'])) { + $principal = 'principal:' . parent::getOwner(); + $shares = $this->getShares(); + $shares = array_filter($shares, function($share) use ($principal){ + return $share['href'] === $principal; + }); + if (empty($shares)) { + throw new Forbidden(); + } + + /** @var CalDavBackend $calDavBackend */ + $calDavBackend = $this->caldavBackend; + $calDavBackend->updateShares($this, [], [ + 'href' => $principal + ]); + return; + } + parent::delete(); + } +} diff --git a/apps/dav/lib/caldav/calendarhome.php b/apps/dav/lib/caldav/calendarhome.php new file mode 100644 index 00000000000..7f98dfb94e0 --- /dev/null +++ b/apps/dav/lib/caldav/calendarhome.php @@ -0,0 +1,78 @@ +<?php + +namespace OCA\DAV\CalDAV; + +use Sabre\CalDAV\Backend\NotificationSupport; +use Sabre\CalDAV\Backend\SchedulingSupport; +use Sabre\CalDAV\Backend\SubscriptionSupport; +use Sabre\CalDAV\Schedule\Inbox; +use Sabre\CalDAV\Schedule\Outbox; +use Sabre\CalDAV\Subscriptions\Subscription; +use Sabre\DAV\Exception\NotFound; + +class CalendarHome extends \Sabre\CalDAV\CalendarHome { + + /** + * @inheritdoc + */ + function getChildren() { + $calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']); + $objs = []; + foreach ($calendars as $calendar) { + $objs[] = new Calendar($this->caldavBackend, $calendar); + } + + if ($this->caldavBackend instanceof SchedulingSupport) { + $objs[] = new Inbox($this->caldavBackend, $this->principalInfo['uri']); + $objs[] = new Outbox($this->principalInfo['uri']); + } + + // We're adding a notifications node, if it's supported by the backend. + if ($this->caldavBackend instanceof NotificationSupport) { + $objs[] = new \Sabre\CalDAV\Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']); + } + + // If the backend supports subscriptions, we'll add those as well, + if ($this->caldavBackend instanceof SubscriptionSupport) { + foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) { + $objs[] = new Subscription($this->caldavBackend, $subscription); + } + } + + return $objs; + } + + /** + * @inheritdoc + */ + function getChild($name) { + // Special nodes + if ($name === 'inbox' && $this->caldavBackend instanceof SchedulingSupport) { + return new Inbox($this->caldavBackend, $this->principalInfo['uri']); + } + if ($name === 'outbox' && $this->caldavBackend instanceof SchedulingSupport) { + return new Outbox($this->principalInfo['uri']); + } + if ($name === 'notifications' && $this->caldavBackend instanceof NotificationSupport) { + return new \Sabre\CalDAv\Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']); + } + + // Calendars + foreach ($this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']) as $calendar) { + if ($calendar['uri'] === $name) { + return new Calendar($this->caldavBackend, $calendar); + } + } + + if ($this->caldavBackend instanceof SubscriptionSupport) { + foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) { + if ($subscription['uri'] === $name) { + return new Subscription($this->caldavBackend, $subscription); + } + } + + } + + throw new NotFound('Node with name \'' . $name . '\' could not be found'); + } +}
\ No newline at end of file diff --git a/apps/dav/lib/caldav/calendarroot.php b/apps/dav/lib/caldav/calendarroot.php new file mode 100644 index 00000000000..ae5fc54cdf3 --- /dev/null +++ b/apps/dav/lib/caldav/calendarroot.php @@ -0,0 +1,10 @@ +<?php + +namespace OCA\DAV\CalDAV; + +class CalendarRoot extends \Sabre\CalDAV\CalendarRoot { + + function getChildForPrincipal(array $principal) { + return new CalendarHome($this->caldavBackend, $principal); + } +}
\ No newline at end of file diff --git a/apps/dav/lib/carddav/addressbook.php b/apps/dav/lib/carddav/addressbook.php index 513eae4d723..ca3f5ba0ef6 100644 --- a/apps/dav/lib/carddav/addressbook.php +++ b/apps/dav/lib/carddav/addressbook.php @@ -21,6 +21,7 @@ namespace OCA\DAV\CardDAV; use OCA\DAV\DAV\Sharing\IShareable; +use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable { @@ -132,4 +133,32 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareable { public function getResourceId() { return $this->addressBookInfo['id']; } + + function getOwner() { + if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) { + return $this->addressBookInfo['{http://owncloud.org/ns}owner-principal']; + } + return parent::getOwner(); + } + + function delete() { + if (isset($this->addressBookInfo['{http://owncloud.org/ns}owner-principal'])) { + $principal = 'principal:' . parent::getOwner(); + $shares = $this->getShares(); + $shares = array_filter($shares, function($share) use ($principal){ + return $share['href'] === $principal; + }); + if (empty($shares)) { + throw new Forbidden(); + } + + /** @var CardDavBackend $cardDavBackend */ + $cardDavBackend = $this->carddavBackend; + $cardDavBackend->updateShares($this, [], [ + 'href' => $principal + ]); + return; + } + parent::delete(); + } } diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php index 3dc5c00e10b..9ca166c22a2 100644 --- a/apps/dav/lib/carddav/carddavbackend.php +++ b/apps/dav/lib/carddav/carddavbackend.php @@ -103,7 +103,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { $result = $query->execute(); while($row = $result->fetch()) { - $addressBooks[] = [ + $addressBooks[$row['id']] = [ 'id' => $row['id'], 'uri' => $row['uri'], 'principaluri' => $row['principaluri'], @@ -133,7 +133,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { list(, $name) = URLUtil::splitPath($row['principaluri']); $uri = $row['uri'] . '_shared_by_' . $name; $displayName = $row['displayname'] . "($name)"; - $addressBooks[] = [ + $addressBooks[$row['id']] = [ 'id' => $row['id'], 'uri' => $uri, 'principaluri' => $principalUri, @@ -147,7 +147,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { } $result->closeCursor(); - return $addressBooks; + return array_values($addressBooks); } /** @@ -336,10 +336,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { ->setParameter('id', $addressBookId) ->execute(); - $query->delete('dav_shares') - ->where($query->expr()->eq('resourceid', $query->createNamedParameter($addressBookId))) - ->andWhere($query->expr()->eq('type', $query->createNamedParameter('addressbook'))) - ->execute(); + $this->sharingBackend->deleteAllShares($addressBookId); $query->delete($this->dbCardsPropertiesTable) ->where($query->expr()->eq('addressbookid', $query->createNamedParameter($addressBookId))) @@ -920,22 +917,6 @@ class CardDavBackend implements BackendInterface, SyncSupport { * @return array */ public function applyShareAcl($addressBookId, $acl) { - - $shares = $this->getShares($addressBookId); - foreach ($shares as $share) { - $acl[] = [ - 'privilege' => '{DAV:}read', - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], - 'protected' => true, - ]; - if (!$share['readOnly']) { - $acl[] = [ - 'privilege' => '{DAV:}write', - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], - 'protected' => true, - ]; - } - } - return $acl; + return $this->sharingBackend->applyShareAcl($addressBookId, $acl); } } diff --git a/apps/dav/lib/dav/sharing/backend.php b/apps/dav/lib/dav/sharing/backend.php index fee864ffe6f..0b28891fbc4 100644 --- a/apps/dav/lib/dav/sharing/backend.php +++ b/apps/dav/lib/dav/sharing/backend.php @@ -58,7 +58,7 @@ class Backend { $this->shareWith($shareable, $element); } foreach($remove as $element) { - $this->unshare($shareable->getResourceId(), $element); + $this->unshare($shareable, $element); } } @@ -73,8 +73,13 @@ class Backend { return; } + // don't share with owner + if ($shareable->getOwner() === $parts[1]) { + return; + } + // remove the share if it already exists - $this->unshare($shareable->getResourceId(), $element['href']); + $this->unshare($shareable, $element['href']); $access = self::ACCESS_READ; if (isset($element['readOnly'])) { $access = $element['readOnly'] ? self::ACCESS_READ : self::ACCESS_READ_WRITE; @@ -92,18 +97,34 @@ class Backend { } /** - * @param int $resourceId + * @param $resourceId + */ + public function deleteAllShares($resourceId) { + $query = $this->db->getQueryBuilder(); + $query->delete('dav_shares') + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType))) + ->execute(); + } + + /** + * @param IShareable $shareable * @param string $element */ - private function unshare($resourceId, $element) { + private function unshare($shareable, $element) { $parts = explode(':', $element, 2); if ($parts[0] !== 'principal') { return; } + // don't share with owner + if ($shareable->getOwner() === $parts[1]) { + return; + } + $query = $this->db->getQueryBuilder(); $query->delete('dav_shares') - ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($shareable->getResourceId()))) ->andWhere($query->expr()->eq('type', $query->createNamedParameter($this->resourceType))) ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($parts[1]))) ; @@ -136,7 +157,7 @@ class Backend { 'href' => "principal:${row['principaluri']}", // 'commonName' => isset($p['{DAV:}displayname']) ? $p['{DAV:}displayname'] : '', 'status' => 1, - 'readOnly' => ($row['access'] === self::ACCESS_READ), + 'readOnly' => ($row['access'] == self::ACCESS_READ), '{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}principal' => $row['principaluri'] ]; } diff --git a/apps/dav/lib/dav/sharing/plugin.php b/apps/dav/lib/dav/sharing/plugin.php index cbb4408e29b..f6e2cceebd9 100644 --- a/apps/dav/lib/dav/sharing/plugin.php +++ b/apps/dav/lib/dav/sharing/plugin.php @@ -23,9 +23,12 @@ namespace OCA\DAV\DAV\Sharing; use OCA\DAV\Connector\Sabre\Auth; +use OCA\DAV\DAV\Sharing\Xml\Invite; use OCP\IRequest; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\INode; +use Sabre\DAV\PropFind; use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; use Sabre\HTTP\RequestInterface; @@ -97,8 +100,10 @@ class Plugin extends ServerPlugin { function initialize(Server $server) { $this->server = $server; $this->server->xml->elementMap['{' . Plugin::NS_OWNCLOUD . '}share'] = 'OCA\\DAV\\DAV\\Sharing\\Xml\\ShareRequest'; + $this->server->xml->elementMap['{' . Plugin::NS_OWNCLOUD . '}invite'] = 'OCA\\DAV\\DAV\\Sharing\\Xml\\Invite'; $this->server->on('method:POST', [$this, 'httpPost']); + $this->server->on('propFind', [$this, 'propFind']); } /** @@ -174,6 +179,28 @@ class Plugin extends ServerPlugin { } } + /** + * This event is triggered when properties are requested for a certain + * node. + * + * This allows us to inject any properties early. + * + * @param PropFind $propFind + * @param INode $node + * @return void + */ + function propFind(PropFind $propFind, INode $node) { + if ($node instanceof IShareable) { + + $propFind->handle('{' . Plugin::NS_OWNCLOUD . '}invite', function() use ($node) { + return new Invite( + $node->getShares() + ); + }); + + } + } + private function protectAgainstCSRF() { $user = $this->auth->getCurrentUser(); if ($this->auth->isDavAuthenticated($user)) { diff --git a/apps/dav/lib/dav/sharing/xml/invite.php b/apps/dav/lib/dav/sharing/xml/invite.php new file mode 100644 index 00000000000..659f95d8074 --- /dev/null +++ b/apps/dav/lib/dav/sharing/xml/invite.php @@ -0,0 +1,149 @@ +<?php + +namespace OCA\DAV\DAV\Sharing\Xml; + +use OCA\DAV\DAV\Sharing\Plugin; +use Sabre\Xml\Writer; +use Sabre\Xml\XmlSerializable; + +/** + * Invite property + * + * This property encodes the 'invite' property, as defined by + * the 'caldav-sharing-02' spec, in the http://calendarserver.org/ns/ + * namespace. + * + * @see https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing-02.txt + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Invite implements XmlSerializable { + + /** + * The list of users a calendar has been shared to. + * + * @var array + */ + protected $users; + + /** + * The organizer contains information about the person who shared the + * object. + * + * @var array + */ + protected $organizer; + + /** + * Creates the property. + * + * Users is an array. Each element of the array has the following + * properties: + * + * * href - Often a mailto: address + * * commonName - Optional, for example a first and lastname for a user. + * * status - One of the SharingPlugin::STATUS_* constants. + * * readOnly - true or false + * * summary - Optional, description of the share + * + * The organizer key is optional to specify. It's only useful when a + * 'sharee' requests the sharing information. + * + * The organizer may have the following properties: + * * href - Often a mailto: address. + * * commonName - Optional human-readable name. + * * firstName - Optional first name. + * * lastName - Optional last name. + * + * If you wonder why these two structures are so different, I guess a + * valid answer is that the current spec is still a draft. + * + * @param array $users + */ + function __construct(array $users, array $organizer = null) { + + $this->users = $users; + $this->organizer = $organizer; + + } + + /** + * Returns the list of users, as it was passed to the constructor. + * + * @return array + */ + function getValue() { + + return $this->users; + + } + + /** + * The xmlSerialize metod is called during xml writing. + * + * Use the $writer argument to write its own xml serialization. + * + * An important note: do _not_ create a parent element. Any element + * implementing XmlSerializble should only ever write what's considered + * its 'inner xml'. + * + * The parent of the current element is responsible for writing a + * containing element. + * + * This allows serializers to be re-used for different element names. + * + * If you are opening new elements, you must also close them again. + * + * @param Writer $writer + * @return void + */ + function xmlSerialize(Writer $writer) { + + $cs = '{' . Plugin::NS_OWNCLOUD . '}'; + + if (!is_null($this->organizer)) { + + $writer->startElement($cs . 'organizer'); + $writer->writeElement('{DAV:}href', $this->organizer['href']); + + if (isset($this->organizer['commonName']) && $this->organizer['commonName']) { + $writer->writeElement($cs . 'common-name', $this->organizer['commonName']); + } + if (isset($this->organizer['firstName']) && $this->organizer['firstName']) { + $writer->writeElement($cs . 'first-name', $this->organizer['firstName']); + } + if (isset($this->organizer['lastName']) && $this->organizer['lastName']) { + $writer->writeElement($cs . 'last-name', $this->organizer['lastName']); + } + $writer->endElement(); // organizer + + } + + foreach ($this->users as $user) { + + $writer->startElement($cs . 'user'); + $writer->writeElement('{DAV:}href', $user['href']); + if (isset($user['commonName']) && $user['commonName']) { + $writer->writeElement($cs . 'common-name', $user['commonName']); + } + $writer->writeElement($cs . 'invite-accepted'); + + $writer->startElement($cs . 'access'); + if ($user['readOnly']) { + $writer->writeElement($cs . 'read'); + } else { + $writer->writeElement($cs . 'read-write'); + } + $writer->endElement(); // access + + if (isset($user['summary']) && $user['summary']) { + $writer->writeElement($cs . 'summary', $user['summary']); + } + + $writer->endElement(); //user + + } + + } +} diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index 5be469e7b0c..2a8f63a2270 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -22,12 +22,12 @@ namespace OCA\DAV; use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CalDAV\CalendarRoot; use OCA\DAV\CardDAV\AddressBookRoot; use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\DAV\GroupPrincipalBackend; use OCA\DAV\DAV\SystemPrincipalBackend; -use Sabre\CalDAV\CalendarRoot; use Sabre\CalDAV\Principal\Collection; use Sabre\DAV\SimpleCollection; @@ -55,7 +55,7 @@ class RootCollection extends SimpleCollection { $systemPrincipals->disableListing = $disableListing; $filesCollection = new Files\RootCollection($userPrincipalBackend, 'principals/users'); $filesCollection->disableListing = $disableListing; - $caldavBackend = new CalDavBackend($db); + $caldavBackend = new CalDavBackend($db, $userPrincipalBackend); $calendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; diff --git a/apps/dav/tests/travis/caldav/install.sh b/apps/dav/tests/travis/caldav/install.sh index e836e37f86f..9688ec660de 100644 --- a/apps/dav/tests/travis/caldav/install.sh +++ b/apps/dav/tests/travis/caldav/install.sh @@ -15,6 +15,7 @@ fi cd "$SCRIPTPATH/../../../../../" OC_PASS=user01 php occ user:add --password-from-env user01 php occ dav:create-calendar user01 calendar +php occ dav:create-calendar user01 shared OC_PASS=user02 php occ user:add --password-from-env user02 php occ dav:create-calendar user02 calendar cd "$SCRIPTPATH/../../../../../" diff --git a/apps/dav/tests/travis/caldav/script.sh b/apps/dav/tests/travis/caldav/script.sh index fe3391d5a06..aa5fc732922 100644 --- a/apps/dav/tests/travis/caldav/script.sh +++ b/apps/dav/tests/travis/caldav/script.sh @@ -10,9 +10,7 @@ sleep 30 # run the tests cd "$SCRIPTPATH/CalDAVTester" PYTHONPATH="$SCRIPTPATH/pycalendar/src" python testcaldav.py --print-details-onfail --basedir "$SCRIPTPATH/../caldavtest/" -o cdt.txt \ - "CalDAV/current-user-principal.xml" \ - "CalDAV/sync-report.xml" - + "CalDAV/sharing-calendars.xml" RESULT=$? diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml new file mode 100644 index 00000000000..3bcf9dc47f9 --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/1.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8" ?> +<CS:share xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns"> + <CS:set> + <D:href>principal:principals/users/user02</D:href> + <CS:summary>My Shared Calendar</CS:summary> + <CS:read-write/> + </CS:set> +</CS:share> diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml new file mode 100644 index 00000000000..fd0f248bb31 --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/4.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8" ?> +<D:propfind xmlns:D="DAV:"> +<D:prop> +<D:resourcetype/> +<D:owner/> +<D:current-user-privilege-set/> +</D:prop> +</D:propfind> diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics new file mode 100644 index 00000000000..ae21adac8b2 --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.ics @@ -0,0 +1,29 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//PYVOBJECT//NONSGML Version 1//EN +BEGIN:VTIMEZONE +TZID:US/Eastern +LAST-MODIFIED:20040110T032845Z +BEGIN:STANDARD +DTSTART:20001026T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZNAME:EST +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:20000404T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZNAME:EDT +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:$uid1: +DTSTART;TZID=US/Eastern:$now.year.1:0101T100000 +DURATION:PT1H +DTSTAMP:20051222T205953Z +SUMMARY:event 1 +END:VEVENT +END:VCALENDAR diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml new file mode 100644 index 00000000000..4862ed195f8 --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/5.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" ?> +<D:propfind xmlns:D="DAV:" xmlns:CS="http://owncloud.org/ns"> +<D:prop> +<CS:invite/> +</D:prop> +</D:propfind> diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics new file mode 100644 index 00000000000..145f5f14c7b --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/6.ics @@ -0,0 +1,29 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//PYVOBJECT//NONSGML Version 1//EN +BEGIN:VTIMEZONE +TZID:US/Eastern +LAST-MODIFIED:20040110T032845Z +BEGIN:STANDARD +DTSTART:20001026T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZNAME:EST +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:20000404T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZNAME:EDT +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:$uid1: +DTSTART;TZID=US/Eastern:$now.year.1:0101T100000 +DURATION:PT4H +DTSTAMP:20051222T205953Z +SUMMARY:event 4 +END:VEVENT +END:VCALENDAR diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics new file mode 100644 index 00000000000..c4e816210df --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/7.ics @@ -0,0 +1,29 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//PYVOBJECT//NONSGML Version 1//EN +BEGIN:VTIMEZONE +TZID:US/Eastern +LAST-MODIFIED:20040110T032845Z +BEGIN:STANDARD +DTSTART:20001026T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZNAME:EST +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:20000404T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZNAME:EDT +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:$uid2: +DTSTART;TZID=US/Eastern:$now.year.1:0201T100000 +DURATION:PT1H +DTSTAMP:20051222T205953Z +SUMMARY:event 7 +END:VEVENT +END:VCALENDAR diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics new file mode 100644 index 00000000000..2da72d2f601 --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/8.ics @@ -0,0 +1,29 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//PYVOBJECT//NONSGML Version 1//EN +BEGIN:VTIMEZONE +TZID:US/Eastern +LAST-MODIFIED:20040110T032845Z +BEGIN:STANDARD +DTSTART:20001026T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZNAME:EST +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:20000404T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZNAME:EDT +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:$uid2: +DTSTART;TZID=US/Eastern:$now.year.1:0201T100000 +DURATION:PT7H +DTSTAMP:20051222T205953Z +SUMMARY:event 7-1 +END:VEVENT +END:VCALENDAR diff --git a/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics new file mode 100644 index 00000000000..dfc21bb9c5b --- /dev/null +++ b/apps/dav/tests/travis/caldavtest/data/Resource/CalDAV/sharing/calendars/read-write/9.ics @@ -0,0 +1,29 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//PYVOBJECT//NONSGML Version 1//EN +BEGIN:VTIMEZONE +TZID:US/Eastern +LAST-MODIFIED:20040110T032845Z +BEGIN:STANDARD +DTSTART:20001026T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZNAME:EST +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:20000404T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZNAME:EDT +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:$uid3: +DTSTART;TZID=US/Eastern:$now.year.1:0201T100000 +DURATION:PT7H +DTSTAMP:20051222T205953Z +SUMMARY:event 9.ics +END:VEVENT +END:VCALENDAR diff --git a/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml b/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml index fa20a6e4862..334fa561aec 100644 --- a/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml +++ b/apps/dav/tests/travis/caldavtest/tests/CalDAV/sharing-calendars.xml @@ -27,6 +27,7 @@ </require-feature> <start> + <!-- <request user="$userid1:" pswd="$pswd1:"> <method>DELETEALL</method> <ruri>$notificationpath1:/</ruri> @@ -50,6 +51,7 @@ <filepath>Resource/Common/PROPPATCH/calendar-transp-opaque.xml</filepath> </data> </request> + --> </start> <test-suite name='Read-write calendar'> @@ -67,56 +69,11 @@ </verify> </request> </test> - <test name='2'> - <description>Check Sharee notification collection</description> - <request user="$userid2:" pswd="$pswd2:"> - <method>WAITCOUNT 1</method> - <ruri>$notificationpath2:/</ruri> - </request> - <request user="$userid2:" pswd="$pswd2:"> - <method>GETNEW</method> - <ruri>$notificationpath2:/</ruri> - <verify> - <callback>xmlDataMatch</callback> - <arg> - <name>filepath</name> - <value>Resource/CalDAV/sharing/calendars/read-write/2.xml</value> - </arg> - <arg> - <name>filter</name> - <value>{http://calendarserver.org/ns/}dtstamp</value> - <value>{http://calendarserver.org/ns/}uid</value> - </arg> - </verify> - <grabelement> - <name>{http://calendarserver.org/ns/}invite-notification/{http://calendarserver.org/ns/}uid</name> - <variable>$inviteuid:</variable> - </grabelement> - </request> - </test> - <test name='3'> - <description>Sharee replies ACCEPTED</description> - <request user="$userid2:" pswd="$pswd2:"> - <method>POST</method> - <ruri>$calendarhome2:/</ruri> - <data> - <content-type>application/xml; charset=utf-8</content-type> - <filepath>Resource/CalDAV/sharing/calendars/read-write/3.xml</filepath> - </data> - <verify> - <callback>statusCode</callback> - </verify> - <grabelement> - <name>{DAV:}href</name> - <variable>$sharedcalendar:</variable> - </grabelement> - </request> - </test> <test name='4'> <description>Shared calendar exists</description> <request user="$userid2:" pswd="$pswd2:"> <method>PROPFIND</method> - <ruri>$sharedcalendar:/</ruri> + <ruri>$calendarhome1:/shared/</ruri> <header> <name>Depth</name> <value>0</value> @@ -132,12 +89,12 @@ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value> <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value> <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:caldav}calendar</value> - <value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value> + <!-- value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value --> <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value> <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value> <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value> <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value> - <value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value> + <!-- value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value --> </arg> <arg> <name>notexists</name> @@ -151,7 +108,7 @@ <description>Shared calendar exists Depth:1</description> <request user="$userid2:" pswd="$pswd2:"> <method>PROPFIND</method> - <ruri>$calendarhome2:/</ruri> + <ruri>$calendarhome2:</ruri> <header> <name>Depth</name> <value>1</value> @@ -164,19 +121,19 @@ <callback>xmlElementMatch</callback> <arg> <name>parent</name> - <value>$multistatus-response-prefix:[^{DAV:}href=$sharedcalendar:/]</value> + <value>$multistatus-response-prefix:[^{DAV:}href=$calendarhome2:/shared_shared_by_user01/]</value> </arg> <arg> <name>exists</name> <value>$verify-response-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value> <value>$verify-response-prefix:/{DAV:}resourcetype/{DAV:}collection</value> <value>$verify-response-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:caldav}calendar</value> - <value>$verify-response-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value> + <!-- value>$verify-response-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value --> <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value> <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value> <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value> <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value> - <value>$verify-response-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value> + <!-- value>$verify-response-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value --> </arg> <arg> <name>notexists</name> @@ -186,44 +143,31 @@ </verify> </request> </test> - <test name='4b'> - <description>Shared calendar has invite property</description> - <request user="$userid2:" pswd="$pswd2:"> + <test name='5'> + <description>Original calendar unchanged</description> + <request> <method>PROPFIND</method> - <ruri>$sharedcalendar:/</ruri> + <ruri>$calendarhome1:/shared/</ruri> <header> <name>Depth</name> <value>0</value> </header> <data> <content-type>text/xml; charset=utf-8</content-type> - <filepath>Resource/CalDAV/sharing/calendars/read-write/5.xml</filepath> + <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath> </data> <verify> - <callback>propfindItems</callback> - <arg> - <name>okprops</name> - <value>{http://calendarserver.org/ns/}invite</value> - </arg> - </verify> - <verify> <callback>xmlElementMatch</callback> <arg> <name>exists</name> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}organizer</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}organizer/{DAV:}href[=$principaluri1:]</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}organizer/{http://calendarserver.org/ns/}common-name[=$username1:]</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{DAV:}href[=$cuaddrurn2:]</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{http://calendarserver.org/ns/}access/{http://calendarserver.org/ns/}read-write</value> - <value>$verify-property-prefix:/{http://calendarserver.org/ns/}invite/{http://calendarserver.org/ns/}user/{http://calendarserver.org/ns/}invite-accepted</value> + <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value> + <!--<value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}opaque</value>--> </arg> </verify> </request> </test> - <test name='5'> - <description>Original calendar unchanged</description> + <test name='5a'> + <description>Invite propfind returns sharees</description> <request> <method>PROPFIND</method> <ruri>$calendarhome1:/shared/</ruri> @@ -233,14 +177,14 @@ </header> <data> <content-type>text/xml; charset=utf-8</content-type> - <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath> + <filepath>Resource/CalDAV/sharing/calendars/read-write/5.xml</filepath> </data> <verify> <callback>xmlElementMatch</callback> <arg> <name>exists</name> - <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value> - <value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}opaque</value> + <value>$verify-property-prefix:/{http://owncloud.org/ns}invite/{http://owncloud.org/ns}user/{DAV:}href</value> + <value>$verify-property-prefix:/{http://owncloud.org/ns}invite/{http://owncloud.org/ns}user/{http://owncloud.org/ns}invite-accepted</value> </arg> </verify> </request> @@ -249,7 +193,7 @@ <description>Sharee creates event</description> <request user="$userid2:" pswd="$pswd2:"> <method>PUT</method> - <ruri>$sharedcalendar:/1.ics</ruri> + <ruri>$calendarhome1:/shared/1.ics</ruri> <data> <content-type>text/calendar; charset=utf-8</content-type> <filepath>Resource/CalDAV/sharing/calendars/read-write/5.ics</filepath> @@ -291,7 +235,7 @@ <description>Sharee sees changed event</description> <request user="$userid2:" pswd="$pswd2:"> <method>GET</method> - <ruri>$sharedcalendar:/1.ics</ruri> + <ruri>$calendarhome1:/shared/1.ics</ruri> <verify> <callback>calendarDataMatch</callback> <arg> @@ -319,7 +263,7 @@ <description>Sharee sees new event</description> <request user="$userid2:" pswd="$pswd2:"> <method>GET</method> - <ruri>$sharedcalendar:/2.ics</ruri> + <ruri>$calendarhome1:/shared/2.ics</ruri> <verify> <callback>calendarDataMatch</callback> <arg> @@ -333,7 +277,7 @@ <description>Sharee changes event</description> <request user="$userid2:" pswd="$pswd2:"> <method>PUT</method> - <ruri>$sharedcalendar:/2.ics</ruri> + <ruri>$calendarhome1:/shared/2.ics</ruri> <data> <content-type>text/calendar; charset=utf-8</content-type> <filepath>Resource/CalDAV/sharing/calendars/read-write/8.ics</filepath> @@ -357,8 +301,76 @@ </verify> </request> </test> + <test name='14'> + <description>Un-share by delete</description> + <request user="$userid2:" pswd="$pswd2:"> + <method>DELETE</method> + <ruri>$calendarhome2:/shared_shared_by_user01/</ruri> + <verify> + <callback>statusCode</callback> + </verify> + </request> + </test> + <test name='15'> + <description>Original calendar still exists</description> + <request> + <method>PROPFIND</method> + <ruri>$calendarhome1:/shared/</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath> + </data> + <verify> + <callback>xmlElementMatch</callback> + <arg> + <name>exists</name> + <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value> + <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value> + <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:caldav}calendar</value> + <!-- value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value --> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value> + <!-- value>$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp/{urn:ietf:params:xml:ns:caldav}transparent</value --> + </arg> + <arg> + <name>notexists</name> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value> + </arg> + </verify> + </request> + </test> + <test name='16'> + <description>Shared calendar no longer exists Depth:1</description> + <request user="$userid2:" pswd="$pswd2:"> + <method>PROPFIND</method> + <ruri>$calendarhome2:</ruri> + <header> + <name>Depth</name> + <value>1</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CalDAV/sharing/calendars/read-write/4.xml</filepath> + </data> + <verify> + <callback>xmlElementMatch</callback> + <arg> + <name>notexists</name> + <value>$multistatus-response-prefix:[^{DAV:}href=$calendarhome2:/shared_shared_by_user01/]</value> + </arg> + </verify> + </request> + </test> </test-suite> - + + <!-- <test-suite name='Default calendar cannot be shared calendar'> <test name='1'> <description>Set property on Inbox</description> @@ -560,7 +572,10 @@ </test> </test-suite> +--> + <end> + <!-- <request user="$useradmin:" pswd="$pswdadmin:"> <method>DELETEALL</method> <ruri>$notificationpath1:/</ruri> @@ -568,6 +583,7 @@ <ruri>$notificationpath3:/</ruri> <ruri>$notificationpath4:/</ruri> </request> + --> </end> </caldavtest> diff --git a/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml index 37b4941b9f1..84ee6265017 100644 --- a/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml +++ b/apps/dav/tests/travis/caldavtest/tests/CardDAV/sharing-addressbooks.xml @@ -238,7 +238,70 @@ </verify> </request> </test> - </test-suite> + <test name='14'> + <description>Un-share by delete</description> + <request user="$userid2:" pswd="$pswd2:"> + <method>DELETE</method> + <ruri>$addressbookhome2:/addressbook_shared_by_user01/</ruri> + <verify> + <callback>statusCode</callback> + </verify> + </request> + </test> + <test name='15'> + <description>Original address book still exists</description> + <request> + <method>PROPFIND</method> + <ruri>$addressbookhome1:/addressbook/</ruri> + <header> + <name>Depth</name> + <value>0</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath> + </data> + <verify> + <callback>xmlElementMatch</callback> + <arg> + <name>exists</name> + <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value> + <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value> + <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value> + </arg> + <arg> + <name>notexists</name> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value> + <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value> + </arg> + </verify> </request> + </test> + <test name='16'> + <description>Shared calendar no longer exists Depth:1</description> + <request user="$userid2:" pswd="$pswd2:"> + <method>PROPFIND</method> + <ruri>$addressbookhome2:</ruri> + <header> + <name>Depth</name> + <value>1</value> + </header> + <data> + <content-type>text/xml; charset=utf-8</content-type> + <filepath>Resource/CardDAV/sharing/read-write/4.xml</filepath> + </data> + <verify> + <callback>xmlElementMatch</callback> + <arg> + <name>notexists</name> + <value>$multistatus-response-prefix:[^{DAV:}href=$addressbookhome2:/addressbook_shared_by_user01/]</value> + </arg> + </verify> + </request> + </test> </test-suite> <end> </end> diff --git a/apps/dav/tests/unit/caldav/caldavbackendtest.php b/apps/dav/tests/unit/caldav/caldavbackendtest.php index 939fd36fba8..aece738166a 100644 --- a/apps/dav/tests/unit/caldav/caldavbackendtest.php +++ b/apps/dav/tests/unit/caldav/caldavbackendtest.php @@ -23,9 +23,12 @@ namespace Tests\Connector\Sabre; use DateTime; use DateTimeZone; use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CalDAV\Calendar; +use OCA\DAV\Connector\Sabre\Principal; use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet; use Sabre\DAV\PropPatch; use Sabre\DAV\Xml\Property\Href; +use Sabre\DAVACL\IACL; use Test\TestCase; /** @@ -40,14 +43,30 @@ class CalDavBackendTest extends TestCase { /** @var CalDavBackend */ private $backend; - const UNIT_TEST_USER = 'caldav-unit-test'; + /** @var Principal | \PHPUnit_Framework_MockObject_MockObject */ + private $principal; + const UNIT_TEST_USER = 'principals/users/caldav-unit-test'; + const UNIT_TEST_USER1 = 'principals/users/caldav-unit-test1'; + const UNIT_TEST_GROUP = 'principals/groups/caldav-unit-test-group'; public function setUp() { parent::setUp(); + $this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal') + ->disableOriginalConstructor() + ->setMethods(['getPrincipalByPath', 'getGroupMembership']) + ->getMock(); + $this->principal->method('getPrincipalByPath') + ->willReturn([ + 'uri' => 'principals/best-friend' + ]); + $this->principal->method('getGroupMembership') + ->withAnyParameters() + ->willReturn([self::UNIT_TEST_GROUP]); + $db = \OC::$server->getDatabaseConnection(); - $this->backend = new CalDavBackend($db); + $this->backend = new CalDavBackend($db, $this->principal); $this->tearDown(); } @@ -90,6 +109,87 @@ class CalDavBackendTest extends TestCase { $this->assertEquals(0, count($books)); } + public function providesSharingData() { + return [ + [true, true, true, false, [ + [ + 'href' => 'principal:' . self::UNIT_TEST_USER1, + 'readOnly' => false + ], + [ + 'href' => 'principal:' . self::UNIT_TEST_GROUP, + 'readOnly' => true + ] + ]], + [true, false, false, false, [ + [ + 'href' => 'principal:' . self::UNIT_TEST_USER1, + 'readOnly' => true + ], + ]], + + ]; + } + + /** + * @dataProvider providesSharingData + */ + public function testCalendarSharing($userCanRead, $userCanWrite, $groupCanRead, $groupCanWrite, $add) { + + $calendarId = $this->createTestCalendar(); + $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); + $this->assertEquals(1, count($books)); + $calendar = new Calendar($this->backend, $books[0]); + $this->backend->updateShares($calendar, $add, []); + $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER1); + $this->assertEquals(1, count($books)); + $calendar = new Calendar($this->backend, $books[0]); + $acl = $calendar->getACL(); + $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}read', $acl); + $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}write', $acl); + $this->assertAccess($userCanRead, self::UNIT_TEST_USER1, '{DAV:}read', $acl); + $this->assertAccess($userCanWrite, self::UNIT_TEST_USER1, '{DAV:}write', $acl); + $this->assertAccess($groupCanRead, self::UNIT_TEST_GROUP, '{DAV:}read', $acl); + $this->assertAccess($groupCanWrite, self::UNIT_TEST_GROUP, '{DAV:}write', $acl); + $this->assertEquals(self::UNIT_TEST_USER, $calendar->getOwner()); + + // test acls on the child + $uri = $this->getUniqueID('calobj'); + $calData = <<<'EOD' +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:ownCloud Calendar +BEGIN:VEVENT +CREATED;VALUE=DATE-TIME:20130910T125139Z +UID:47d15e3ec8 +LAST-MODIFIED;VALUE=DATE-TIME:20130910T125139Z +DTSTAMP;VALUE=DATE-TIME:20130910T125139Z +SUMMARY:Test Event +DTSTART;VALUE=DATE-TIME:20130912T130000Z +DTEND;VALUE=DATE-TIME:20130912T140000Z +CLASS:PUBLIC +END:VEVENT +END:VCALENDAR +EOD; + + $this->backend->createCalendarObject($calendarId, $uri, $calData); + + /** @var IACL $child */ + $child = $calendar->getChild($uri); + $acl = $child->getACL(); + $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}read', $acl); + $this->assertAcl(self::UNIT_TEST_USER, '{DAV:}write', $acl); + $this->assertAccess($userCanRead, self::UNIT_TEST_USER1, '{DAV:}read', $acl); + $this->assertAccess($userCanWrite, self::UNIT_TEST_USER1, '{DAV:}write', $acl); + $this->assertAccess($groupCanRead, self::UNIT_TEST_GROUP, '{DAV:}read', $acl); + $this->assertAccess($groupCanWrite, self::UNIT_TEST_GROUP, '{DAV:}write', $acl); + + // delete the address book + $this->backend->deleteCalendar($books[0]['id']); + $books = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); + $this->assertEquals(0, count($books)); + } + public function testCalendarObjectsOperations() { $calendarId = $this->createTestCalendar(); @@ -345,4 +445,32 @@ EOD; $sos = $this->backend->getSchedulingObjects(self::UNIT_TEST_USER); $this->assertEquals(0, count($sos)); } + + private function assertAcl($principal, $privilege, $acl) { + foreach($acl as $a) { + if ($a['principal'] === $principal && $a['privilege'] === $privilege) { + $this->assertTrue(true); + return; + } + } + $this->fail("ACL does not contain $principal / $privilege"); + } + + private function assertNotAcl($principal, $privilege, $acl) { + foreach($acl as $a) { + if ($a['principal'] === $principal && $a['privilege'] === $privilege) { + $this->fail("ACL contains $principal / $privilege"); + return; + } + } + $this->assertTrue(true); + } + + private function assertAccess($shouldHaveAcl, $principal, $privilege, $acl) { + if ($shouldHaveAcl) { + $this->assertAcl($principal, $privilege, $acl); + } else { + $this->assertNotAcl($principal, $privilege, $acl); + } + } } diff --git a/apps/dav/tests/unit/caldav/calendartest.php b/apps/dav/tests/unit/caldav/calendartest.php new file mode 100644 index 00000000000..93b3f4bff8c --- /dev/null +++ b/apps/dav/tests/unit/caldav/calendartest.php @@ -0,0 +1,64 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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 OCA\DAV\Tests\Unit\CalDAV; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\CalDAV\Calendar; +use Test\TestCase; + +class CalendarTest extends TestCase { + + public function testDelete() { + /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */ + $backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock(); + $backend->expects($this->once())->method('updateShares'); + $backend->method('getShares')->willReturn([ + ['href' => 'principal:user2'] + ]); + $calendarInfo = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + 'principaluri' => 'user2', + 'id' => 666 + ]; + $c = new Calendar($backend, $calendarInfo); + $c->delete(); + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + public function testDeleteFromGroup() { + /** @var \PHPUnit_Framework_MockObject_MockObject | CalDavBackend $backend */ + $backend = $this->getMockBuilder('OCA\DAV\CalDAV\CalDavBackend')->disableOriginalConstructor()->getMock(); + $backend->expects($this->never())->method('updateShares'); + $backend->method('getShares')->willReturn([ + ['href' => 'principal:group2'] + ]); + $calendarInfo = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + 'principaluri' => 'user2', + 'id' => 666 + ]; + $c = new Calendar($backend, $calendarInfo); + $c->delete(); + } +} diff --git a/apps/dav/tests/unit/carddav/addressbooktest.php b/apps/dav/tests/unit/carddav/addressbooktest.php new file mode 100644 index 00000000000..d714fc71679 --- /dev/null +++ b/apps/dav/tests/unit/carddav/addressbooktest.php @@ -0,0 +1,64 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @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 OCA\DAV\Tests\Unit\CardDAV; + +use OCA\DAV\CardDAV\AddressBook; +use OCA\DAV\CardDAV\CardDavBackend; +use Test\TestCase; + +class AddressBookTest extends TestCase { + + public function testDelete() { + /** @var \PHPUnit_Framework_MockObject_MockObject | CardDavBackend $backend */ + $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock(); + $backend->expects($this->once())->method('updateShares'); + $backend->method('getShares')->willReturn([ + ['href' => 'principal:user2'] + ]); + $calendarInfo = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + 'principaluri' => 'user2', + 'id' => 666 + ]; + $c = new AddressBook($backend, $calendarInfo); + $c->delete(); + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + public function testDeleteFromGroup() { + /** @var \PHPUnit_Framework_MockObject_MockObject | CardDavBackend $backend */ + $backend = $this->getMockBuilder('OCA\DAV\CardDAV\CardDavBackend')->disableOriginalConstructor()->getMock(); + $backend->expects($this->never())->method('updateShares'); + $backend->method('getShares')->willReturn([ + ['href' => 'principal:group2'] + ]); + $calendarInfo = [ + '{http://owncloud.org/ns}owner-principal' => 'user1', + 'principaluri' => 'user2', + 'id' => 666 + ]; + $c = new AddressBook($backend, $calendarInfo); + $c->delete(); + } +} diff --git a/apps/dav/tests/unit/carddav/carddavbackendtest.php b/apps/dav/tests/unit/carddav/carddavbackendtest.php index 0158330a194..86bc26b4c0d 100644 --- a/apps/dav/tests/unit/carddav/carddavbackendtest.php +++ b/apps/dav/tests/unit/carddav/carddavbackendtest.php @@ -27,7 +27,6 @@ use OCA\DAV\CardDAV\AddressBook; use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\Connector\Sabre\Principal; use OCP\IDBConnection; -use OCP\ILogger; use Sabre\DAV\PropPatch; use Sabre\VObject\Component\VCard; use Sabre\VObject\Property\Text; @@ -57,19 +56,24 @@ class CardDavBackendTest extends TestCase { /** @var string */ private $dbCardsPropertiesTable = 'cards_properties'; - const UNIT_TEST_USER = 'carddav-unit-test'; + const UNIT_TEST_USER = 'principals/users/carddav-unit-test'; + const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1'; + const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group'; public function setUp() { parent::setUp(); $this->principal = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal') ->disableOriginalConstructor() - ->setMethods(['getPrincipalByPath']) + ->setMethods(['getPrincipalByPath', 'getGroupMembership']) ->getMock(); $this->principal->method('getPrincipalByPath') ->willReturn([ 'uri' => 'principals/best-friend' ]); + $this->principal->method('getGroupMembership') + ->withAnyParameters() + ->willReturn([self::UNIT_TEST_GROUP]); $this->db = \OC::$server->getDatabaseConnection(); @@ -124,6 +128,29 @@ class CardDavBackendTest extends TestCase { $this->assertEquals(0, count($books)); } + public function testAddressBookSharing() { + + $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []); + $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER); + $this->assertEquals(1, count($books)); + $addressBook = new AddressBook($this->backend, $books[0]); + $this->backend->updateShares($addressBook, [ + [ + 'href' => 'principal:' . self::UNIT_TEST_USER1, + ], + [ + 'href' => 'principal:' . self::UNIT_TEST_GROUP, + ] + ], []); + $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1); + $this->assertEquals(1, count($books)); + + // delete the address book + $this->backend->deleteAddressBook($books[0]['id']); + $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER); + $this->assertEquals(0, count($books)); + } + public function testCardOperations() { /** @var CardDavBackend | \PHPUnit_Framework_MockObject_MockObject $backend */ diff --git a/apps/files_external/l10n/it.js b/apps/files_external/l10n/it.js index d9adaad833b..b6fad31111d 100644 --- a/apps/files_external/l10n/it.js +++ b/apps/files_external/l10n/it.js @@ -29,6 +29,7 @@ OC.L10N.register( "Error generating key pair" : "Errore durante la generazione della coppia di chiavi", "Enable encryption" : "Abilita cifratura", "Enable previews" : "Abilita le anteprime", + "Enable sharing" : "Abilita condivisione", "Check for changes" : "Controlla le modifiche", "Never" : "Mai", "Once every direct access" : "Una volta per ogni accesso diretto", diff --git a/apps/files_external/l10n/it.json b/apps/files_external/l10n/it.json index b228cd76604..e253c22b6b1 100644 --- a/apps/files_external/l10n/it.json +++ b/apps/files_external/l10n/it.json @@ -27,6 +27,7 @@ "Error generating key pair" : "Errore durante la generazione della coppia di chiavi", "Enable encryption" : "Abilita cifratura", "Enable previews" : "Abilita le anteprime", + "Enable sharing" : "Abilita condivisione", "Check for changes" : "Controlla le modifiche", "Never" : "Mai", "Once every direct access" : "Una volta per ogni accesso diretto", diff --git a/apps/files_external/l10n/pt_PT.js b/apps/files_external/l10n/pt_PT.js index b84c399e34d..ef75f504bcf 100644 --- a/apps/files_external/l10n/pt_PT.js +++ b/apps/files_external/l10n/pt_PT.js @@ -29,6 +29,7 @@ OC.L10N.register( "Error generating key pair" : "Erro ao gerar chave par", "Enable encryption" : "Ative a encriptação", "Enable previews" : "Ative as pré-visualizações", + "Enable sharing" : "Ativar partilha", "Check for changes" : "Verifique as suas alterações", "Never" : "Nunca", "Once every direct access" : "Uma vez em cada acesso direto", diff --git a/apps/files_external/l10n/pt_PT.json b/apps/files_external/l10n/pt_PT.json index ac65ca7744f..686802379ee 100644 --- a/apps/files_external/l10n/pt_PT.json +++ b/apps/files_external/l10n/pt_PT.json @@ -27,6 +27,7 @@ "Error generating key pair" : "Erro ao gerar chave par", "Enable encryption" : "Ative a encriptação", "Enable previews" : "Ative as pré-visualizações", + "Enable sharing" : "Ativar partilha", "Check for changes" : "Verifique as suas alterações", "Never" : "Nunca", "Once every direct access" : "Uma vez em cada acesso direto", diff --git a/core/css/systemtags.css b/core/css/systemtags.css index 2a02bc05ea7..588c76e1e3f 100644 --- a/core/css/systemtags.css +++ b/core/css/systemtags.css @@ -76,4 +76,10 @@ .systemtags-select2-container .select2-choices .select2-search-field input { line-height: 20px; } - +.systemtags-select2-dropdown .label { + width:85%; + display:-moz-inline-box; + display:inline-block; + overflow:hidden; + text-overflow:ellipsis; +} diff --git a/lib/private/comments/comment.php b/lib/private/comments/comment.php index 75964603f9f..36189d9523b 100644 --- a/lib/private/comments/comment.php +++ b/lib/private/comments/comment.php @@ -242,7 +242,7 @@ class Comment implements IComment { /** * sets (overwrites) the actor type and id * - * @param string $actorType e.g. 'user' + * @param string $actorType e.g. 'users' * @param string $actorId e.g. 'zombie234' * @return IComment * @since 9.0.0 @@ -328,7 +328,7 @@ class Comment implements IComment { /** * sets (overwrites) the object of the comment * - * @param string $objectType e.g. 'file' + * @param string $objectType e.g. 'files' * @param string $objectId e.g. '16435' * @return IComment * @since 9.0.0 diff --git a/lib/private/comments/manager.php b/lib/private/comments/manager.php index 28bd3b0916a..0cacc1cce71 100644 --- a/lib/private/comments/manager.php +++ b/lib/private/comments/manager.php @@ -384,7 +384,7 @@ class Manager implements ICommentsManager { * saved in the used data storage. Use save() after setting other fields * of the comment (e.g. message or verb). * - * @param string $actorType the actor type (e.g. 'user') + * @param string $actorType the actor type (e.g. 'users') * @param string $actorId a user id * @param string $objectType the object type the comment is attached to * @param string $objectId the object id the comment is attached to @@ -533,7 +533,7 @@ class Manager implements ICommentsManager { * removes references to specific actor (e.g. on user delete) of a comment. * The comment itself must not get lost/deleted. * - * @param string $actorType the actor type (e.g. 'user') + * @param string $actorType the actor type (e.g. 'users') * @param string $actorId a user id * @return boolean * @since 9.0.0 @@ -560,7 +560,7 @@ class Manager implements ICommentsManager { /** * deletes all comments made of a specific object (e.g. on file delete) * - * @param string $objectType the object type (e.g. 'file') + * @param string $objectType the object type (e.g. 'files') * @param string $objectId e.g. the file id * @return boolean * @since 9.0.0 diff --git a/lib/private/user/manager.php b/lib/private/user/manager.php index 86750dcd994..6798a7340c3 100644 --- a/lib/private/user/manager.php +++ b/lib/private/user/manager.php @@ -265,6 +265,10 @@ class Manager extends PublicEmitter implements IUserManager { if (trim($uid) == '') { throw new \Exception($l->t('A valid username must be provided')); } + // No whitespace at the beginning or at the end + if (strlen(trim($uid, "\t\n\r\0\x0B\xe2\x80\x8b")) !== strlen(trim($uid))) { + throw new \Exception($l->t('Username contains whitespace at the beginning or at the end')); + } // No empty password if (trim($password) == '') { throw new \Exception($l->t('A valid password must be provided')); diff --git a/lib/private/user/user.php b/lib/private/user/user.php index 5e556575118..516c1d443c6 100644 --- a/lib/private/user/user.php +++ b/lib/private/user/user.php @@ -210,7 +210,7 @@ class User implements IUser { // Delete the users entry in the storage table \OC\Files\Cache\Storage::remove('home::' . $this->uid); - \OC::$server->getCommentsManager()->deleteReferencesOfActor('user', $this->uid); + \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid); \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this); } diff --git a/lib/public/comments/icomment.php b/lib/public/comments/icomment.php index d97cfe3f1cc..e695b5193f2 100644 --- a/lib/public/comments/icomment.php +++ b/lib/public/comments/icomment.php @@ -161,7 +161,7 @@ interface IComment { /** * sets (overwrites) the actor type and id * - * @param string $actorType e.g. 'user' + * @param string $actorType e.g. 'users' * @param string $actorId e.g. 'zombie234' * @return IComment * @since 9.0.0 @@ -223,7 +223,7 @@ interface IComment { /** * sets (overwrites) the object of the comment * - * @param string $objectType e.g. 'file' + * @param string $objectType e.g. 'files' * @param string $objectId e.g. '16435' * @return IComment * @since 9.0.0 diff --git a/lib/public/comments/icommentsmanager.php b/lib/public/comments/icommentsmanager.php index f5b290bf8b2..46608ca8165 100644 --- a/lib/public/comments/icommentsmanager.php +++ b/lib/public/comments/icommentsmanager.php @@ -39,7 +39,7 @@ interface ICommentsManager { * * User interfaces shall show "Deleted user" as display name, if needed. */ - const DELETED_USER = 'deleted_user'; + const DELETED_USER = 'deleted_users'; /** * returns a comment instance @@ -127,7 +127,7 @@ interface ICommentsManager { * saved in the used data storage. Use save() after setting other fields * of the comment (e.g. message or verb). * - * @param string $actorType the actor type (e.g. 'user') + * @param string $actorType the actor type (e.g. 'users') * @param string $actorId a user id * @param string $objectType the object type the comment is attached to * @param string $objectId the object id the comment is attached to @@ -170,10 +170,10 @@ interface ICommentsManager { * removes references to specific actor (e.g. on user delete) of a comment. * The comment itself must not get lost/deleted. * - * A 'user' type actor (type and id) should get replaced by the + * A 'users' type actor (type and id) should get replaced by the * value of the DELETED_USER constant of this interface. * - * @param string $actorType the actor type (e.g. 'user') + * @param string $actorType the actor type (e.g. 'users') * @param string $actorId a user id * @return boolean * @since 9.0.0 @@ -183,7 +183,7 @@ interface ICommentsManager { /** * deletes all comments made of a specific object (e.g. on file delete) * - * @param string $objectType the object type (e.g. 'file') + * @param string $objectType the object type (e.g. 'files') * @param string $objectId e.g. the file id * @return boolean * @since 9.0.0 diff --git a/tests/lib/comments/comment.php b/tests/lib/comments/comment.php index 02adea8729e..e6f9c941c96 100644 --- a/tests/lib/comments/comment.php +++ b/tests/lib/comments/comment.php @@ -15,10 +15,10 @@ class Test_Comments_Comment extends TestCase $childrenCount = 6; $message = 'I like to comment comment'; $verb = 'comment'; - $actor = ['type' => 'user', 'id' => 'alice']; + $actor = ['type' => 'users', 'id' => 'alice']; $creationDT = new \DateTime(); $latestChildDT = new \DateTime('yesterday'); - $object = ['type' => 'file', 'id' => 'file64']; + $object = ['type' => 'files', 'id' => 'file64']; $comment ->setId($id) @@ -87,11 +87,11 @@ class Test_Comments_Comment extends TestCase public function roleSetterProvider() { return [ ['Actor', true, true], - ['Actor', 'user', true], + ['Actor', 'users', true], ['Actor', true, 'alice'], ['Actor', ' ', ' '], ['Object', true, true], - ['Object', 'file', true], + ['Object', 'files', true], ['Object', true, 'file64'], ['Object', ' ', ' '], ]; diff --git a/tests/lib/comments/manager.php b/tests/lib/comments/manager.php index a71f78f2818..c55f4728883 100644 --- a/tests/lib/comments/manager.php +++ b/tests/lib/comments/manager.php @@ -35,13 +35,13 @@ class Test_Comments_Manager extends TestCase 'parent_id' => $qb->createNamedParameter($parentId), 'topmost_parent_id' => $qb->createNamedParameter($topmostParentId), 'children_count' => $qb->createNamedParameter(2), - 'actor_type' => $qb->createNamedParameter('user'), + 'actor_type' => $qb->createNamedParameter('users'), 'actor_id' => $qb->createNamedParameter('alice'), 'message' => $qb->createNamedParameter('nice one'), 'verb' => $qb->createNamedParameter('comment'), 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'), 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'), - 'object_type' => $qb->createNamedParameter('file'), + 'object_type' => $qb->createNamedParameter('files'), 'object_id' => $qb->createNamedParameter('file64'), ]) ->execute(); @@ -83,13 +83,13 @@ class Test_Comments_Manager extends TestCase 'parent_id' => $qb->createNamedParameter('2'), 'topmost_parent_id' => $qb->createNamedParameter('1'), 'children_count' => $qb->createNamedParameter(2), - 'actor_type' => $qb->createNamedParameter('user'), + 'actor_type' => $qb->createNamedParameter('users'), 'actor_id' => $qb->createNamedParameter('alice'), 'message' => $qb->createNamedParameter('nice one'), 'verb' => $qb->createNamedParameter('comment'), 'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'), 'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'), - 'object_type' => $qb->createNamedParameter('file'), + 'object_type' => $qb->createNamedParameter('files'), 'object_id' => $qb->createNamedParameter('file64'), ]) ->execute(); @@ -102,11 +102,11 @@ class Test_Comments_Manager extends TestCase $this->assertSame($comment->getParentId(), '2'); $this->assertSame($comment->getTopmostParentId(), '1'); $this->assertSame($comment->getChildrenCount(), 2); - $this->assertSame($comment->getActorType(), 'user'); + $this->assertSame($comment->getActorType(), 'users'); $this->assertSame($comment->getActorId(), 'alice'); $this->assertSame($comment->getMessage(), 'nice one'); $this->assertSame($comment->getVerb(), 'comment'); - $this->assertSame($comment->getObjectType(), 'file'); + $this->assertSame($comment->getObjectType(), 'files'); $this->assertSame($comment->getObjectId(), 'file64'); $this->assertEquals($comment->getCreationDateTime(), $creationDT); $this->assertEquals($comment->getLatestChildDateTime(), $latestChildDT); @@ -207,7 +207,7 @@ class Test_Comments_Manager extends TestCase $this->addDatabaseEntry(0, 0); $manager = $this->getManager(); - $comments = $manager->getForObject('file', 'file64'); + $comments = $manager->getForObject('files', 'file64'); $this->assertTrue(is_array($comments)); $this->assertSame(count($comments), 1); @@ -227,7 +227,7 @@ class Test_Comments_Manager extends TestCase $manager = $this->getManager(); $offset = 0; do { - $comments = $manager->getForObject('file', 'file64', 3, $offset); + $comments = $manager->getForObject('files', 'file64', 3, $offset); $this->assertTrue(is_array($comments)); foreach($comments as $comment) { @@ -247,7 +247,7 @@ class Test_Comments_Manager extends TestCase $id2 = $this->addDatabaseEntry(2, 2, new \DateTime('-2 hours')); $manager = $this->getManager(); - $comments = $manager->getForObject('file', 'file64', 0, 0, new \DateTime('-4 hours')); + $comments = $manager->getForObject('files', 'file64', 0, 0, new \DateTime('-4 hours')); $this->assertSame(count($comments), 2); $this->assertSame($comments[0]->getId(), strval($id2)); @@ -266,7 +266,7 @@ class Test_Comments_Manager extends TestCase $manager = $this->getManager(); $offset = 0; do { - $comments = $manager->getForObject('file', 'file64', 3, $offset, new \DateTime('-4 hours')); + $comments = $manager->getForObject('files', 'file64', 3, $offset, new \DateTime('-4 hours')); $this->assertTrue(is_array($comments)); foreach($comments as $comment) { @@ -290,7 +290,7 @@ class Test_Comments_Manager extends TestCase $amount = $manager->getNumberOfCommentsForObject('untype', '00'); $this->assertSame($amount, 0); - $amount = $manager->getNumberOfCommentsForObject('file', 'file64'); + $amount = $manager->getNumberOfCommentsForObject('files', 'file64'); $this->assertSame($amount, 4); } @@ -357,8 +357,8 @@ class Test_Comments_Manager extends TestCase $manager = $this->getManager(); $comment = new \OC\Comments\Comment(); $comment - ->setActor('user', 'alice') - ->setObject('file', 'file64') + ->setActor('users', 'alice') + ->setObject('files', 'file64') ->setMessage('very beautiful, I am impressed!') ->setVerb('comment'); @@ -377,8 +377,8 @@ class Test_Comments_Manager extends TestCase $manager = $this->getManager(); $comment = new \OC\Comments\Comment(); $comment - ->setActor('user', 'alice') - ->setObject('file', 'file64') + ->setActor('users', 'alice') + ->setObject('files', 'file64') ->setMessage('very beautiful, I am impressed!') ->setVerb('comment'); @@ -398,8 +398,8 @@ class Test_Comments_Manager extends TestCase $manager = $this->getManager(); $comment = new \OC\Comments\Comment(); $comment - ->setActor('user', 'alice') - ->setObject('file', 'file64') + ->setActor('users', 'alice') + ->setObject('files', 'file64') ->setMessage('very beautiful, I am impressed!') ->setVerb('comment'); @@ -428,8 +428,8 @@ class Test_Comments_Manager extends TestCase for($i = 0; $i < 3; $i++) { $comment = new \OC\Comments\Comment(); $comment - ->setActor('user', 'alice') - ->setObject('file', 'file64') + ->setActor('users', 'alice') + ->setObject('files', 'file64') ->setParentId(strval($id)) ->setMessage('full ack') ->setVerb('comment') @@ -450,7 +450,7 @@ class Test_Comments_Manager extends TestCase [ ['', ''], [1, 'alice'], - ['user', 1], + ['users', 1], ]; } @@ -473,10 +473,10 @@ class Test_Comments_Manager extends TestCase // just to make sure they are really set, with correct actor data $comment = $manager->get(strval($ids[1])); - $this->assertSame($comment->getActorType(), 'user'); + $this->assertSame($comment->getActorType(), 'users'); $this->assertSame($comment->getActorId(), 'alice'); - $wasSuccessful = $manager->deleteReferencesOfActor('user', 'alice'); + $wasSuccessful = $manager->deleteReferencesOfActor('users', 'alice'); $this->assertTrue($wasSuccessful); foreach($ids as $id) { @@ -487,7 +487,7 @@ class Test_Comments_Manager extends TestCase // actor info is gone from DB, but when database interaction is alright, // we still expect to get true back - $wasSuccessful = $manager->deleteReferencesOfActor('user', 'alice'); + $wasSuccessful = $manager->deleteReferencesOfActor('users', 'alice'); $this->assertTrue($wasSuccessful); } @@ -496,7 +496,7 @@ class Test_Comments_Manager extends TestCase $this->assertTrue($user instanceof \OCP\IUser); $manager = \OC::$server->getCommentsManager(); - $comment = $manager->create('user', $user->getUID(), 'file', 'file64'); + $comment = $manager->create('users', $user->getUID(), 'files', 'file64'); $comment ->setMessage('Most important comment I ever left on the Internet.') ->setVerb('comment'); @@ -516,7 +516,7 @@ class Test_Comments_Manager extends TestCase [ ['', ''], [1, 'file64'], - ['file', 1], + ['files', 1], ]; } @@ -539,10 +539,10 @@ class Test_Comments_Manager extends TestCase // just to make sure they are really set, with correct actor data $comment = $manager->get(strval($ids[1])); - $this->assertSame($comment->getObjectType(), 'file'); + $this->assertSame($comment->getObjectType(), 'files'); $this->assertSame($comment->getObjectId(), 'file64'); - $wasSuccessful = $manager->deleteCommentsAtObject('file', 'file64'); + $wasSuccessful = $manager->deleteCommentsAtObject('files', 'file64'); $this->assertTrue($wasSuccessful); $verified = 0; @@ -557,7 +557,7 @@ class Test_Comments_Manager extends TestCase // actor info is gone from DB, but when database interaction is alright, // we still expect to get true back - $wasSuccessful = $manager->deleteCommentsAtObject('file', 'file64'); + $wasSuccessful = $manager->deleteCommentsAtObject('files', 'file64'); $this->assertTrue($wasSuccessful); } |