From c5208f0ef62550468bf9571b87594bdfe5c51f77 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sun, 1 Mar 2020 22:21:53 +0100 Subject: [PATCH] fix tags --- test/api/unit/models/tag.test.js | 19 +++++++++++++++++++ test/api/unit/models/user.test.js | 25 +++++++++++++++++++++++++ website/server/models/tag.js | 15 +++++++++++++++ website/server/models/user/hooks.js | 8 ++++++++ 4 files changed, 67 insertions(+) create mode 100644 test/api/unit/models/tag.test.js diff --git a/test/api/unit/models/tag.test.js b/test/api/unit/models/tag.test.js new file mode 100644 index 0000000000..1585dd11ad --- /dev/null +++ b/test/api/unit/models/tag.test.js @@ -0,0 +1,19 @@ +import { model as Tag } from '../../../../website/server/models/tag'; + +describe('Tag Model', () => { + context('cleanupCorruptData', () => { + it('converts an array of tags to a safe version', () => { + const tags = [ + null, // invalid, not an object + { name: '123' }, // invalid, no id + { id: '123' }, // invalid, no name + new Tag({ name: 'ABC', id: 123 }), // valid + ]; + + const safetags = Tag.cleanupCorruptData(tags); + expect(safetags.length).to.equal(1); + expect(safetags[0].name).to.equal('ABC'); + expect(safetags[0].id).to.equal('123'); + }); + }); +}); diff --git a/test/api/unit/models/user.test.js b/test/api/unit/models/user.test.js index 9425fee275..fd2a3f4061 100644 --- a/test/api/unit/models/user.test.js +++ b/test/api/unit/models/user.test.js @@ -182,6 +182,31 @@ describe('User Model', () => { }); context('post init', () => { + it('removes invalid tags when loading the user', async () => { + let user = new User(); + await user.save(); + await user.update({ + $set: { + tags: [ + null, // invalid, not an object + // { name: '123' }, // invalid, no id - generated automatically + { id: '123' }, // invalid, no name + { name: 'ABC', id: '1234' }, // valid + ], + }, + }).exec(); + + user = await User.findById(user._id).exec(); + + const userToJSON = user.toJSON(); + console.log(userToJSON.tags); + expect(userToJSON.tags.length).to.equal(1); + + expect(userToJSON.tags[0]).to.have.all.keys(['id', 'name']); + expect(userToJSON.tags[0].id).to.equal('1234'); + expect(userToJSON.tags[0].name).to.equal('ABC'); + }); + it('removes invalid push devices when loading the user', async () => { let user = new User(); await user.save(); diff --git a/website/server/models/tag.js b/website/server/models/tag.js index 1fa8bc59a7..94afd95bd8 100644 --- a/website/server/models/tag.js +++ b/website/server/models/tag.js @@ -33,4 +33,19 @@ schema.statics.sanitizeUpdate = function sanitizeUpdate (updateObj) { return this.sanitize(updateObj, noUpdate); }; +/** + * Remove invalid data from an array of tags. + * Fix for https://github.com/HabitRPG/habitica/issues/10688 + * Called by user's post init hook (models/user/hooks.js) + */ +schema.statics.cleanupCorruptData = function cleanupCorruptTagsData (tags) { + if (!tags) return tags; + + return tags.filter(tag => { + // Exclude tags with a nullish value or no id + if (!tag || !tag.id || !tag.name) return false; + return true; + }); +}; + export const model = mongoose.model('Tag', schema); diff --git a/website/server/models/user/hooks.js b/website/server/models/user/hooks.js index 2d8dcd9e78..63aa42ed57 100644 --- a/website/server/models/user/hooks.js +++ b/website/server/models/user/hooks.js @@ -9,6 +9,9 @@ import { import { model as PushDevice, } from '../pushDevice'; +import { + model as Tag, +} from '../tag'; import { // eslint-disable-line import/no-cycle userActivityWebhook, } from '../../libs/webhook'; @@ -198,6 +201,11 @@ schema.post('init', function postInitUser () { this.pushDevices = PushDevice.cleanupCorruptData(this.pushDevices); } + // Make sure tags are loaded + if (this.isDirectSelected('tags')) { + this.tags = Tag.cleanupCorruptData(this.tags); + } + return true; });