Ver Fonte

feat(server): Expand input for registerCustomerAccount mutation

Michael Bromley há 7 anos atrás
pai
commit
79b23bb6de

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
schema.json


+ 4 - 3
server/src/api/resolvers/auth.resolver.ts

@@ -10,6 +10,7 @@ import {
 
 import { ConfigService } from '../../config/config.service';
 import { User } from '../../entity/user/user.entity';
+import { I18nError } from '../../i18n/i18n-error';
 import { AuthService } from '../../service/services/auth.service';
 import { ChannelService } from '../../service/services/channel.service';
 import { CustomerService } from '../../service/services/customer.service';
@@ -69,9 +70,7 @@ export class AuthResolver {
         @Ctx() ctx: RequestContext,
         @Args() args: RegisterCustomerAccountMutationArgs,
     ) {
-        return this.customerService
-            .registerCustomerAccount(ctx, args.emailAddress, args.password)
-            .then(() => true);
+        return this.customerService.registerCustomerAccount(ctx, args.input).then(() => true);
     }
 
     @Mutation()
@@ -98,6 +97,8 @@ export class AuthResolver {
                 req,
                 res,
             );
+        } else {
+            throw new I18nError(`error.verification-token-not-recognized`);
         }
     }
 

+ 9 - 1
server/src/api/types/auth.api.graphql

@@ -6,7 +6,7 @@ type Mutation {
     login(username: String!, password: String!, rememberMe: Boolean): LoginResult!
     logout: Boolean!
     "Register a Customer account with the given credentials"
-    registerCustomerAccount(emailAddress: String!, password: String!): Boolean!
+    registerCustomerAccount(input: RegisterCustomerInput!): Boolean!
     "Verify a Customer email address with the token sent to that address"
     verifyCustomerEmailAddress(token: String!, password: String!): LoginResult!
 }
@@ -20,3 +20,11 @@ type CurrentUser {
     identifier: String!
     channelTokens: [String!]!
 }
+
+input RegisterCustomerInput {
+    emailAddress: String!
+    title: String
+    firstName: String
+    lastName: String
+    password: String!
+}

+ 3 - 1
server/src/i18n/messages/en.json

@@ -5,6 +5,7 @@
     "cannot-transition-to-shipping-when-order-is-empty": "Cannot transition Order to the \"ArrangingShipping\" state when it is empty",
     "cannot-transition-to-payment-without-customer": "Cannot transition Order to the \"ArrangingShipping\" state without Customer details",
     "channel-not-found":  "No channel with the token \"{ token }\" exists",
+    "email-address-not-verified": "Please verify this email address before logging in",
     "entity-has-no-translation-in-language": "Translatable entity '{ entityName }' has not been translated into the requested language ({ languageCode })",
     "entity-with-id-not-found": "No { entityName } with the id '{ id }' could be found",
     "forbidden": "This action is forbidden",
@@ -12,6 +13,7 @@
     "order-contents-may-only-be-modified-in-addingitems-state": "Order contents may only be modified when in the \"AddingItems\" state",
     "order-does-not-contain-line-with-id": "This order does not contain an OrderLine with the id { id }",
     "order-item-quantity-must-be-positive": "{ quantity } is not a valid quantity for an OrderItem",
-    "payment-may-only-be-added-in-arrangingpayment-state": "A Payment may only be added when Order is in \"ArrangingPayment\" state"
+    "payment-may-only-be-added-in-arrangingpayment-state": "A Payment may only be added when Order is in \"ArrangingPayment\" state",
+    "verification-token-not-recognized": "Verification token not recognized"
   }
 }

+ 4 - 0
server/src/service/services/auth.service.ts

@@ -11,6 +11,7 @@ import { AnonymousSession } from '../../entity/session/anonymous-session.entity'
 import { AuthenticatedSession } from '../../entity/session/authenticated-session.entity';
 import { Session } from '../../entity/session/session.entity';
 import { User } from '../../entity/user/user.entity';
