diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index b33b5f61f2..41a9a5d441 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -4430,3 +4430,39 @@ describe('allowClientClassCreation option', () => { defaultConfiguration.allowClientClassCreation = true; }); }); + +describe('log levels', () => { + const logLevels = ['info', 'warn', 'error']; + const testLogLevels = ['info'];//[undefined, 'silent', 'info', 'warn', 'error']; + + it_id('bd3929eb-85dd-4955-ac1d-5ba59ab1b9a3')(fit)('should use log level for username already exists error', async () => { + for (const testLogLevel of testLogLevels) { + await reconfigureServer({ + logLevels: { + usernameAlreadyExists: testLogLevel, + }, + }); + + // Set up logger spies + const logger = require('../lib/logger').logger; + logLevels.forEach(level => spyOn(logger, level).and.callFake(() => {})); + + // Invoke error + const uniqueUsername = `user_${Date.now()}`; + await Parse.User.signUp(uniqueUsername, 'pass'); + await expectAsync(Parse.User.signUp(uniqueUsername, 'pass')).toBeRejectedWith( + new Parse.Error( + Parse.Error.USERNAME_TAKEN, + 'Account already exists for this username.' + ) + ); + + // Verify log outputs + logLevels.forEach(level => { + const levelOrDefault = testLogLevel || 'error'; + expect(logger[level]).toHaveBeenCalledTimes(level === levelOrDefault ? 1 : 0); + logger[level].calls.reset(); + }); + } + }); +}); diff --git a/spec/helper.js b/spec/helper.js index c09a0c4eb4..5702ac48f0 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -150,6 +150,7 @@ if (silent) { triggerAfter: 'silent', triggerBeforeError: 'silent', triggerBeforeSuccess: 'silent', + usernameAlreadyExists: 'silent', }; } diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index a1da6c09a7..936a4cea5d 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -1117,4 +1117,10 @@ module.exports.LogLevels = { 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`.', default: 'info', }, + usernameAlreadyExists: { + env: 'PARSE_SERVER_LOG_LEVELS_USERNAME_ALREADY_EXISTS', + help: + 'Log level for the username already exists error when trying to sign up. Default is `error`.', + default: 'error', + }, }; diff --git a/src/Options/docs.js b/src/Options/docs.js index 4c2883adaa..ee351eaa8f 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -254,4 +254,5 @@ * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. + * @property {String} usernameAlreadyExists Log level for the username already exists error when trying to sign up. Default is `error`. */ diff --git a/src/Options/index.js b/src/Options/index.js index 40e15afb27..68fa0fbca2 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -635,4 +635,8 @@ export interface LogLevels { :DEFAULT: error */ cloudFunctionError: ?string; + /* Log level for the username already exists error when trying to sign up. Default is `error`. + :DEFAULT: error + */ + usernameAlreadyExists: ?string; } diff --git a/src/RestWrite.js b/src/RestWrite.js index 255c55f24c..814f6e0312 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -739,10 +739,11 @@ RestWrite.prototype._validateUserName = function () { ) .then(results => { if (results.length > 0) { - throw new Parse.Error( + const usernameError = new Parse.Error( Parse.Error.USERNAME_TAKEN, 'Account already exists for this username.' ); + throw usernameError; } return; }); @@ -1557,10 +1558,18 @@ RestWrite.prototype.runDatabaseOperation = function () { // Quick check, if we were able to infer the duplicated field name if (error && error.userInfo && error.userInfo.duplicated_field === 'username') { - throw new Parse.Error( + const usernameError = new Parse.Error( Parse.Error.USERNAME_TAKEN, 'Account already exists for this username.' ); + if (this.config.logLevels.usernameAlreadyExists === 'info') { + logger.info(JSON.stringify(usernameError)); + } else if (this.config.logLevels.usernameAlreadyExists === 'warn') { + logger.warn(JSON.stringify(usernameError)); + } else if (this.config.logLevels.usernameAlreadyExists === 'error') { + logger.error(JSON.stringify(usernameError)); + } + throw usernameError; } if (error && error.userInfo && error.userInfo.duplicated_field === 'email') { @@ -1585,10 +1594,14 @@ RestWrite.prototype.runDatabaseOperation = function () { ) .then(results => { if (results.length > 0) { - throw new Parse.Error( + const usernameError = new Parse.Error( Parse.Error.USERNAME_TAKEN, 'Account already exists for this username.' ); + if (this.config.logLevels.usernameAlreadyExists !== 'silent') { + logger[this.config.logLevels.usernameAlreadyExists](JSON.stringify(usernameError)); + } + throw usernameError; } return this.config.database.find( this.className,