From 3954db87729de6b5158f308803bbc819cb64225b Mon Sep 17 00:00:00 2001 From: Pat Plunkett Date: Thu, 21 Oct 2021 14:21:26 -0700 Subject: [PATCH 1/5] Add phone number to user accounts. This change adds a phone number to the user_account table, adds the corresponding migration, updates the swagger API, and adds a basic form for updating the phone number on the account settings page. --- backend/core/src/auth/entities/user.entity.ts | 7 ++- .../1634848388161-add-phone-number.ts | 14 ++++++ backend/core/types/src/backend-swagger.ts | 15 +++++++ sites/public/pages/account/edit.tsx | 44 +++++++++++++++++++ ui-components/src/locales/general.json | 1 + 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 backend/core/src/migration/1634848388161-add-phone-number.ts diff --git a/backend/core/src/auth/entities/user.entity.ts b/backend/core/src/auth/entities/user.entity.ts index 24d7afd74d..594a3541bd 100644 --- a/backend/core/src/auth/entities/user.entity.ts +++ b/backend/core/src/auth/entities/user.entity.ts @@ -12,7 +12,7 @@ import { } from "typeorm" import { Listing } from "../../listings/entities/listing.entity" import { Expose, Type } from "class-transformer" -import { IsDate, IsEmail, IsEnum, IsOptional, IsString, IsUUID, MaxLength } from "class-validator" +import { IsDate, IsEmail, IsEnum, IsOptional, IsPhoneNumber, IsString, IsUUID, MaxLength } from "class-validator" import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum" import { ApiProperty } from "@nestjs/swagger" import { Language } from "../../shared/types/language-enum" @@ -75,6 +75,11 @@ export class User { @Type(() => Date) dob?: Date | null + @Column("varchar", { nullable: true }) + @Expose() + @IsPhoneNumber(null) + phoneNumber?: string + @CreateDateColumn() @Expose() @IsDate({ groups: [ValidationsGroupsEnum.default] }) diff --git a/backend/core/src/migration/1634848388161-add-phone-number.ts b/backend/core/src/migration/1634848388161-add-phone-number.ts new file mode 100644 index 0000000000..a8d0784400 --- /dev/null +++ b/backend/core/src/migration/1634848388161-add-phone-number.ts @@ -0,0 +1,14 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class addPhoneNumber1634848388161 implements MigrationInterface { + name = 'addPhoneNumber1634848388161' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_accounts" ADD "phone_number" character varying`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_accounts" DROP COLUMN "phone_number"`); + } + +} diff --git a/backend/core/types/src/backend-swagger.ts b/backend/core/types/src/backend-swagger.ts index f89c5473ef..2ea0f85586 100644 --- a/backend/core/types/src/backend-swagger.ts +++ b/backend/core/types/src/backend-swagger.ts @@ -3628,6 +3628,9 @@ export interface User { /** */ dob?: Date + /** */ + phoneNumber?: string + /** */ createdAt: Date @@ -3671,6 +3674,9 @@ export interface UserCreate { /** */ dob?: Date + + /** */ + phoneNumber?: string } export interface UserBasic { @@ -3707,6 +3713,9 @@ export interface UserBasic { /** */ dob?: Date + /** */ + phoneNumber?: string + /** */ createdAt: Date @@ -3798,6 +3807,9 @@ export interface UserUpdate { /** */ dob?: Date + + /** */ + phoneNumber?: string } export interface UserFilterParams { @@ -3857,6 +3869,9 @@ export interface UserInvite { /** */ dob?: Date + + /** */ + phoneNumber?: string } export interface JurisdictionCreate { diff --git a/sites/public/pages/account/edit.tsx b/sites/public/pages/account/edit.tsx index 1de6f191ae..43f18c950b 100644 --- a/sites/public/pages/account/edit.tsx +++ b/sites/public/pages/account/edit.tsx @@ -34,6 +34,7 @@ const Edit = () => { const [passwordAlert, setPasswordAlert] = useState() const [nameAlert, setNameAlert] = useState() const [dobAlert, setDobAlert] = useState() + const [phoneNumberAlert, setPhoneNumberAlert] = useState() const [emailAlert, setEmailAlert] = useState() const MIN_PASSWORD_LENGTH = 8 const password = useRef({}) @@ -90,6 +91,20 @@ const Edit = () => { } } + const onPhoneNumberSubmit = async (data: { phoneNumber: string }) => { + const { phoneNumber } = data + setPhoneNumberAlert(null) + try { + await userService.update({ + body: { ...profile, phoneNumber }, + }) + setPhoneNumberAlert({ type: "success", message: `${t("account.settings.alerts.phoneNumberSuccess")}` }) + } catch (err) { + setPhoneNumberAlert({ type: "alert", message: `${t("account.settings.alerts.genericError")}` }) + console.warn(err) + } + } + const onPasswordSubmit = async (data: { password: string passwordConfirmation: string @@ -233,6 +248,35 @@ const Edit = () => { +
+ {phoneNumberAlert && ( + setPhoneNumberAlert(null)} + inverted + closeable + > + {phoneNumberAlert.message} + + )} +
+ +
+ +
+
+
{passwordAlert && ( Date: Thu, 21 Oct 2021 21:32:39 +0000 Subject: [PATCH 2/5] Fix code style issues with Prettier --- backend/core/src/auth/entities/user.entity.ts | 11 ++++++++++- .../migration/1634848388161-add-phone-number.ts | 17 ++++++++--------- sites/public/pages/account/edit.tsx | 10 ++++++++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/backend/core/src/auth/entities/user.entity.ts b/backend/core/src/auth/entities/user.entity.ts index 594a3541bd..a755a36fb0 100644 --- a/backend/core/src/auth/entities/user.entity.ts +++ b/backend/core/src/auth/entities/user.entity.ts @@ -12,7 +12,16 @@ import { } from "typeorm" import { Listing } from "../../listings/entities/listing.entity" import { Expose, Type } from "class-transformer" -import { IsDate, IsEmail, IsEnum, IsOptional, IsPhoneNumber, IsString, IsUUID, MaxLength } from "class-validator" +import { + IsDate, + IsEmail, + IsEnum, + IsOptional, + IsPhoneNumber, + IsString, + IsUUID, + MaxLength, +} from "class-validator" import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum" import { ApiProperty } from "@nestjs/swagger" import { Language } from "../../shared/types/language-enum" diff --git a/backend/core/src/migration/1634848388161-add-phone-number.ts b/backend/core/src/migration/1634848388161-add-phone-number.ts index a8d0784400..34e26f2d23 100644 --- a/backend/core/src/migration/1634848388161-add-phone-number.ts +++ b/backend/core/src/migration/1634848388161-add-phone-number.ts @@ -1,14 +1,13 @@ -import {MigrationInterface, QueryRunner} from "typeorm"; +import { MigrationInterface, QueryRunner } from "typeorm" export class addPhoneNumber1634848388161 implements MigrationInterface { - name = 'addPhoneNumber1634848388161' + name = "addPhoneNumber1634848388161" - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_accounts" ADD "phone_number" character varying`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "user_accounts" DROP COLUMN "phone_number"`); - } + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_accounts" ADD "phone_number" character varying`) + } + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_accounts" DROP COLUMN "phone_number"`) + } } diff --git a/sites/public/pages/account/edit.tsx b/sites/public/pages/account/edit.tsx index 43f18c950b..bb6e82ffd2 100644 --- a/sites/public/pages/account/edit.tsx +++ b/sites/public/pages/account/edit.tsx @@ -98,9 +98,15 @@ const Edit = () => { await userService.update({ body: { ...profile, phoneNumber }, }) - setPhoneNumberAlert({ type: "success", message: `${t("account.settings.alerts.phoneNumberSuccess")}` }) + setPhoneNumberAlert({ + type: "success", + message: `${t("account.settings.alerts.phoneNumberSuccess")}`, + }) } catch (err) { - setPhoneNumberAlert({ type: "alert", message: `${t("account.settings.alerts.genericError")}` }) + setPhoneNumberAlert({ + type: "alert", + message: `${t("account.settings.alerts.genericError")}`, + }) console.warn(err) } } From eeb5c6f71038143dfed8e60558854beb6db8bcf5 Mon Sep 17 00:00:00 2001 From: Pat Plunkett Date: Mon, 25 Oct 2021 15:37:30 -0700 Subject: [PATCH 3/5] Remove sites and ui-component changes. We only need the backend changes, initially. --- sites/public/pages/account/edit.tsx | 50 -------------------------- ui-components/src/locales/general.json | 1 - 2 files changed, 51 deletions(-) diff --git a/sites/public/pages/account/edit.tsx b/sites/public/pages/account/edit.tsx index bb6e82ffd2..1de6f191ae 100644 --- a/sites/public/pages/account/edit.tsx +++ b/sites/public/pages/account/edit.tsx @@ -34,7 +34,6 @@ const Edit = () => { const [passwordAlert, setPasswordAlert] = useState() const [nameAlert, setNameAlert] = useState() const [dobAlert, setDobAlert] = useState() - const [phoneNumberAlert, setPhoneNumberAlert] = useState() const [emailAlert, setEmailAlert] = useState() const MIN_PASSWORD_LENGTH = 8 const password = useRef({}) @@ -91,26 +90,6 @@ const Edit = () => { } } - const onPhoneNumberSubmit = async (data: { phoneNumber: string }) => { - const { phoneNumber } = data - setPhoneNumberAlert(null) - try { - await userService.update({ - body: { ...profile, phoneNumber }, - }) - setPhoneNumberAlert({ - type: "success", - message: `${t("account.settings.alerts.phoneNumberSuccess")}`, - }) - } catch (err) { - setPhoneNumberAlert({ - type: "alert", - message: `${t("account.settings.alerts.genericError")}`, - }) - console.warn(err) - } - } - const onPasswordSubmit = async (data: { password: string passwordConfirmation: string @@ -254,35 +233,6 @@ const Edit = () => { -
- {phoneNumberAlert && ( - setPhoneNumberAlert(null)} - inverted - closeable - > - {phoneNumberAlert.message} - - )} -
- -
- -
-
-
{passwordAlert && ( Date: Tue, 26 Oct 2021 10:23:00 -0700 Subject: [PATCH 4/5] Add a test for setting a user's phone number. This test exercises setting the user's phone number through the backend APIs. --- backend/core/test/user/user.e2e-spec.ts | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/backend/core/test/user/user.e2e-spec.ts b/backend/core/test/user/user.e2e-spec.ts index 51e046de7b..701a22c3af 100644 --- a/backend/core/test/user/user.e2e-spec.ts +++ b/backend/core/test/user/user.e2e-spec.ts @@ -273,6 +273,37 @@ describe("Users", () => { .expect(403) }) + it("should allow a user to modify their phone number", async () => { + const user = (await supertest(app.getHttpServer()) + .get("/user") + .set(...setAuthorization(userAccessToken)) + .expect(200)).body + const testPhoneNumber = "1234567890" + const userUpdateDto: UserUpdateDto = { + id: user.id, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + confirmedAt: user.confirmedAt, + jurisdictions: user.jurisdictions.map((jurisdiction) => ({ + id: jurisdiction.id, + })), + phoneNumber: testPhoneNumber, + } + + await supertest(app.getHttpServer()) + .put(`/user/${user.id}`) + .set(...setAuthorization(userAccessToken)) + .send(userUpdateDto) + .expect(200) + const updatedUser = (await supertest(app.getHttpServer()) + .get("/user") + .set(...setAuthorization(userAccessToken)) + .expect(200)).body + + expect(updatedUser.phoneNumber).toEqual(testPhoneNumber) + }) + it("should allow user to resend confirmation", async () => { const userCreateDto: UserCreateDto = { password: "Abcdef1!", From ebdb237efb8976512219ed8e013c1d1799146be2 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 26 Oct 2021 17:27:47 +0000 Subject: [PATCH 5/5] Fix code style issues with Prettier --- backend/core/test/user/user.e2e-spec.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/core/test/user/user.e2e-spec.ts b/backend/core/test/user/user.e2e-spec.ts index 701a22c3af..2e2ba8117a 100644 --- a/backend/core/test/user/user.e2e-spec.ts +++ b/backend/core/test/user/user.e2e-spec.ts @@ -274,10 +274,12 @@ describe("Users", () => { }) it("should allow a user to modify their phone number", async () => { - const user = (await supertest(app.getHttpServer()) + const user = ( + await supertest(app.getHttpServer()) .get("/user") .set(...setAuthorization(userAccessToken)) - .expect(200)).body + .expect(200) + ).body const testPhoneNumber = "1234567890" const userUpdateDto: UserUpdateDto = { id: user.id, @@ -296,10 +298,12 @@ describe("Users", () => { .set(...setAuthorization(userAccessToken)) .send(userUpdateDto) .expect(200) - const updatedUser = (await supertest(app.getHttpServer()) + const updatedUser = ( + await supertest(app.getHttpServer()) .get("/user") .set(...setAuthorization(userAccessToken)) - .expect(200)).body + .expect(200) + ).body expect(updatedUser.phoneNumber).toEqual(testPhoneNumber) })