diff --git a/common/locales/en/messages.json b/common/locales/en/messages.json index 6a7bfb6e16..ead1d7601a 100644 --- a/common/locales/en/messages.json +++ b/common/locales/en/messages.json @@ -32,5 +32,24 @@ "armoireEquipment": "<%= image %> You found a piece of rare Equipment in the Armoire: <%= dropText %>! Awesome!", "armoireFood": "<%= image %> You rummage in the Armoire and find <%= dropArticle %><%= dropText %>. What's that doing in here?", - "armoireExp": "You wrestle with the Armoire and gain Experience. Take that!" + "armoireExp": "You wrestle with the Armoire and gain Experience. Take that!", + + "messageInsufficientGems": "Not enough gems!", + + "messageAuthPasswordMustMatch": ":password and :confirmPassword don't match", + "messageAuthCredentialsRequired": ":username, :email, :password, :confirmPassword required", + "messageAuthUsernameTaken": "Username already taken", + "messageAuthEmailTaken": "Email already taken", + "messageAuthNoUserFound": "No user found.", + "messageAuthMustBeLoggedIn": "You must be logged in.", + "messageAuthMustIncludeTokens": "You must include a token and uid (user id) in your request", + + "messageGroupNotFound": "Group not found or you don't have access.", + "messageGroupAlreadyInParty": "Already in a party, try refreshing.", + "messageGroupOnlyLeaderCanUpdate": "Only the group leader can update the group!", + "messageGroupRequiresInvite": "Can't join a group you're not invited to.", + "messageGroupCannotRemoveSelf": "You cannot remove yourself!", + + "messageUserOperationProtected": "path `<%= operation %>` was not saved, as it's a protected path.", + "messageUserOperationNotFound": "<%= operation %> operation not found" } diff --git a/test/api/groups/GET-groups_id.test.js b/test/api/groups/GET-groups_id.test.js index 982fb3ccd0..786bc45b83 100644 --- a/test/api/groups/GET-groups_id.test.js +++ b/test/api/groups/GET-groups_id.test.js @@ -2,6 +2,7 @@ import { createAndPopulateGroup, generateUser, requester, + translate as t, } from '../../helpers/api.helper'; import { find, @@ -148,7 +149,7 @@ describe('GET /groups/:id', () => { return expect(api.get(`/groups/${createdGroup._id}`)) .to.eventually.be.rejected.and.eql({ code: 404, - text: 'Group not found or you don\'t have access.', + text: t('messageGroupNotFound'), }); }); }); @@ -178,7 +179,7 @@ describe('GET /groups/:id', () => { return expect(api.get(`/groups/${createdGroup._id}`)) .to.eventually.be.rejected.and.eql({ code: 404, - text: 'Group not found or you don\'t have access.', + text: t('messageGroupNotFound'), }); }); }); @@ -227,7 +228,7 @@ describe('GET /groups/:id', () => { return expect(api.get('/groups/group-that-does-not-exist')) .to.eventually.be.rejected.and.eql({ code: 404, - text: 'Group not found or you don\'t have access.', + text: t('messageGroupNotFound'), }); }); }); diff --git a/test/api/groups/POST-groups.test.js b/test/api/groups/POST-groups.test.js index 7597cd9beb..d29b50e7d6 100644 --- a/test/api/groups/POST-groups.test.js +++ b/test/api/groups/POST-groups.test.js @@ -2,6 +2,7 @@ import { generateGroup, generateUser, requester, + translate as t, } from '../../helpers/api.helper'; describe('POST /groups', () => { @@ -82,7 +83,7 @@ describe('POST /groups', () => { }); })).to.eventually.be.rejected.and.eql({ code: 400, - text: 'Already in a party, try refreshing.', + text: t('messageGroupAlreadyInParty'), }); }) @@ -119,11 +120,10 @@ describe('POST /groups', () => { }); })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'Not enough gems!', + text: t('messageInsufficientGems'), }); }); - it('can create a public guild', () => { return expect(api.post('/groups', { type: 'guild', diff --git a/test/api/groups/POST-groups_id.test.js b/test/api/groups/POST-groups_id.test.js index 279ad76edf..603d0fe6a6 100644 --- a/test/api/groups/POST-groups_id.test.js +++ b/test/api/groups/POST-groups_id.test.js @@ -2,6 +2,7 @@ import { generateGroup, generateUser, requester, + translate as t, } from '../../helpers/api.helper'; describe('POST /groups/:id', () => { @@ -34,7 +35,7 @@ describe('POST /groups/:id', () => { name: 'Change' })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'Only the group leader can update the group!', + text: t('messageGroupOnlyLeaderCanUpdate'), }); }); }); diff --git a/test/api/groups/POST-groups_id_join.test.js b/test/api/groups/POST-groups_id_join.test.js index 38587ee235..1d3ab95dca 100644 --- a/test/api/groups/POST-groups_id_join.test.js +++ b/test/api/groups/POST-groups_id_join.test.js @@ -2,6 +2,7 @@ import { createAndPopulateGroup, generateUser, requester, + translate as t, } from '../../helpers/api.helper'; import { each, find } from 'lodash'; @@ -75,7 +76,7 @@ describe('POST /groups/:id/join', () => { return api.get(`/groups/${group._id}`); })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'Can\'t join a group you\'re not invited to.', + text: t('messageGroupRequiresInvite'), }); }); }); diff --git a/test/api/groups/POST-groups_id_leave.test.js b/test/api/groups/POST-groups_id_leave.test.js index 2a6fad1686..bfd280d842 100644 --- a/test/api/groups/POST-groups_id_leave.test.js +++ b/test/api/groups/POST-groups_id_leave.test.js @@ -3,6 +3,7 @@ import { generateGroup, generateUser, requester, + translate as t, } from '../../helpers/api.helper'; import { find } from 'lodash'; @@ -88,7 +89,7 @@ describe('POST /groups/:id/leave', () => { return api.get(`/groups/${group._id}`); })).to.eventually.be.rejected.and.eql({ code: 404, - text: 'Group not found or you don\'t have access.', + text: t('messageGroupNotFound'), }); }); }); diff --git a/test/api/groups/POST-groups_id_removeMember.test.js b/test/api/groups/POST-groups_id_removeMember.test.js index 8e27aedd74..2806e54fc5 100644 --- a/test/api/groups/POST-groups_id_removeMember.test.js +++ b/test/api/groups/POST-groups_id_removeMember.test.js @@ -3,6 +3,7 @@ import { generateGroup, generateUser, requester, + translate as t, } from '../../helpers/api.helper'; describe('POST /groups/:id/removeMember', () => { @@ -40,7 +41,7 @@ describe('POST /groups/:id/removeMember', () => { uuid: leader._id, })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'You cannot remove yourself!', + text: t('messageGroupCannotRemoveSelf'), }); }); diff --git a/test/api/register/POST-register.test.js b/test/api/register/POST-register.test.js index 0f003f6357..bb87eea1ff 100644 --- a/test/api/register/POST-register.test.js +++ b/test/api/register/POST-register.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../helpers/api.helper'; import {v4 as generateRandomUserName} from 'uuid'; @@ -39,7 +40,55 @@ describe('POST /register', () => { confirmPassword: confirmPassword, })).to.eventually.be.rejected.and.eql({ code: 401, - text: ':password and :confirmPassword don\'t match', + text: t('messageAuthPasswordMustMatch'), + }); + }); + + it('requires a username', () => { + let api = requester(); + let email = `${generateRandomUserName()}@example.com`; + let password = 'password'; + let confirmPassword = 'password'; + + return expect(api.post('/register', { + email: email, + password: password, + confirmPassword: confirmPassword, + })).to.eventually.be.rejected.and.eql({ + code: 401, + text: t('messageAuthCredentialsRequired'), + }); + }); + + it('requires an email', () => { + let api = requester(); + let username = generateRandomUserName(); + let password = 'password'; + let confirmPassword = 'password'; + + return expect(api.post('/register', { + username: username, + password: password, + confirmPassword: confirmPassword, + })).to.eventually.be.rejected.and.eql({ + code: 401, + text: t('messageAuthCredentialsRequired'), + }); + }); + + it('requires a password', () => { + let api = requester(); + let username = generateRandomUserName(); + let email = `${username}@example.com`; + let confirmPassword = 'password'; + + return expect(api.post('/register', { + username: username, + email: email, + confirmPassword: confirmPassword, + })).to.eventually.be.rejected.and.eql({ + code: 401, + text: t('messageAuthCredentialsRequired'), }); }); }); @@ -68,7 +117,7 @@ describe('POST /register', () => { confirmPassword: password, })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'Username already taken', + text: t('messageAuthUsernameTaken'), }); }); @@ -84,7 +133,7 @@ describe('POST /register', () => { confirmPassword: password, })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'Email already taken', + text: t('messageAuthEmailTaken'), }); }); }); diff --git a/test/api/user/DELETE-user.test.js b/test/api/user/DELETE-user.test.js index 2446bd33ec..310f4744d8 100644 --- a/test/api/user/DELETE-user.test.js +++ b/test/api/user/DELETE-user.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../helpers/api.helper'; describe('DELETE /user', () => { @@ -17,10 +18,14 @@ describe('DELETE /user', () => { return api.get('/user'); })).to.eventually.be.rejected.and.eql({ code: 401, - text: 'No user found.', + text: t('messageAuthNoUserFound'), }); }); + context('user has active subscription', () => { + it('does not delete account'); + }); + context('user in solo group', () => { it('deletes party when user is the only member'); diff --git a/test/api/user/GET-user_tags_id.test.js b/test/api/user/GET-user_tags_id.test.js index b7e2e281d3..5bcbead2f0 100644 --- a/test/api/user/GET-user_tags_id.test.js +++ b/test/api/user/GET-user_tags_id.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../helpers/api.helper'; describe('GET /user/tags/id', () => { @@ -22,7 +23,7 @@ describe('GET /user/tags/id', () => { return expect(api.get('/user/tags/not-an-id')) .to.eventually.be.rejected.and.eql({ code: 404, - text: 'Tag not found.' + text: t('messageTagNotFound'), }); }); }); diff --git a/test/api/user/PUT-user.test.js b/test/api/user/PUT-user.test.js index 40f7520864..836e97920b 100644 --- a/test/api/user/PUT-user.test.js +++ b/test/api/user/PUT-user.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../helpers/api.helper'; import { each } from 'lodash'; @@ -15,7 +16,7 @@ describe('PUT /user', () => { }); }); - context('allowed paths', () => { + context('allowed operations', () => { it('updates the user', () => { return api.put('/user', { 'profile.name' : 'Frodo', @@ -29,8 +30,8 @@ describe('PUT /user', () => { }); }); - context('top level protected paths', () => { - let protectedPaths = { + context('top level protected operations', () => { + let protectedOperations = { 'gem balance': {balance: 100}, 'auth': {'auth.blocked': true, 'auth.timestamps.created': new Date()}, 'contributor': {'contributor.level': 9, 'contributor.admin': true, 'contributor.text': 'some text'}, @@ -40,11 +41,11 @@ describe('PUT /user', () => { 'tasks': {todos: [], habits: [], dailys: [], rewards: []}, }; - each(protectedPaths, (data, testName) => { + each(protectedOperations, (data, testName) => { it(`does not allow updating ${testName}`, () => { let errorText = []; - each(data, (value, path) => { - errorText.push(`path \`${path}\` was not saved, as it's a protected path.`); + each(data, (value, operation) => { + errorText.push(t('messageUserOperationProtected', { operation: operation })); }); return expect(api.put('/user', data)).to.eventually.be.rejected.and.eql({ code: 401, @@ -54,16 +55,16 @@ describe('PUT /user', () => { }); }); - context('sub-level protected paths', () => { - let protectedPaths = { + context('sub-level protected operations', () => { + let protectedOperations = { 'class stat': {'stats.class': 'wizard'}, }; - each(protectedPaths, (data, testName) => { + each(protectedOperations, (data, testName) => { it(`does not allow updating ${testName}`, () => { let errorText = []; - each(data, (value, path) => { - errorText.push(`path \`${path}\` was not saved, as it's a protected path.`); + each(data, (value, operation) => { + errorText.push(t('messageUserOperationProtected', { operation: operation })); }); return expect(api.put('/user', data)).to.eventually.be.rejected.and.eql({ code: 401, diff --git a/test/api/user/batch-update/POST-user_batch-update.test.js b/test/api/user/batch-update/POST-user_batch-update.test.js index b5bcbea9ba..23e6be52fe 100644 --- a/test/api/user/batch-update/POST-user_batch-update.test.js +++ b/test/api/user/batch-update/POST-user_batch-update.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../../helpers/api.helper'; import { each } from 'lodash'; @@ -49,7 +50,7 @@ describe('POST /user/batch-update', () => { {op: operation}, ])).to.eventually.be.rejected.and.eql({ code: 500, - text: `${operation} operation not found`, + text: t('messageUserOperationNotFound', { operation: operation}), }); }); }); @@ -61,7 +62,7 @@ describe('POST /user/batch-update', () => { {op: 'aNotRealOperation'}, ])).to.eventually.be.rejected.and.eql({ code: 500, - text: 'aNotRealOperation operation not found', + text: t('messageUserOperationNotFound', { operation: 'aNotRealOperation' }), }); }); }); diff --git a/test/api/user/tasks/DELETE-tasks_id.test.js b/test/api/user/tasks/DELETE-tasks_id.test.js index 59d15afc37..3a13a6e3c5 100644 --- a/test/api/user/tasks/DELETE-tasks_id.test.js +++ b/test/api/user/tasks/DELETE-tasks_id.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../../helpers/api.helper'; describe('DELETE /user/tasks/:id', () => { @@ -20,7 +21,7 @@ describe('DELETE /user/tasks/:id', () => { return api.get(`/user/tasks/${task.id}`); })).to.eventually.be.rejected.and.eql({ code: 404, - text: 'No task found.', + text: t('messageTaskNotFound'), }); }); @@ -28,7 +29,7 @@ describe('DELETE /user/tasks/:id', () => { return expect(api.del('/user/tasks/task-that-does-not-exist')) .to.eventually.be.rejected.and.eql({ code: 404, - text: 'Task not found.', + text: t('messageTaskNotFound'), }); }); diff --git a/test/api/user/tasks/GET-tasks.test.js b/test/api/user/tasks/GET-tasks.test.js index 1f712814b7..c58e8d11ef 100644 --- a/test/api/user/tasks/GET-tasks.test.js +++ b/test/api/user/tasks/GET-tasks.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../../helpers/api.helper'; describe('GET /user/tasks/', () => { diff --git a/test/api/user/tasks/GET-tasks_id.test.js b/test/api/user/tasks/GET-tasks_id.test.js index 688ce2dbb2..d321b66666 100644 --- a/test/api/user/tasks/GET-tasks_id.test.js +++ b/test/api/user/tasks/GET-tasks_id.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../../helpers/api.helper'; describe('GET /user/tasks/:id', () => { @@ -28,7 +29,7 @@ describe('GET /user/tasks/:id', () => { return expect(api.get('/user/tasks/task-that-does-not-exist')) .to.eventually.be.rejected.and.eql({ code: 404, - text: 'No task found.', + text: t('messageTaskNotFound'), }); }); @@ -38,7 +39,7 @@ describe('GET /user/tasks/:id', () => { return api.get(`/user/tasks/${otherUsersTask.id}`); })).to.eventually.be.rejected.and.eql({ code: 404, - text: 'No task found.', + text: t('messageTaskNotFound'), }); }); }); diff --git a/test/api/user/tasks/POST-tasks.test.js b/test/api/user/tasks/POST-tasks.test.js index a51a40f871..556e4f37af 100644 --- a/test/api/user/tasks/POST-tasks.test.js +++ b/test/api/user/tasks/POST-tasks.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../../helpers/api.helper'; describe('POST /user/tasks', () => { @@ -46,7 +47,7 @@ describe('POST /user/tasks', () => { id: todo.id, })).to.eventually.be.rejected.and.eql({ code: 409, - text: 'A task with that ID already exists.', + text: t('messageDuplicateTaskID'), }); }); diff --git a/test/api/user/tasks/PUT-tasks_id.test.js b/test/api/user/tasks/PUT-tasks_id.test.js index dff1a8862b..0fa32b3546 100644 --- a/test/api/user/tasks/PUT-tasks_id.test.js +++ b/test/api/user/tasks/PUT-tasks_id.test.js @@ -1,6 +1,7 @@ import { generateUser, requester, + translate as t, } from '../../../helpers/api.helper'; describe('PUT /user/tasks/:id', () => { diff --git a/test/helpers/api.helper.js b/test/helpers/api.helper.js index 01afef66f1..dd66edc80a 100644 --- a/test/helpers/api.helper.js +++ b/test/helpers/api.helper.js @@ -7,6 +7,9 @@ import { import {MongoClient as mongo} from 'mongodb'; import {v4 as generateUUID} from 'uuid'; import superagent from 'superagent'; +import i18n from '../../common/script/src/i18n'; +require('coffee-script'); +i18n.translations = require('../../website/src/i18n.js').translations; const API_TEST_SERVER_PORT = 3003; @@ -22,6 +25,22 @@ export function requester(user={}) { } }; +// Use this to verify error messages returned by the server +// That way, if the translated string changes, the test +// will not break. NOTE: it checks agains errors with string as well. +export function translate(key, variables) { + const STRING_ERROR_MSG = 'Error processing the string. Please see Help > Report a Bug.'; + const STRING_DOES_NOT_EXIST_MSG = /^String '.*' not found.$/; + + let translatedString = i18n.t(key, variables); + + expect(translatedString).to.not.be.empty; + expect(translatedString).to.not.eql(STRING_ERROR_MSG); + expect(translatedString).to.not.match(STRING_DOES_NOT_EXIST_MSG); + + return translatedString; +}; + // Creates a new user and returns it // If you need the user to have specific requirements, // such as a balance > 0, just pass in the adjustment diff --git a/website/src/controllers/auth.js b/website/src/controllers/auth.js index a416bebd88..7fa551689e 100644 --- a/website/src/controllers/auth.js +++ b/website/src/controllers/auth.js @@ -16,9 +16,9 @@ var isProd = nconf.get('NODE_ENV') === 'production'; var api = module.exports; -var NO_TOKEN_OR_UID = { err: "You must include a token and uid (user id) in your request"}; -var NO_USER_FOUND = {err: "No user found."}; -var NO_SESSION_FOUND = { err: "You must be logged in." }; +var NO_TOKEN_OR_UID = { err: shared.i18n.t('messageAuthMustIncludeTokens') }; +var NO_USER_FOUND = {err: shared.i18n.t('messageAuthNoUserFound') }; +var NO_SESSION_FOUND = { err: shared.i18n.t('messageAuthMustBeLoggedIn') }; var accountSuspended = function(uuid){ return { err: 'Account has been suspended, please contact leslie@habitica.com with your UUID ('+uuid+') for assistance.', @@ -72,9 +72,9 @@ api.registerUser = function(req, res, next) { async.auto({ validate: function(cb) { if (!(username && req.body.password && email)) - return cb({code:401, err: ":username, :email, :password, :confirmPassword required"}); + return cb({code:401, err: shared.i18n.t('messageAuthCredentialsRequired')}); if (req.body.password !== req.body.confirmPassword) - return cb({code:401, err: ":password and :confirmPassword don't match"}); + return cb({code:401, err: shared.i18n.t('messageAuthPasswordMustMatch')}); if (!validator.isEmail(email)) return cb({code:401, err: ":email invalid"}); cb(); @@ -90,7 +90,7 @@ api.registerUser = function(req, res, next) { if (data.findReg) { if (email === data.findReg.auth.local.email) return cb({code:401, err:"Email already taken"}); // Check that the lowercase username isn't already used - if (lowerCaseUsername === data.findReg.auth.local.lowerCaseUsername) return cb({code:401, err:"Username already taken"}); + if (lowerCaseUsername === data.findReg.auth.local.lowerCaseUsername) return cb({code:401, err: shared.i18n.t('messageAuthUsernameTaken')}); } var salt = utils.makeSalt(); var newUser = { @@ -309,7 +309,7 @@ api.changeEmail = function(req, res, next){ User.findOne({'auth.local.email': email}, {auth:1}, cb); }, function(found, cb){ - if(found) return cb({code:401, err: "Email already taken"}); + if(found) return cb({code:401, err: shared.i18n.t('messageAuthEmailTaken')}); if (invalidPassword(res.locals.user, req.body.password)) return cb(invalidPassword(res.locals.user, req.body.password)); res.locals.user.auth.local.email = email; res.locals.user.save(cb); diff --git a/website/src/controllers/groups.js b/website/src/controllers/groups.js index 800aa0eabf..56a881f3d4 100644 --- a/website/src/controllers/groups.js +++ b/website/src/controllers/groups.js @@ -143,7 +143,7 @@ api.get = function(req, res, next) { q.exec(function(err, group){ if (err) return next(err); if(!group){ - if(gid !== 'party') return res.json(404,{err: "Group not found or you don't have access."}); + if(gid !== 'party') return res.json(404,{err: shared.i18n.t('messageGroupNotFound')}); // Don't send a 404 when querying for a party even if it doesn't exist // so that users with no party don't get a 404 on every access to the site @@ -184,7 +184,7 @@ api.create = function(req, res, next) { group.leader = user._id; if(group.type === 'guild'){ - if(user.balance < 1) return res.json(401, {err: 'Not enough gems!'}); + if(user.balance < 1) return res.json(401, {err: shared.i18n.t('messageInsufficientGems')}); group.balance = 1; user.balance--; @@ -209,7 +209,7 @@ api.create = function(req, res, next) { Group.findOne({type:'party',members:{$in:[user._id]}},cb); }, function(found, cb){ - if (found) return cb('Already in a party, try refreshing.'); + if (found) return cb(shared.i18n.t('messageGroupAlreadyInParty')); group.save(cb); }, function(saved, count, cb){ @@ -218,7 +218,7 @@ api.create = function(req, res, next) { saved.populate('members', nameFields, cb); } ], function(err, populated){ - if (err == 'Already in a party, try refreshing.') return res.json(400,{err:err}); + if (err === shared.i18n.t('messageGroupAlreadyInParty')) return res.json(400,{err:err}); if (err) return next(err); group = user = null; return res.json(populated); @@ -231,7 +231,7 @@ api.update = function(req, res, next) { var user = res.locals.user; if(group.leader !== user._id) - return res.json(401, {err: "Only the group leader can update the group!"}); + return res.json(401, {err: shared.i18n.t('messageGroupOnlyLeaderCanUpdate')}); 'name description logo logo leaderMessage leader leaderOnly'.split(' ').forEach(function(attr){ group[attr] = req.body[attr]; @@ -251,7 +251,7 @@ api.attachGroup = function(req, res, next) { var q = (gid == 'party') ? Group.findOne({type: 'party', members: {'$in': [res.locals.user._id]}}) : Group.findById(gid); q.exec(function(err, group){ if(err) return next(err); - if(!group) return res.json(404, {err: "Group not found"}); + if(!group) return res.json(404, {err: shared.i18n.t('messageGroupNotFound')}); res.locals.group = group; next(); }); @@ -270,7 +270,7 @@ api.getChat = function(req, res, next) { populateQuery(gid, q); q.exec(function(err, group){ if (err) return next(err); - if (!group && gid!=='party') return res.json(404,{err: "Group not found or you don't have access."}); + if (!group && gid!=='party') return res.json(404,{err: shared.i18n.t('messageGroupNotFound')}); res.json(res.locals.group.chat); gid = null; }); @@ -470,7 +470,7 @@ api.join = function(req, res, next) { } } - if(!isUserInvited) return res.json(401, {err: "Can't join a group you're not invited to."}); + if(!isUserInvited) return res.json(401, {err: shared.i18n.t('messageGroupRequiresInvite')}); if (!_.contains(group.members, user._id)){ if (group.members.length === 0) { diff --git a/website/src/controllers/user.js b/website/src/controllers/user.js index f33c65970e..b9559e23c5 100644 --- a/website/src/controllers/user.js +++ b/website/src/controllers/user.js @@ -164,7 +164,7 @@ api.getTasks = function(req, res, next) { */ api.getTask = function(req, res, next) { var task = findTask(req,res); - if (!task) return res.json(404, {err: "No task found."}); + if (!task) return res.json(404, {err: shared.i18n.t('messageTaskNotFound')}); return res.json(200, task); }; @@ -317,7 +317,7 @@ api.update = function(req, res, next) { if (acceptablePUTPaths[k]) user.fns.dotSet(k, v); else - errors.push("path `" + k + "` was not saved, as it's a protected path."); + errors.push(shared.i18n.t('messageUserOperationProtected', { operation: k })); return true; }); user.save(function(err) { @@ -600,7 +600,7 @@ api.batchUpdate = function(req, res, next) { return cb(code+": "+ (data.message ? data.message : data.err ? data.err : JSON.stringify(data))); return cb(); }; - if(!api[_req.op]) { return cb(_req.op + ' operation not found'); } + if(!api[_req.op]) { return cb(shared.i18n.t('messageUserOperationNotFound', { operation: _req.op })); } api[_req.op](_req, res, cb); }); })