import { random } from 'lodash' ; import { AUTO_FOLLOW_TAGS , CIRCLE_STATE , DB_NOTICE_TYPE , INVITATION_STATE , VERIFICATION_CODE_STATUS , } from 'common/enums' ; import { environment } from 'common/environment' ; import { CodeInvalidError , DisplayNameInvalidError , EmailExistsError , EmailInvalidError , NameExistsError , NameInvalidError , PasswordInvalidError , } from 'common/errors' ; import { isValidDisplayName , isValidEmail , isValidPassword , isValidUserName , makeUserName , setCookie , } from 'common/utils' ; import { GQLAuthResultType , GQLVerificationCodeType , MutationToUserRegisterResolver , } from 'definitions' ; const resolver = async ( root , { input } , { viewer , dataSources : { atomService , tagService , userService , notificationService } , req , res , } ) => { const { email : rawEmail , userName , displayName , password , codeId } = input ; const email = rawEmail . toLowerCase ( ) ; if ( ! isValidEmail ( email , { allowPlusSign : false } ) ) { throw new EmailInvalidError ( 'invalid email address format' ) ; } const [ code ] = await userService . findVerificationCodes ( { where : { uuid : codeId , email , type : GQLVerificationCodeType . register , status : VERIFICATION_CODE_STATUS . verified , } , } ) ; if ( ! code ) { throw new CodeInvalidError ( 'code does not exists' ) ; } const otherUser = await userService . findByEmail ( email ) ; if ( otherUser ) { throw new EmailExistsError ( 'email address has already been registered' ) ; } const shouldCheckDisplayName = displayName !== userName ; if ( shouldCheckDisplayName && ! isValidDisplayName ( displayName ) ) { throw new DisplayNameInvalidError ( 'invalid user display name' ) ; } if ( ! isValidPassword ( password ) ) { throw new PasswordInvalidError ( 'invalid user password' ) ; } let newUserName ; if ( userName ) { if ( ! isValidUserName ( userName ) ) { throw new NameInvalidError ( 'invalid user name' ) ; } if ( await userService . checkUserNameExists ( userName ) ) { throw new NameExistsError ( 'user name already exists' ) ; } newUserName = userName ; } else { let retries = 0 ; const mainName = makeUserName ( email ) ; newUserName = mainName ; while ( ! isValidUserName ( newUserName ) || ( await userService . checkUserNameExists ( newUserName ) ) ) { if ( retries >= 20 ) { throw new NameInvalidError ( 'cannot generate user name' ) ; } newUserName = `${ mainName }${ random ( 1 , 999 ) }` ; retries += 1 ; } } const newUser = await userService . create ( { ... input , email , userName : newUserName , } ) ; await userService . follow ( newUser . id , environment . mattyId ) ; await tagService . followTags ( newUser . id , AUTO_FOLLOW_TAGS ) ; await userService . markVerificationCodeAs ( { codeId : code . id , status : VERIFICATION_CODE_STATUS . used , } ) ; notificationService . mail . sendRegisterSuccess ( { to : email , recipient : { displayName , } , language : viewer . language , } ) ; const invitations = await atomService . findMany ( { table : 'circle_invitation' , where : { email , state : INVITATION_STATE . pending } , } ) ; await Promise . all ( invitations . map ( async ( invitation ) => { const circle = await atomService . findFirst ( { table : 'circle' , where : { id : invitation . circleId , state : CIRCLE_STATE . active , } , } ) ; notificationService . trigger ( { event : DB_NOTICE_TYPE . circle_invitation , actorId : invitation . inviter , recipientId : newUser . id , entities : [ { type : 'target' , entityTable : 'circle' , entity : circle , } , ] , } ) ; } ) ) ; const { token , user } = await userService . loginByEmail ( { ... input , email } ) ; setCookie ( { req , res , token , user } ) ; return { token , auth : true , type : GQLAuthResultType . Signup } ; } ; export default resolver ;