diff --git a/apps/edr-freight-api/src/migrations/1820000000011-DropEmailPhoneFromExternalProfiles.ts b/apps/edr-freight-api/src/migrations/1820000000011-DropEmailPhoneFromExternalProfiles.ts new file mode 100644 index 000000000..757c20720 --- /dev/null +++ b/apps/edr-freight-api/src/migrations/1820000000011-DropEmailPhoneFromExternalProfiles.ts @@ -0,0 +1,33 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +/** + * Contact email/phone for an external profile is sourced from IAM (the user's + * identity) and from the company record, so the duplicated `email`/`phone` + * columns on external_profiles are redundant and are dropped. Dropping `email` + * also removes its UNIQUE constraint. + */ +export class DropEmailPhoneFromExternalProfiles1820000000011 + implements MigrationInterface +{ + name = 'DropEmailPhoneFromExternalProfiles1820000000011'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE freight.external_profiles DROP COLUMN IF EXISTS email;`, + ); + await queryRunner.query( + `ALTER TABLE freight.external_profiles DROP COLUMN IF EXISTS phone;`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + // Re-added as nullable (the original email was UNIQUE NOT NULL) since the + // dropped values cannot be recovered to satisfy those constraints. + await queryRunner.query( + `ALTER TABLE freight.external_profiles ADD COLUMN IF NOT EXISTS email varchar(150);`, + ); + await queryRunner.query( + `ALTER TABLE freight.external_profiles ADD COLUMN IF NOT EXISTS phone varchar(20);`, + ); + } +} diff --git a/apps/edr-freight-api/src/modules/companies/companies.service.ts b/apps/edr-freight-api/src/modules/companies/companies.service.ts index 7858945e2..a838495d5 100644 --- a/apps/edr-freight-api/src/modules/companies/companies.service.ts +++ b/apps/edr-freight-api/src/modules/companies/companies.service.ts @@ -139,10 +139,12 @@ export class CompaniesService { } } - const existingProfile = await this.profilesRepo.findByEmail(identity.email); + const existingProfile = await this.profilesRepo.findByUserId( + identity.userId, + ); if (existingProfile) { throw new ConflictException( - `Profile with email ${identity.email} already exists`, + `Profile for user ${identity.userId} already exists`, ); } @@ -176,8 +178,6 @@ export class CompaniesService { companyId: company.id, firstName: identity.firstName, lastName: identity.lastName, - email: identity.email, - phone: normalizeE164(identity.phone) ?? identity.phone, jobTitle: dto.jobTitle ?? null, isPrimaryContact: dto.isPrimaryContact ?? true, activeProfileType, @@ -251,15 +251,6 @@ export class CompaniesService { return this.getCompanyInfoByUserId(identity.userId); } - // A profile may exist for the same email under a different IAM id — block - // duplicates as the final create does. - const byEmail = await this.profilesRepo.findByEmail(identity.email); - if (byEmail) { - throw new ConflictException( - `Profile with email ${identity.email} already exists`, - ); - } - const allowedTypes = this.getProfileTypeForCompanyType(companyType); const chosenTypes = roles.filter((t) => allowedTypes.includes(t)); const activeProfileType = @@ -284,8 +275,6 @@ export class CompaniesService { companyId: company.id, firstName: identity.firstName, lastName: identity.lastName, - email: identity.email, - phone: normalizeE164(identity.phone) ?? identity.phone, isPrimaryContact: true, activeProfileType, onboardingStep: "company", @@ -637,10 +626,10 @@ export class CompaniesService { async createProfile(dto: CreateExternalProfileDto): Promise { await this.findCompanyById(dto.companyId); - const existing = await this.profilesRepo.findByEmail(dto.email); + const existing = await this.profilesRepo.findByUserId(dto.userId); if (existing) { throw new ConflictException( - `Profile with email ${dto.email} already exists`, + `Profile for user ${dto.userId} already exists`, ); } diff --git a/apps/edr-freight-api/src/modules/companies/dto/create-external-profile.dto.ts b/apps/edr-freight-api/src/modules/companies/dto/create-external-profile.dto.ts index 7a9b94c44..ff0f94495 100644 --- a/apps/edr-freight-api/src/modules/companies/dto/create-external-profile.dto.ts +++ b/apps/edr-freight-api/src/modules/companies/dto/create-external-profile.dto.ts @@ -1,5 +1,4 @@ -import { IsString, IsNotEmpty, IsOptional, IsEmail, MaxLength, IsBoolean, IsUUID } from 'class-validator'; -import { IsValidPhone } from '../../../common/validators/is-phone-number.validator'; +import { IsString, IsNotEmpty, IsOptional, MaxLength, IsBoolean, IsUUID } from 'class-validator'; export class CreateExternalProfileDto { @IsUUID() @@ -20,16 +19,6 @@ export class CreateExternalProfileDto { @MaxLength(100) lastName!: string; - @IsEmail() - @IsNotEmpty() - email!: string; - - @IsOptional() - @IsString() - @MaxLength(20) - @IsValidPhone() - phone?: string; - @IsOptional() @IsString() @MaxLength(50) diff --git a/apps/edr-freight-api/src/modules/companies/dto/response-external-profile.dto.ts b/apps/edr-freight-api/src/modules/companies/dto/response-external-profile.dto.ts index 7e17bcc60..256641074 100644 --- a/apps/edr-freight-api/src/modules/companies/dto/response-external-profile.dto.ts +++ b/apps/edr-freight-api/src/modules/companies/dto/response-external-profile.dto.ts @@ -10,8 +10,6 @@ export class ResponseExternalProfileDto { companyId: string; firstName: string; lastName: string; - email: string; - phone?: string | null; nationalId?: string | null; jobTitle?: string | null; isPrimaryContact: boolean; @@ -34,8 +32,6 @@ export class ResponseExternalProfileDto { this.companyId = profile.companyId; this.firstName = profile.firstName; this.lastName = profile.lastName; - this.email = profile.email; - this.phone = profile.phone; this.nationalId = profile.nationalId; this.jobTitle = profile.jobTitle; this.isPrimaryContact = profile.isPrimaryContact; diff --git a/apps/edr-freight-api/src/modules/companies/entities/external-profile.entity.ts b/apps/edr-freight-api/src/modules/companies/entities/external-profile.entity.ts index 3b1554cc9..93e499b5e 100644 --- a/apps/edr-freight-api/src/modules/companies/entities/external-profile.entity.ts +++ b/apps/edr-freight-api/src/modules/companies/entities/external-profile.entity.ts @@ -23,12 +23,6 @@ export class ExternalProfile extends BaseEntity { @Column({ name: 'last_name', type: 'varchar', length: 100 }) lastName!: string; - @Column({ name: 'email', type: 'varchar', length: 150, unique: true }) - email!: string; - - @Column({ name: 'phone', type: 'varchar', length: 20, nullable: true }) - phone?: string | null; - @Column({ name: 'national_id', type: 'varchar', length: 50, nullable: true }) nationalId?: string | null; diff --git a/apps/edr-freight-api/src/modules/companies/external-profile.repository.ts b/apps/edr-freight-api/src/modules/companies/external-profile.repository.ts index 581dfd72b..70c05abd7 100644 --- a/apps/edr-freight-api/src/modules/companies/external-profile.repository.ts +++ b/apps/edr-freight-api/src/modules/companies/external-profile.repository.ts @@ -23,8 +23,4 @@ export class ExternalProfileRepository extends BaseRepository { async findByCompanyId(companyId: string): Promise { return this.repository.find({ where: { companyId } as any }); } - - async findByEmail(email: string): Promise { - return this.repository.findOne({ where: { email } as any }); - } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8563e7ec..55a578fc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,10 +86,10 @@ importers: version: 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) '@tria-plc/api-common': specifier: file:../../local-packages/tria-plc-api-common-1.4.3.tgz - version: file:local-packages/tria-plc-api-common-1.4.3.tgz(28ab85b15f2c569b3d04dfa1367528a6) + version: file:local-packages/tria-plc-api-common-1.4.3.tgz(7eb88ce5307a74a35f2916434d2a0c8f) '@tria-plc/iamapi-common': - specifier: file:../../local-packages/tria-plc-iamapi-common-0.7.3.tgz - version: file:local-packages/tria-plc-iamapi-common-0.7.3.tgz(578386f46cf99fd4720e3e99f196f69e) + specifier: file:../../local-packages/tria-plc-iamapi-common-0.7.4.tgz + version: file:local-packages/tria-plc-iamapi-common-0.7.4.tgz(578386f46cf99fd4720e3e99f196f69e) amqp-connection-manager: specifier: ^5.0.0 version: 5.0.0(amqplib@2.0.1) @@ -479,10 +479,10 @@ importers: version: 8.1.6 '@tria-plc/api-common': specifier: file:../../local-packages/tria-plc-api-common-1.4.3.tgz - version: file:local-packages/tria-plc-api-common-1.4.3.tgz(d81a2b6a79840fd7ce8c5d0cfc968145) + version: file:local-packages/tria-plc-api-common-1.4.3.tgz(e6b80acddd4bb7fc40e438635b24d1bc) '@tria-plc/iamapi-common': - specifier: file:../../local-packages/tria-plc-iamapi-common-0.7.3.tgz - version: file:local-packages/tria-plc-iamapi-common-0.7.3.tgz(c97ba831ddde82920910406ab5262991) + specifier: file:../../local-packages/tria-plc-iamapi-common-0.7.4.tgz + version: file:local-packages/tria-plc-iamapi-common-0.7.4.tgz(c97ba831ddde82920910406ab5262991) '@types/bcrypt': specifier: ^6.0.0 version: 6.0.0 @@ -4065,9 +4065,9 @@ packages: rxjs: ^7.8.0 typeorm: ^0.3.0 - '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.3.tgz': - resolution: {integrity: sha512-poMG3sm+HmnfNbWNqMDZJMf3pXdc3HHA+o/ay6CA4E6ehLKkO7Np77C6xrCYuGxyDgqqKdmWiFLqKKddkv5rig==, tarball: file:local-packages/tria-plc-iamapi-common-0.7.3.tgz} - version: 0.7.3 + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.4.tgz': + resolution: {integrity: sha512-6Ot921laEp3rZZBXDFX+gL7nPKEyHIRJaHSIP1i+seG20+PCCGA/QHDglcJXSgF5ccnpxBdlxmI/BZbYu7LV/A==, tarball: file:local-packages/tria-plc-iamapi-common-0.7.4.tgz} + version: 0.7.4 engines: {node: '>=20'} peerDependencies: '@nestjs/axios': ^4.0.0 @@ -5211,12 +5211,6 @@ packages: resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} engines: {node: '>=10.0.0'} - batch@0.6.1: - resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} - - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - bcrypt@6.0.0: resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==} engines: {node: '>= 18'} @@ -15197,7 +15191,7 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(28ab85b15f2c569b3d04dfa1367528a6)': + '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(7eb88ce5307a74a35f2916434d2a0c8f)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -15208,7 +15202,7 @@ snapshots: '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/iamapi-common': file:local-packages/tria-plc-iamapi-common-0.7.3.tgz(578386f46cf99fd4720e3e99f196f69e) + '@tria-plc/iamapi-common': file:local-packages/tria-plc-iamapi-common-0.7.4.tgz(578386f46cf99fd4720e3e99f196f69e) argon2: 0.43.1 axios: 1.17.0 change-case: 5.4.4 @@ -15241,7 +15235,7 @@ snapshots: - debug - supports-color - '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(d81a2b6a79840fd7ce8c5d0cfc968145)': + '@tria-plc/api-common@file:local-packages/tria-plc-api-common-1.4.3.tgz(e6b80acddd4bb7fc40e438635b24d1bc)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -15252,7 +15246,7 @@ snapshots: '@nestjs/swagger': 7.4.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/iamapi-common': file:local-packages/tria-plc-iamapi-common-0.7.3.tgz(c97ba831ddde82920910406ab5262991) + '@tria-plc/iamapi-common': file:local-packages/tria-plc-iamapi-common-0.7.4.tgz(c97ba831ddde82920910406ab5262991) argon2: 0.43.1 axios: 1.17.0 change-case: 5.4.4 @@ -15285,7 +15279,7 @@ snapshots: - debug - supports-color - '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.3.tgz(578386f46cf99fd4720e3e99f196f69e)': + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.4.tgz(578386f46cf99fd4720e3e99f196f69e)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -15296,7 +15290,7 @@ snapshots: '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.4.3.tgz(28ab85b15f2c569b3d04dfa1367528a6) + '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.4.3.tgz(7eb88ce5307a74a35f2916434d2a0c8f) api-common: 1.2.2 argon2: 0.43.1 axios: 1.17.0 @@ -15320,7 +15314,7 @@ snapshots: - '@faker-js/faker' - supports-color - '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.3.tgz(c97ba831ddde82920910406ab5262991)': + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-0.7.4.tgz(c97ba831ddde82920910406ab5262991)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -15331,7 +15325,7 @@ snapshots: '@nestjs/swagger': 7.4.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.4.3.tgz(d81a2b6a79840fd7ce8c5d0cfc968145) + '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.4.3.tgz(e6b80acddd4bb7fc40e438635b24d1bc) api-common: 1.2.2 argon2: 0.43.1 axios: 1.17.0 @@ -16718,12 +16712,6 @@ snapshots: basic-ftp@5.3.1: {} - batch@0.6.1: {} - - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - bcrypt@6.0.0: dependencies: node-addon-api: 8.8.0