Skip to content

Commit f18f307

Browse files
authored
feat: Add option logLevels.signupUsernameTaken to change log level of username already exists sign-up rejection (#9962)
1 parent 3b38dff commit f18f307

File tree

6 files changed

+78
-1
lines changed

6 files changed

+78
-1
lines changed

spec/ParseUser.spec.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,59 @@ describe('Parse.User testing', () => {
8181
}
8282
});
8383

84+
it('logs username taken with configured log level', async () => {
85+
await reconfigureServer({ logLevels: { signupUsernameTaken: 'warn' } });
86+
const logger = require('../lib/logger').default;
87+
loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
88+
const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough();
89+
90+
const user = new Parse.User();
91+
user.setUsername('dupUser');
92+
user.setPassword('pass');
93+
await user.signUp();
94+
95+
const user2 = new Parse.User();
96+
user2.setUsername('dupUser');
97+
user2.setPassword('pass2');
98+
99+
expect(loggerWarnSpy).not.toHaveBeenCalled();
100+
101+
try {
102+
await user2.signUp();
103+
fail('should have thrown');
104+
} catch (e) {
105+
expect(e.code).toBe(Parse.Error.USERNAME_TAKEN);
106+
}
107+
108+
expect(loggerWarnSpy).toHaveBeenCalledTimes(1);
109+
expect(loggerErrorSpy.calls.count()).toBe(0);
110+
});
111+
112+
it('can silence username taken log event', async () => {
113+
await reconfigureServer({ logLevels: { signupUsernameTaken: 'silent' } });
114+
const logger = require('../lib/logger').default;
115+
loggerErrorSpy = spyOn(logger, 'error').and.callThrough();
116+
const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough();
117+
118+
const user = new Parse.User();
119+
user.setUsername('dupUser');
120+
user.setPassword('pass');
121+
await user.signUp();
122+
123+
const user2 = new Parse.User();
124+
user2.setUsername('dupUser');
125+
user2.setPassword('pass2');
126+
try {
127+
await user2.signUp();
128+
fail('should have thrown');
129+
} catch (e) {
130+
expect(e.code).toBe(Parse.Error.USERNAME_TAKEN);
131+
}
132+
133+
expect(loggerWarnSpy).not.toHaveBeenCalled();
134+
expect(loggerErrorSpy.calls.count()).toBe(0);
135+
});
136+
84137
it('user login with context', async () => {
85138
let hit = 0;
86139
const context = { foo: 'bar' };

src/Options/Definitions.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,12 @@ module.exports.LogLevels = {
14811481
'Log level used by the Cloud Code Functions on success. Default is `info`. See [LogLevel](LogLevel.html) for available values.',
14821482
default: 'info',
14831483
},
1484+
signupUsernameTaken: {
1485+
env: 'PARSE_SERVER_LOG_LEVELS_SIGNUP_USERNAME_TAKEN',
1486+
help:
1487+
'Log level used when a sign-up fails because the username already exists. Default is `info`. See [LogLevel](LogLevel.html) for available values.',
1488+
default: 'info',
1489+
},
14841490
triggerAfter: {
14851491
env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_AFTER',
14861492
help:

src/Options/docs.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Options/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,4 +786,8 @@ export interface LogLevels {
786786
:DEFAULT: error
787787
*/
788788
cloudFunctionError: ?string;
789+
/* Log level used when a sign-up fails because the username already exists. Default is `info`. See [LogLevel](LogLevel.html) for available values.
790+
:DEFAULT: info
791+
*/
792+
signupUsernameTaken: ?string;
789793
}

src/middlewares.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ export function handleParseErrors(err, req, res, next) {
466466
if (req.config && req.config.enableExpressErrorHandler) {
467467
return next(err);
468468
}
469+
const signupUsernameTakenLevel =
470+
req.config?.logLevels?.signupUsernameTaken || 'info';
469471
let httpStatus;
470472
// TODO: fill out this mapping
471473
switch (err.code) {
@@ -480,7 +482,17 @@ export function handleParseErrors(err, req, res, next) {
480482
}
481483
res.status(httpStatus);
482484
res.json({ code: err.code, error: err.message });
483-
log.error('Parse error: ', err);
485+
if (err.code === Parse.Error.USERNAME_TAKEN) {
486+
if (signupUsernameTakenLevel !== 'silent') {
487+
const loggerMethod =
488+
typeof log[signupUsernameTakenLevel] === 'function'
489+
? log[signupUsernameTakenLevel].bind(log)
490+
: log.error.bind(log);
491+
loggerMethod('Parse error: ', err);
492+
}
493+
} else {
494+
log.error('Parse error: ', err);
495+
}
484496
} else if (err.status && err.message) {
485497
res.status(err.status);
486498
res.json({ error: err.message });

types/Options/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,5 +296,6 @@ export interface LogLevels {
296296
triggerBeforeError?: string;
297297
cloudFunctionSuccess?: string;
298298
cloudFunctionError?: string;
299+
signupUsernameTaken?: string;
299300
}
300301
export {};

0 commit comments

Comments
 (0)