]> source.dussan.org Git - nextcloud-server.git/commitdiff
Reset comments read marker after loading comments
authorVincent Petry <pvince81@owncloud.com>
Wed, 3 Feb 2016 15:18:14 +0000 (16:18 +0100)
committerVincent Petry <pvince81@owncloud.com>
Wed, 3 Feb 2016 15:18:14 +0000 (16:18 +0100)
apps/comments/appinfo/app.php
apps/comments/js/commentcollection.js
apps/comments/js/commentmodel.js
apps/comments/js/commentstabview.js
apps/comments/js/commentsummarymodel.js [new file with mode: 0644]
apps/comments/tests/js/commentscollectionSpec.js
apps/comments/tests/js/commentstabviewSpec.js
tests/karma.config.js

index c6f36567c51b9bd6575790a97bb0ac794e71cbf8..a1eb4f6899df6c493e211cb3b6ed1e784476a0ea 100644 (file)
@@ -27,6 +27,7 @@ $eventDispatcher->addListener(
                \OCP\Util::addScript('comments', 'app');
                \OCP\Util::addScript('comments', 'commentmodel');
                \OCP\Util::addScript('comments', 'commentcollection');
+               \OCP\Util::addScript('comments', 'commentsummarymodel');
                \OCP\Util::addScript('comments', 'commentstabview');
                \OCP\Util::addScript('comments', 'filesplugin');
                \OCP\Util::addStyle('comments', 'comments');
index d10e5e008656d2585811ed4a0948f61075da1d4d..a15039cf48475e0838dbd542fb8c73687d98a93e 100644 (file)
@@ -10,8 +10,6 @@
 
 (function(OC, OCA) {
 
-       var NS_OWNCLOUD = 'http://owncloud.org/ns';
-
        /**
         * @class OCA.Comments.CommentCollection
         * @classdesc
 
                model: OCA.Comments.CommentModel,
 
+               /**
+                * Object type
+                *
+                * @type string
+                */
                _objectType: 'files',
+
+               /**
+                * Object id
+                *
+                * @type string
+                */
                _objectId: null,
 
+               /**
+                * True if there are no more page results left to fetch
+                *
+                * @type bool
+                */
                _endReached: false,
+
+               /**
+                * Number of comments to fetch per page
+                *
+                * @type int
+                */
                _limit : 20,
 
+               /**
+                * Initializes the collection
+                *
+                * @param {string} [options.objectType] object type
+                * @param {string} [options.objectId] object id
+                */
                initialize: function(models, options) {
                        options = options || {};
                        if (options.objectType) {
@@ -58,6 +84,7 @@
 
                reset: function() {
                        this._endReached = false;
+                       this._summaryModel = null;
                        return OC.Backbone.Collection.prototype.reset.apply(this, arguments);
                },
 
                        var success = options.success;
                        options = _.extend({
                                remove: false,
+                               parse: true,
                                data: body,
                                davProperties: CommentCollection.prototype.model.prototype.davProperties,
                                success: function(resp) {
                        }, options);
 
                        return this.sync('REPORT', this, options);
+               },
+
+               /**
+                * Returns the matching summary model
+                *
+                * @return {OCA.Comments.CommentSummaryModel} summary model
+                */
+               getSummaryModel: function() {
+                       if (!this._summaryModel) {
+                               this._summaryModel = new OCA.Comments.CommentSummaryModel({
+                                       id: this._objectId,
+                                       objectType: this._objectType
+                               });
+                       }
+                       return this._summaryModel;
+               },
+
+               /**
+                * Updates the read marker for this comment thread
+                *
+                * @param {Date} [date] optional date, defaults to now
+                * @param {Object} [options] backbone options
+                */
+               updateReadMarker: function(date, options) {
+                       options = options || {};
+
+                       return this.getSummaryModel().save({
+                               readMarker: (date || new Date()).toUTCString()
+                       }, options);
                }
        });
 
index b945f71fdd2af6c340767eca6591bbb8b5eabea0..ba04fd61de3f19f242741461b758a3bb0a624406 100644 (file)
                        'actorDisplayName': '{' + NS_OWNCLOUD + '}actorDisplayName',
                        'creationDateTime': '{' + NS_OWNCLOUD + '}creationDateTime',
                        'objectType': '{' + NS_OWNCLOUD + '}objectType',
-                       'objectId': '{' + NS_OWNCLOUD + '}objectId'
+                       'objectId': '{' + NS_OWNCLOUD + '}objectId',
+                       'isUnread': '{' + NS_OWNCLOUD + '}isUnread'
                },
 
                parse: function(data) {
-                       // TODO: parse non-string values
+                       data.isUnread = (data.isUnread === 'true');
                        return data;
                }
        });
