fix: rm email and phone on exteranl profile

This commit is contained in:
Nathnael
2026-06-25 07:14:29 +00:00
parent 0c461273c8
commit ce5c69acb3
7 changed files with 57 additions and 72 deletions

View File

@@ -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<void> {
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<void> {
// 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);`,
);
}
}

View File

@@ -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<ExternalProfile> {
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`,
);
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -23,8 +23,4 @@ export class ExternalProfileRepository extends BaseRepository<ExternalProfile> {
async findByCompanyId(companyId: string): Promise<ExternalProfile[]> {
return this.repository.find({ where: { companyId } as any });
}
async findByEmail(email: string): Promise<ExternalProfile | null> {
return this.repository.findOne({ where: { email } as any });
}
}

46
pnpm-lock.yaml generated
View File

@@ -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