diff --git a/test/api/v3/integration/user/GET-user_anonymized.test.js b/test/api/v3/integration/user/GET-user_anonymized.test.js new file mode 100644 index 0000000000..bbcaaf6249 --- /dev/null +++ b/test/api/v3/integration/user/GET-user_anonymized.test.js @@ -0,0 +1,90 @@ +import { + generateUser, + generateHabit, + generateDaily, + generateReward, +} from '../../../../helpers/api-integration/v3'; +import common from '../../../../../common'; +import { v4 as generateUUID } from 'uuid'; + +describe('GET /user/anonymized', () => { + let user; + let endpoint = '/user/anonymized'; + + before(async () => { + user = await generateUser(); + await user.update({ newMessages: ['some', 'new', 'messages'], profile: 'profile', 'purchased.plan': 'purchased plan', + contributor: 'contributor', invitations: 'invitations', 'items.special.nyeReceived': 'some', 'items.special.valentineReceived': 'some', + webhooks: 'some', 'achievements.challenges': 'some', + 'inbox.messages': [{ text: 'some text' }], + tags: [{ name: 'some name', challenge: 'some challenge' }], + }); + + await generateHabit({ userId: user._id }); + await generateHabit({ userId: user._id, text: generateUUID() }); + let daily = await generateDaily({ userId: user._id, checklist: [{ completed: false, text: 'this-text' }] }); + expect(daily.checklist[0].text.substr(0, 5)).to.not.eql('item '); + await generateReward({ userId: user._id, text: 'some text 4' }); + + expect(user.newMessages).to.exist; + expect(user.profile).to.exist; + expect(user.purchased.plan).to.exist; + expect(user.contributor).to.exist; + expect(user.invitations).to.exist; + expect(user.items.special.nyeReceived).to.exist; + expect(user.items.special.valentineReceived).to.exist; + expect(user.webhooks).to.exist; + expect(user.achievements.challenges).to.exist; + expect(user.inbox.messages[0].text).to.exist; + expect(user.inbox.messages[0].text).to.not.eql('inbox message text'); + expect(user.tags[0].name).to.exist; + expect(user.tags[0].name).to.not.eql('tag'); + expect(user.tags[0].challenge).to.not.eql('challenge'); + }); + + it('returns the authenticated user', async () => { + let returnedUser = await user.get(endpoint); + returnedUser = returnedUser.user; + expect(returnedUser._id).to.equal(user._id); + }); + + it('does not return private paths (and apiToken)', async () => { + let returnedUser = await user.get(endpoint); + let tasks2 = returnedUser.tasks; + returnedUser = returnedUser.user; + expect(returnedUser.auth.local).to.not.exist; + expect(returnedUser.apiToken).to.not.exist; + expect(returnedUser.stats.maxHealth).to.eql(common.maxHealth); + expect(returnedUser.stats.toNextLevel).to.eql(common.tnl(user.stats.lvl)); + expect(returnedUser.stats.maxMP).to.eql(30); // TODO why 30? + expect(returnedUser.newMessages).to.not.exist; + expect(returnedUser.profile).to.not.exist; + expect(returnedUser.purchased.plan).to.not.exist; + expect(returnedUser.contributor).to.not.exist; + expect(returnedUser.invitations).to.not.exist; + expect(returnedUser.items.special.nyeReceived).to.not.exist; + expect(returnedUser.items.special.valentineReceived).to.not.exist; + expect(returnedUser.webhooks).to.not.exist; + expect(returnedUser.achievements.challenges).to.not.exist; + _.forEach(returnedUser.inbox.messages, (msg) => { + expect(msg.text).to.eql('inbox message text'); + }); + _.forEach(returnedUser.tags, (tag) => { + expect(tag.name).to.eql('tag'); + expect(tag.challenge).to.eql('challenge'); + }); + // tasks + expect(tasks2).to.exist; + expect(tasks2.length).to.eql(5); // +1 because generateUser() assigns one todo + expect(tasks2[0].checklist).to.exist; + _.forEach(tasks2, (task) => { + expect(task.text).to.eql('task text'); + expect(task.notes).to.eql('task notes'); + if (task.checklist) { + _.forEach(task.checklist, (c) => { + expect(c.text.substr(0, 5)).to.eql('item '); + }); + } + }); + }); +}); diff --git a/test/helpers/api-integration/v3/object-generators.js b/test/helpers/api-integration/v3/object-generators.js index edd27f30ba..42de6d243c 100644 --- a/test/helpers/api-integration/v3/object-generators.js +++ b/test/helpers/api-integration/v3/object-generators.js @@ -5,6 +5,7 @@ import Q from 'q'; import { v4 as generateUUID } from 'uuid'; import { ApiUser, ApiGroup, ApiChallenge } from '../api-classes'; import { requester } from '../requester'; +import * as Tasks from '../../../../website/src/models/task'; // Creates a new user and returns it // If you need the user to have specific requirements, @@ -32,6 +33,27 @@ export async function generateUser (update = {}) { return apiUser; } +export async function generateHabit (update = {}) { + let type = 'habit'; + let task = new Tasks[type](update); + await task.save({ validateBeforeSave: false }); + return task; +} + +export async function generateDaily (update = {}) { + let type = 'daily'; + let task = new Tasks[type](update); + await task.save({ validateBeforeSave: false }); + return task; +} + +export async function generateReward (update = {}) { + let type = 'reward'; + let task = new Tasks[type](update); + await task.save({ validateBeforeSave: false }); + return task; +} + // Generates a new group. Requires a user object, which // will will become the groups leader. Takes a details argument // for the initial group creation and an update argument which diff --git a/website/src/controllers/api-v3/user.js b/website/src/controllers/api-v3/user.js index 6d26304944..fdba009372 100644 --- a/website/src/controllers/api-v3/user.js +++ b/website/src/controllers/api-v3/user.js @@ -98,6 +98,73 @@ api.deleteUser = { }, }; +function _cleanChecklist (task) { + _.forEach(task.checklist, (c, i) => { + c.text = `item ${i}`; + }); +} + +/** + * @api {get} /user/anonymized + * @apiVersion 3.0.0 + * @apiName UserGetAnonymized + * @apiGroup User + * @apiSuccess {Object} object The object { user, tasks } + **/ +api.getUserAnonymized = { + method: 'GET', + middlewares: [authWithHeaders(), cron], + url: '/user/anonymized', + async handler (req, res) { + let user = res.locals.user.toJSON(); + user.stats.toNextLevel = common.tnl(user.stats.lvl); + user.stats.maxHealth = common.maxHealth; + user.stats.maxMP = res.locals.user._statsComputed.maxMP; + + delete user.apiToken; + if (user.auth) { + delete user.auth.local; + delete user.auth.facebook; + } + delete user.newMessages; + delete user.profile; + delete user.purchased.plan; + delete user.contributor; + delete user.invitations; + delete user.items.special.nyeReceived; + delete user.items.special.valentineReceived; + delete user.webhooks; + delete user.achievements.challenges; + + _.forEach(user.inbox.messages, (msg) => { + msg.text = 'inbox message text'; + }); + _.forEach(user.tags, (tag) => { + tag.name = 'tag'; + tag.challenge = 'challenge'; + }); + + let query = { + userId: user._id, + $or: [ + { type: 'todo', completed: false }, + { type: { $in: ['habit', 'daily', 'reward'] } }, + ], + }; + let tasks = await Tasks.Task.find(query).exec(); + + _.forEach(tasks, (task) => { + task.text = 'task text'; + task.notes = 'task notes'; + if (task.type === 'todo' || task.type === 'daily') { + _cleanChecklist(task); + } + }); + + return res.respond(200, { user, tasks }); + }, +}; + const partyMembersFields = 'profile.name stats achievements items.special'; /**