index 463ac2d76eff10d8cecfa1891f2e5ea729b9ebaa..188d8c5943cd560471c06112844670e4d761dd8f 100644 (file)
@@ -31,7 +31,7 @@
                '<div class="loading hidden" style="height: 50px"></div>';
 
        var COMMENT_TEMPLATE =
-               '<li class="comment">' +
+               '<li class="comment{{#if isUnread}} unread{{/if}}" data-id="{{id}}">' +
                '    <div class="authorRow">' +
                '        {{#if avatarEnabled}}' +
                '        <div class="avatar" data-username="{{actorId}}"> </div>' +
 
                setFileInfo: function(fileInfo) {
                        if (fileInfo) {
+                               this.model = fileInfo;
                                this.render();
                                this.collection.setObjectId(fileInfo.id);
                                // reset to first page
                                this.collection.reset([], {silent: true});
                                this.nextPage();
                        } else {
+                               this.model = null;
                                this.render();
                                this.collection.reset();
                        }
                        this.$el.find('.showMore').addClass('hidden');
                },
 
-               _onEndRequest: function() {
+               _onEndRequest: function(type) {
+                       var fileInfoModel = this.model;
                        this._toggleLoading(false);
                        this.$el.find('.empty').toggleClass('hidden', !!this.collection.length);
                        this.$el.find('.showMore').toggleClass('hidden', !this.collection.hasMoreResults());
+
+                       if (type !== 'REPORT') {
+                               return;
+                       }
+
+                       // find first unread comment
+                       var firstUnreadComment = this.collection.findWhere({isUnread: true});
+                       if (firstUnreadComment) {
+                               // update read marker
+                               this.collection.updateReadMarker(
+                                       null,
+                                       {
+                                               success: function() {
+                                                       fileInfoModel.set('commentsUnread', 0);
+                                               }
+                                       }
+                               );
+                       }
                },
 
                _onAddModel: function(model, collection, options) {
                                actorType: 'users',
                                verb: 'comment',
                                message: $textArea.val(),
-                               creationDateTime: (new Date()).getTime()
+                               creationDateTime: (new Date()).toUTCString()
                        }, {
                                at: 0,
                                success: function() {
diff --git a/apps/comments/js/commentsummarymodel.js b/apps/comments/js/commentsummarymodel.js
new file mode 100644 (file)
index 0000000..d405315
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC, OCA) {
+       var NS_OWNCLOUD = 'http://owncloud.org/ns';
+       /**
+        * @class OCA.Comments.CommentSummaryModel
+        * @classdesc
+        *
+        * Model containing summary information related to comments
+        * like the read marker. 
+        *
+        */
+       var CommentSummaryModel = OC.Backbone.Model.extend(
+               /** @lends OCA.Comments.CommentSummaryModel.prototype */ {
+               sync: OC.Backbone.davSync,
+
+               /**
+                * Object type
+                *
+                * @type string
+                */
+               _objectType: 'files',
+
+               /**
+                * Object id
+                *
+                * @type string
+                */
+               _objectId: null,
+
+               davProperties: {
+                       'readMarker': '{' + NS_OWNCLOUD + '}readMarker'
+               },
+
+               /**
+                * Initializes the summary model
+                *
+                * @param {string} [options.objectType] object type
+                * @param {string} [options.objectId] object id
+                */
+               initialize: function(attrs, options) {
+                       options = options || {};
+                       if (options.objectType) {
+                               this._objectType = options.objectType;
+                       }
+               },
+
+               url: function() {
+                       return OC.linkToRemote('dav') + '/comments/' +
+                               encodeURIComponent(this._objectType) + '/' +
+                               encodeURIComponent(this.id) + '/';
+               }
+       });
+
+       OCA.Comments.CommentSummaryModel = CommentSummaryModel;
+})(OC, OCA);
+
index 0dc68cc167c6e82d0cb6fc6fe909b0114dfbacde..2f41a272f6762fb8a3504a5505fc8743cdca4daa 100644 (file)
@@ -100,5 +100,49 @@ describe('OCA.Comments.CommentCollection', function() {
 
                expect(collection.hasMoreResults()).toEqual(true);
        });
+       describe('resetting read marker', function() {
+               var updateStub;
+               var clock;
+
+               beforeEach(function() {
+                       updateStub = sinon.stub(OCA.Comments.CommentSummaryModel.prototype, 'save');
+                       clock = sinon.useFakeTimers(Date.UTC(2016, 1, 3, 10, 5, 9));
+               });
+               afterEach(function() { 
+                       updateStub.restore();
+                       clock.restore();
+               });
+               
+               it('resets read marker to the default date', function() {
+                       var successStub = sinon.stub();
+                       collection.updateReadMarker(null, {
+                               success: successStub
+                       });
+
+                       expect(updateStub.calledOnce).toEqual(true);
+                       expect(updateStub.lastCall.args[0]).toEqual({
+                               readMarker: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
+                       });
+
+                       updateStub.yieldTo('success');
+
+                       expect(successStub.calledOnce).toEqual(true);
+               });
+               it('resets read marker to the given date', function() {
+                       var successStub = sinon.stub();
+                       collection.updateReadMarker(new Date(Date.UTC(2016, 1, 2, 3, 4, 5)), {
+                               success: successStub
+                       });
+
+                       expect(updateStub.calledOnce).toEqual(true);
+                       expect(updateStub.lastCall.args[0]).toEqual({
+                               readMarker: new Date(Date.UTC(2016, 1, 2, 3, 4, 5)).toUTCString()
+                       });
+
+                       updateStub.yieldTo('success');
+
+                       expect(successStub.calledOnce).toEqual(true);
+               });
+       });
 });
 