+import { I18nError } from '../../i18n/i18n-error';
 import { PasswordCiper } from '../helpers/password-cipher/password-ciper';
 
 import { OrderService } from './order.service';
@@ -44,6 +45,9 @@ export class AuthService {
         if (!passwordMatches) {
             throw new UnauthorizedException();
         }
+        if (this.configService.authOptions.requireVerification && !user.verified) {
+            throw new I18nError(`error.email-address-not-verified`);
+        }
         await this.deleteSessionsByUser(user);
         if (ctx.session && ctx.session.activeOrder) {
             await this.deleteSessionsByActiveOrder(ctx.session && ctx.session.activeOrder);

+ 9 - 7
server/src/service/services/customer.service.ts

@@ -3,6 +3,7 @@ import { InjectConnection } from '@nestjs/typeorm';
 import {
     CreateAddressInput,
     CreateCustomerInput,
+    RegisterCustomerInput,
     UpdateAddressInput,
     UpdateCustomerInput,
 } from 'shared/generated-types';
@@ -79,13 +80,14 @@ export class CustomerService {
         return this.connection.getRepository(Customer).save(customer);
     }
 
-    async registerCustomerAccount(
-        ctx: RequestContext,
-        emailAddress: string,
-        password: string,
-    ): Promise<Customer> {
-        const customer = await this.createOrUpdate({ emailAddress });
-        const user = await this.userService.createCustomerUser(emailAddress, password);
+    async registerCustomerAccount(ctx: RequestContext, input: RegisterCustomerInput): Promise<Customer> {
+        const customer = await this.createOrUpdate({
+            emailAddress: input.emailAddress,
+            title: input.title || '',
+            firstName: input.firstName || '',
+            lastName: input.lastName || '',
+        });
+        const user = await this.userService.createCustomerUser(input.emailAddress, input.password);
         customer.user = user;
         await this.connection.getRepository(Customer).save(customer);
         if (!user.verified) {

+ 5 - 3
server/src/service/services/user.service.ts

@@ -36,7 +36,8 @@ export class UserService {
         }
         user.passwordHash = await this.passwordCipher.hash(password);
         user.identifier = identifier;
-        user.roles = [await this.roleService.getCustomerRole()];
+        const customerRole = await this.roleService.getCustomerRole();
+        user.roles = [customerRole];
         return this.connection.manager.save(user);
     }
 
@@ -53,8 +54,9 @@ export class UserService {
         const user = await this.connection.getRepository(User).findOne({
             where: { verificationToken },
         });
-        if (user && this.passwordCipher.check(password, user.passwordHash)) {
-            if (this.verifyVerificationToken(verificationToken)) {
+        if (user) {
+            const passwordMatches = await this.passwordCipher.check(password, user.passwordHash);
+            if (passwordMatches && this.verifyVerificationToken(verificationToken)) {
                 user.verificationToken = null;
                 user.verified = true;
                 await this.connection.getRepository(User).save(user);

+ 10 - 4
shared/generated-types.ts

@@ -950,6 +950,14 @@ export interface CreateAssetInput {
     file: Upload;
 }
 
+export interface RegisterCustomerInput {
+    emailAddress: string;
+    title?: string | null;
+    firstName?: string | null;
+    lastName?: string | null;
+    password: string;
+}
+
 export interface CreateChannelInput {
     code: string;
     token: string;
@@ -1412,8 +1420,7 @@ export interface LoginMutationArgs {
     rememberMe?: boolean | null;
 }
 export interface RegisterCustomerAccountMutationArgs {
-    emailAddress: string;
-    password: string;
+    input: RegisterCustomerInput;
 }
 export interface VerifyCustomerEmailAddressMutationArgs {
     token: string;
@@ -3738,8 +3745,7 @@ export namespace MutationResolvers {
         RegisterCustomerAccountArgs
     >;
     export interface RegisterCustomerAccountArgs {
-        emailAddress: string;
-        password: string;
+        input: RegisterCustomerInput;
     }
 
     export type VerifyCustomerEmailAddressResolver<R = LoginResult, Parent = any, Context = any> = Resolver<

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff