From f198e3e1ec613cb36b5676ef7e49d6bef59e63a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raimund=20Schl=C3=BC=C3=9Fler?= Date: Thu, 9 Jul 2020 22:39:03 +0200 Subject: [PATCH] Properly handle multiple categories properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Raimund Schlüßler --- src/models/task.js | 44 +++++++++++++++---- src/store/tasks.js | 4 +- .../vcalendar-categories-multiple.ics | 13 ++++++ .../vcalendars/vcalendar-categories-none.ics | 11 +++++ .../vcalendar-categories-single.ics | 12 +++++ tests/javascript/unit/models/task.spec.js | 34 ++++++++++++++ 6 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 tests/assets/ics/vcalendars/vcalendar-categories-multiple.ics create mode 100644 tests/assets/ics/vcalendars/vcalendar-categories-none.ics create mode 100644 tests/assets/ics/vcalendars/vcalendar-categories-single.ics diff --git a/src/models/task.js b/src/models/task.js index 85e89ef6..90beec63 100644 --- a/src/models/task.js +++ b/src/models/task.js @@ -103,8 +103,7 @@ export default class Task { const d = due || start this._allDay = d !== null && d.isDate this._loaded = false - const categories = this.vtodo.getFirstProperty('categories') - this._categories = categories ? categories.getValues() : [] + this._categories = this.getCategories() this._modified = this.vtodo.getFirstPropertyValue('last-modified') this._modifiedMoment = moment(this._modified, 'YYYYMMDDTHHmmss') this._created = this.vtodo.getFirstPropertyValue('created') @@ -508,6 +507,16 @@ export default class Task { return this._categories } + getCategories() { + let categories = [] + for (const cats of this.vtodo.getAllProperties('categories')) { + if (cats) { + categories = categories.concat(cats.getValues()) + } + } + return categories + } + /** * Set the categories * @@ -515,21 +524,38 @@ export default class Task { * @memberof Task */ set categories(newCategories) { - let categories = this.vtodo.getFirstProperty('categories') if (newCategories.length > 0) { - if (categories) { - categories.setValues(newCategories) - } else { + let categories = this.vtodo.getAllProperties('categories') + // If there are no categories set yet, just set them + if (categories.length < 1) { const prop = new ICAL.Property('categories') prop.setValues(newCategories) categories = this.vtodo.addProperty(prop) + // If there is only one categories property, overwrite it + } else if (categories.length < 2) { + categories[0].setValues(newCategories) + // If there are multiple categories properties, we have to iterate over all + // and remove unwanted categories and add new ones + } else { + const toRemove = this._categories.filter(c => !newCategories.includes(c)) + const toAdd = newCategories.filter(c => !this._categories.includes(c)) + // Remove all unwanted categories + for (const cats of categories) { + const c = cats.getValues().filter(c => !toRemove.includes(c)) + if (c.length) { + cats.setValues(c) + } else { + this.vtodo.removeProperty(cats) + } + } + // Add new categories + categories[0].setValues(categories[0].getValues().concat(toAdd)) } } else { - this.vtodo.removeProperty('categories') + this.vtodo.removeAllProperties('categories') } this.updateLastModified() - categories = this.vtodo.getFirstProperty('categories') - this._categories = categories ? categories.getValues() : [] + this._categories = this.getCategories() } updateLastModified() { diff --git a/src/store/tasks.js b/src/store/tasks.js index 99d8a079..6a7f3a4e 100644 --- a/src/store/tasks.js +++ b/src/store/tasks.js @@ -424,9 +424,7 @@ const mutations = { * @param {String} category The category to add */ addCategory(state, { task, category }) { - const categories = task.categories - categories.push(category) - Vue.set(task, 'categories', categories) + Vue.set(task, 'categories', task.categories.concat([category])) }, /** diff --git a/tests/assets/ics/vcalendars/vcalendar-categories-multiple.ics b/tests/assets/ics/vcalendars/vcalendar-categories-multiple.ics new file mode 100644 index 00000000..3350b5cc --- /dev/null +++ b/tests/assets/ics/vcalendars/vcalendar-categories-multiple.ics @@ -0,0 +1,13 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Nextcloud Tasks 0.11.3 +BEGIN:VTODO +CREATED:20181119T183919 +DTSTAMP:20190918T095816 +LAST-MODIFIED:20190918T095816 +UID:pwen9kz28g +CATEGORIES:cat1,cat2 +CATEGORIES:cat3 +SUMMARY:Test 1 +END:VTODO +END:VCALENDAR diff --git a/tests/assets/ics/vcalendars/vcalendar-categories-none.ics b/tests/assets/ics/vcalendars/vcalendar-categories-none.ics new file mode 100644 index 00000000..80114c7b --- /dev/null +++ b/tests/assets/ics/vcalendars/vcalendar-categories-none.ics @@ -0,0 +1,11 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Nextcloud Tasks 0.11.3 +BEGIN:VTODO +CREATED:20181119T183919 +DTSTAMP:20190918T095816 +LAST-MODIFIED:20190918T095816 +UID:pwen9kz29f +SUMMARY:Test 1 +END:VTODO +END:VCALENDAR diff --git a/tests/assets/ics/vcalendars/vcalendar-categories-single.ics b/tests/assets/ics/vcalendars/vcalendar-categories-single.ics new file mode 100644 index 00000000..d59a1859 --- /dev/null +++ b/tests/assets/ics/vcalendars/vcalendar-categories-single.ics @@ -0,0 +1,12 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Nextcloud Tasks 0.11.3 +BEGIN:VTODO +CREATED:20181119T183919 +DTSTAMP:20190918T095816 +LAST-MODIFIED:20190918T095816 +UID:pwen9kz31g +CATEGORIES:cat1,cat2 +SUMMARY:Test 1 +END:VTODO +END:VCALENDAR diff --git a/tests/javascript/unit/models/task.spec.js b/tests/javascript/unit/models/task.spec.js index fb7e5ad4..bfd40942 100644 --- a/tests/javascript/unit/models/task.spec.js +++ b/tests/javascript/unit/models/task.spec.js @@ -161,4 +161,38 @@ describe('task', () => { task.sortOrder = 2 expect(task.sortOrder).toEqual(2) }) + + it('Should show all categories from multiple properties.', () => { + const task = new Task(loadICS('vcalendars/vcalendar-categories-multiple'), {}) + expect(task.categories.length).toEqual(3) + }) + + it('Should properly add and remove categories from multiple properties.', () => { + const task = new Task(loadICS('vcalendars/vcalendar-categories-multiple'), {}) + expect(task.categories.length).toEqual(3) + expect(task.categories).toEqual(['cat1', 'cat2', 'cat3']) + task.categories = ['cat1', 'cat5'] + expect(task.categories).toEqual(['cat1', 'cat5']) + task.categories = [] + expect(task.categories.length).toEqual(0) + }) + + it('Should properly add and remove categories from a single property.', () => { + const task = new Task(loadICS('vcalendars/vcalendar-categories-single'), {}) + expect(task.categories.length).toEqual(2) + expect(task.categories).toEqual(['cat1', 'cat2']) + task.categories = ['cat1', 'cat3'] + expect(task.categories).toEqual(['cat1', 'cat3']) + task.categories = [] + expect(task.categories.length).toEqual(0) + }) + + it('Should properly add and remove categories if none are set yet.', () => { + const task = new Task(loadICS('vcalendars/vcalendar-categories-none'), {}) + expect(task.categories.length).toEqual(0) + task.categories = ['cat1', 'cat3'] + expect(task.categories).toEqual(['cat1', 'cat3']) + task.categories = [] + expect(task.categories.length).toEqual(0) + }) })