mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 01:48:12 +00:00
feat: add shipping line companies management
- Implement ShippingLineCompaniesService for registering and managing shipping line companies. - Create ResendActivationAction component for resending activation links to shipping lines. - Develop ShippingLineCompaniesPage for listing and registering shipping lines with validation. - Introduce shippingLineCompanies.service for API interactions related to shipping lines. - Define types for shipping line companies, including registration and pagination. - Add placeholder pages for shipping line portal, including home, bookings, help, invoices, and settings.
This commit is contained in:
@@ -89,6 +89,28 @@ export class ForgotPasswordService {
|
||||
.getOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Active account by id, WITHOUT requiring an existing credential.
|
||||
*
|
||||
* {@link activeUserQuery} inner-joins an active `user_credentials` row, which
|
||||
* is right for a *reset*: it stops a staff-triggered link from reactivating a
|
||||
* suspended account. But an account that has never set a password has no
|
||||
* credential row yet, so that join excludes exactly the accounts a first-time
|
||||
* *activation* link is for — shipping lines are created deliberately without
|
||||
* one (see ShippingLineCompaniesService.register).
|
||||
*
|
||||
* The `isActive` gate is kept; only the credential requirement is dropped.
|
||||
*/
|
||||
async resolveActivatableUserById(userId: string): Promise<User | null> {
|
||||
if (!userId) return null;
|
||||
return await this.userRepository
|
||||
.createQueryBuilder("u")
|
||||
.where("u.isActive = true")
|
||||
.andWhere("u.id = :userId", { userId })
|
||||
.orderBy("u.createdAt", "DESC")
|
||||
.getOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base query for accounts eligible to reset. `.where()` is claimed here so
|
||||
* callers must use `.andWhere()` — TypeORM's `.where()` resets the clause,
|
||||
@@ -233,9 +255,22 @@ export class ForgotPasswordService {
|
||||
"This password-reset link is invalid or has expired. Request a new one.",
|
||||
);
|
||||
|
||||
const user = await this.resolveActiveUserById(userId);
|
||||
// Credential-less on purpose: this resolves links for *setting* a password,
|
||||
// which includes first-time activation of an account that has never had one
|
||||
// (shipping lines are created without a credential row). Requiring one here
|
||||
// rejected a perfectly valid activation link before its token was ever
|
||||
// checked. The ticket checks below are what actually authorise the reset.
|
||||
const user = await this.resolveActivatableUserById(userId);
|
||||
const identifier = user && this.identifierFor(user);
|
||||
if (!user || !identifier) throw invalid;
|
||||
if (!user || !identifier) {
|
||||
// Logged because the early return above bypasses the rejection warning
|
||||
// below — without this, an account that fails the lookup produces no
|
||||
// diagnostic at all and looks identical to a bad token.
|
||||
this.logger.warn(
|
||||
`Reset link rejected for user ${userId} — no active account or no usable identifier`,
|
||||
);
|
||||
throw invalid;
|
||||
}
|
||||
|
||||
const verification = await this.dataSource
|
||||
.getRepository(UserVerification)
|
||||
|
||||
Reference in New Issue
Block a user