@@ -14,6 +14,8 @@ var triggers = require('./triggers');
14
14
import RestQuery from './RestQuery' ;
15
15
import _ from 'lodash' ;
16
16
17
+ const requiredUserFields = { fields : { ...SchemaController . defaultColumns . _Default , ...SchemaController . defaultColumns . _User } } ;
18
+
17
19
// query and data are both provided in REST API format. So data
18
20
// types are encoded by plain old objects.
19
21
// If query is null, this is a "create" and the data in data should be
@@ -356,44 +358,60 @@ RestWrite.prototype.transformUser = function() {
356
358
}
357
359
return ;
358
360
}
359
- return this . config . database . find (
360
- this . className , {
361
- username : this . data . username ,
362
- objectId : { '$ne' : this . objectId ( ) }
363
- } , { limit : 1 } ) . then ( ( results ) => {
364
- if ( results . length > 0 ) {
365
- throw new Parse . Error ( Parse . Error . USERNAME_TAKEN ,
366
- 'Account already exists for this username' ) ;
367
- }
368
- return Promise . resolve ( ) ;
369
- } ) ;
361
+ // TODO: refactor this so that ensureUniqueness isn't called for every single sign up.
362
+ return this . config . database . adapter . ensureUniqueness ( '_User' , [ 'username' ] , requiredUserFields )
363
+ . catch ( error => {
364
+ if ( error . code === Parse . Error . DUPLICATE_VALUE ) {
365
+ // If they already have duplicate usernames or emails, the ensureUniqueness will fail,
366
+ // and then nobody will be able to sign up D: so just use the old, janky
367
+ // method to check for duplicate usernames.
368
+ return this . config . database . find (
369
+ this . className ,
370
+ { username : this . data . username , objectId : { '$ne' : this . objectId ( ) } } ,
371
+ { limit : 1 }
372
+ )
373
+ . then ( results => {
374
+ if ( results . length > 0 ) {
375
+ throw new Parse . Error ( Parse . Error . USERNAME_TAKEN , 'Account already exists for this username.' ) ;
376
+ }
377
+ return ;
378
+ } ) ;
379
+ }
380
+ throw error ;
381
+ } )
370
382
} ) . then ( ( ) => {
371
383
if ( ! this . data . email || this . data . email . __op === 'Delete' ) {
372
384
return ;
373
385
}
374
386
// Validate basic email address format
375
387
if ( ! this . data . email . match ( / ^ .+ @ .+ $ / ) ) {
376
- throw new Parse . Error ( Parse . Error . INVALID_EMAIL_ADDRESS ,
377
- 'Email address format is invalid.' ) ;
388
+ throw new Parse . Error ( Parse . Error . INVALID_EMAIL_ADDRESS , 'Email address format is invalid.' ) ;
378
389
}
379
390
// Check for email uniqueness
380
- return this . config . database . find (
381
- this . className , {
382
- email : this . data . email ,
383
- objectId : { '$ne' : this . objectId ( ) }
384
- } , { limit : 1 } ) . then ( ( results ) => {
385
- if ( results . length > 0 ) {
386
- throw new Parse . Error ( Parse . Error . EMAIL_TAKEN ,
387
- 'Account already exists for this email ' +
388
- 'address' ) ;
389
- }
390
- return Promise . resolve ( ) ;
391
- } ) . then ( ( ) => {
392
- // We updated the email, send a new validation
393
- this . storage [ 'sendVerificationEmail' ] = true ;
394
- this . config . userController . setEmailVerifyToken ( this . data ) ;
395
- return Promise . resolve ( ) ;
396
- } )
391
+ return this . config . database . adapter . ensureUniqueness ( '_User' , [ 'email' ] , requiredUserFields )
392
+ . catch ( error => {
393
+ // Same problem for email as above for username
394
+ if ( error . code === Parse . Error . DUPLICATE_VALUE ) {
395
+ return this . config . database . find (
396
+ this . className ,
397
+ { email : this . data . email , objectId : { '$ne' : this . objectId ( ) } } ,
398
+ { limit : 1 }
399
+ )
400
+ . then ( results => {
401
+ if ( results . length > 0 ) {
402
+ throw new Parse . Error ( Parse . Error . EMAIL_TAKEN , 'Account already exists for this email address.' ) ;
403
+ }
404
+ return ;
405
+ } ) ;
406
+ }
407
+ throw error ;
408
+ } )
409
+ . then ( ( ) => {
410
+ // We updated the email, send a new validation
411
+ this . storage [ 'sendVerificationEmail' ] = true ;
412
+ this . config . userController . setEmailVerifyToken ( this . data ) ;
413
+ return ;
414
+ } )
397
415
} ) ;
398
416
} ;
399
417
@@ -762,6 +780,36 @@ RestWrite.prototype.runDatabaseOperation = function() {
762
780
763
781
// Run a create
764
782
return this . config . database . create ( this . className , this . data , this . runOptions )
783
+ . catch ( error => {
784
+ if ( this . className !== '_User' || error . code !== Parse . Error . DUPLICATE_VALUE ) {
785
+ throw error ;
786
+ }
787
+ // If this was a failed user creation due to username or email already taken, we need to
788
+ // check whether it was username or email and return the appropriate error.
789
+
790
+ // TODO: See if we can later do this without additional queries by using named indexes.
791
+ return this . config . database . find (
792
+ this . className ,
793
+ { username : this . data . username , objectId : { '$ne' : this . objectId ( ) } } ,
794
+ { limit : 1 }
795
+ )
796
+ . then ( results => {
797
+ if ( results . length > 0 ) {
798
+ throw new Parse . Error ( Parse . Error . USERNAME_TAKEN , 'Account already exists for this username.' ) ;
799
+ }
800
+ return this . config . database . find (
801
+ this . className ,
802
+ { email : this . data . email , objectId : { '$ne' : this . objectId ( ) } } ,
803
+ { limit : 1 }
804
+ ) ;
805
+ } )
806
+ . then ( results => {
807
+ if ( results . length > 0 ) {
808
+ throw new Parse . Error ( Parse . Error . EMAIL_TAKEN , 'Account already exists for this email address.' ) ;
809
+ }
810
+ throw error ;
811
+ } ) ;
812
+ } )
765
813
. then ( response => {
766
814
response . objectId = this . data . objectId ;
767
815
response . createdAt = this . data . createdAt ;
0 commit comments