index 0fb5eec0653611d14080c4a801f22a21a3498276..432fa5ddc4c9b44ed15ef004ca06822571bf9190 100644 (file)
@@ -48,7 +48,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
                        objectType: 'files',
                        objectId: 5,
                        message: 'First',
-                       creationDateTime: Date.UTC(2016, 1, 3, 10, 5, 0)
+                       creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 0)).toUTCString()
                });
                var comment2 = new OCA.Comments.CommentModel({
                        id: 2,
@@ -58,7 +58,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
                        objectType: 'files',
                        objectId: 5,
                        message: 'Second\nNewline',
-                       creationDateTime: Date.UTC(2016, 1, 3, 10, 0, 0)
+                       creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 0, 0)).toUTCString()
                });
 
                testComments = [comment1, comment2];
@@ -142,7 +142,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
                                objectType: 'files',
                                objectId: 5,
                                message: 'Third',
-                               creationDateTime: Date.UTC(2016, 1, 3, 5, 0, 0)
+                               creationDateTime: new Date(Date.UTC(2016, 1, 3, 5, 0, 0)).toUTCString()
                        });
 
                        view.collection.add(comment3);
@@ -184,7 +184,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
                                actorType: 'users',
                                verb: 'comment',
                                message: 'New message',
-                               creationDateTime: Date.UTC(2016, 1, 3, 10, 5, 9)
+                               creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
                        });
                });
                it('does not create a comment if the field is empty', function() {
@@ -195,4 +195,38 @@ describe('OCA.Comments.CommentsTabView tests', function() {
                });
 
        });
+       describe('read marker', function() {
+               var updateMarkerStub;
+
+               beforeEach(function() {
+                       updateMarkerStub = sinon.stub(OCA.Comments.CommentCollection.prototype, 'updateReadMarker');
+               });
+               afterEach(function() { 
+                       updateMarkerStub.restore();
+               });
+
+               it('resets the read marker after REPORT', function() {
+                       testComments[0].set('isUnread', true, {silent: true});
+                       testComments[1].set('isUnread', true, {silent: true});
+                       view.collection.set(testComments);
+                       view.collection.trigger('sync', 'REPORT');
+
+                       expect(updateMarkerStub.calledOnce).toEqual(true);
+                       expect(updateMarkerStub.lastCall.args[0]).toBeFalsy();
+               });
+               it('does not reset the read marker if there was no unread comments', function() {
+                       view.collection.set(testComments);
+                       view.collection.trigger('sync', 'REPORT');
+
+                       expect(updateMarkerStub.notCalled).toEqual(true);
+               });
+               it('does not reset the read marker when posting comments', function() {
+                       testComments[0].set('isUnread', true, {silent: true});
+                       testComments[1].set('isUnread', true, {silent: true});
+                       view.collection.set(testComments);
+                       view.collection.trigger('sync', 'POST');
+
+                       expect(updateMarkerStub.notCalled).toEqual(true);
+               });
+       });
 });
index fddcfb319ebcb432b189f176fd28ccfe2eeaccfc..2b569fb75848efa2d7426068db225f4031fba0e3 100644 (file)
@@ -89,6 +89,7 @@ module.exports = function(config) {
                                        'apps/comments/js/app.js',
                                        'apps/comments/js/commentmodel.js',
                                        'apps/comments/js/commentcollection.js',
+                                       'apps/comments/js/commentsummarymodel.js',
                                        'apps/comments/js/commentstabview.js',
                                        'apps/comments/js/filesplugin.js'
                                ],