remove demo code
This commit is contained in:
265
adapters/bootstrap/SeedDemoUsers.ts
Normal file
265
adapters/bootstrap/SeedDemoUsers.ts
Normal file
@@ -0,0 +1,265 @@
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import type { IAuthRepository } from '@core/identity/domain/repositories/IAuthRepository';
|
||||
import type { IPasswordHashingService } from '@core/identity/domain/services/PasswordHashingService';
|
||||
import type { IAdminUserRepository } from '@core/admin/domain/repositories/IAdminUserRepository';
|
||||
import { User } from '@core/identity/domain/entities/User';
|
||||
import { AdminUser } from '@core/admin/domain/entities/AdminUser';
|
||||
import { EmailAddress } from '@core/identity/domain/value-objects/EmailAddress';
|
||||
import { UserId } from '@core/identity/domain/value-objects/UserId';
|
||||
import { Email } from '@core/admin/domain/value-objects/Email';
|
||||
import { PasswordHash } from '@core/identity/domain/value-objects/PasswordHash';
|
||||
import { stableUuidFromSeedKey } from './racing/SeedIdHelper';
|
||||
|
||||
interface DemoUserSpec {
|
||||
email: string;
|
||||
password: string;
|
||||
needsAdminUser: boolean;
|
||||
needsPrimaryDriverId: boolean;
|
||||
roles: string[];
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* SeedDemoUsers - Creates predefined demo users for testing and development
|
||||
*
|
||||
* This class creates a canonical set of demo users with fixed emails and passwords.
|
||||
* It is idempotent and supports force reseeding via environment variables.
|
||||
*/
|
||||
export class SeedDemoUsers {
|
||||
private readonly demoUserSpecs: DemoUserSpec[] = [
|
||||
{
|
||||
email: 'demo.driver@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: false,
|
||||
needsPrimaryDriverId: true,
|
||||
roles: ['user'],
|
||||
displayName: 'John Driver',
|
||||
},
|
||||
{
|
||||
email: 'demo.sponsor@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: false,
|
||||
needsPrimaryDriverId: false,
|
||||
roles: ['user'],
|
||||
displayName: 'Jane Sponsor',
|
||||
},
|
||||
{
|
||||
email: 'demo.owner@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: true,
|
||||
needsPrimaryDriverId: true,
|
||||
roles: ['owner'],
|
||||
displayName: 'Alice Owner',
|
||||
},
|
||||
{
|
||||
email: 'demo.steward@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: true,
|
||||
needsPrimaryDriverId: true,
|
||||
roles: ['user'],
|
||||
displayName: 'Bob Steward',
|
||||
},
|
||||
{
|
||||
email: 'demo.admin@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: true,
|
||||
needsPrimaryDriverId: true,
|
||||
roles: ['admin'],
|
||||
displayName: 'Charlie Admin',
|
||||
},
|
||||
{
|
||||
email: 'demo.systemowner@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: true,
|
||||
needsPrimaryDriverId: true,
|
||||
roles: ['admin'],
|
||||
displayName: 'Diana SystemOwner',
|
||||
},
|
||||
{
|
||||
email: 'demo.superadmin@example.com',
|
||||
password: 'Demo1234!',
|
||||
needsAdminUser: true,
|
||||
needsPrimaryDriverId: true,
|
||||
roles: ['admin'],
|
||||
displayName: 'Edward SuperAdmin',
|
||||
},
|
||||
];
|
||||
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly authRepository: IAuthRepository,
|
||||
private readonly passwordHashingService: IPasswordHashingService,
|
||||
private readonly adminUserRepository: IAdminUserRepository,
|
||||
) {}
|
||||
|
||||
private getApiPersistence(): 'postgres' | 'inmemory' {
|
||||
const configured = process.env.GRIDPILOT_API_PERSISTENCE?.toLowerCase();
|
||||
if (configured === 'postgres' || configured === 'inmemory') {
|
||||
return configured;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return 'inmemory';
|
||||
}
|
||||
|
||||
return process.env.DATABASE_URL ? 'postgres' : 'inmemory';
|
||||
}
|
||||
|
||||
private generateDeterministicId(seedKey: string, persistence: 'postgres' | 'inmemory'): string {
|
||||
if (persistence === 'postgres') {
|
||||
return stableUuidFromSeedKey(seedKey);
|
||||
}
|
||||
return seedKey;
|
||||
}
|
||||
|
||||
private generatePrimaryDriverId(email: string, persistence: 'postgres' | 'inmemory'): string {
|
||||
// Use the email as the seed for the primary driver ID
|
||||
const seedKey = `primary-driver-${email}`;
|
||||
return this.generateDeterministicId(seedKey, persistence);
|
||||
}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const persistence = this.getApiPersistence();
|
||||
|
||||
// Check for force reseed via environment variable
|
||||
const forceReseedRaw = process.env.GRIDPILOT_API_FORCE_RESEED;
|
||||
const forceReseed = forceReseedRaw !== undefined && forceReseedRaw !== '0' && forceReseedRaw.toLowerCase() !== 'false';
|
||||
|
||||
this.logger.info(
|
||||
`[Bootstrap] Demo users seed precheck: forceReseed=${forceReseed}, persistence=${persistence}`,
|
||||
);
|
||||
|
||||
// Check if all demo users already exist
|
||||
let allUsersExist = true;
|
||||
for (const spec of this.demoUserSpecs) {
|
||||
const existingUser = await this.authRepository.findByEmail(EmailAddress.create(spec.email));
|
||||
if (!existingUser) {
|
||||
allUsersExist = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Also check for admin users if needed
|
||||
if (spec.needsAdminUser) {
|
||||
const existingAdmin = await this.adminUserRepository.findByEmail(Email.create(spec.email));
|
||||
if (!existingAdmin) {
|
||||
allUsersExist = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allUsersExist && !forceReseed) {
|
||||
this.logger.info('[Bootstrap] Demo users already exist, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceReseed) {
|
||||
this.logger.info('[Bootstrap] Force reseed enabled - updating existing demo users');
|
||||
} else {
|
||||
this.logger.info('[Bootstrap] Starting demo users seed');
|
||||
}
|
||||
|
||||
// Create or update each demo user
|
||||
for (const spec of this.demoUserSpecs) {
|
||||
await this.createOrUpdateDemoUser(spec, persistence);
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
`[Bootstrap] Demo users seed completed: ${this.demoUserSpecs.length} users processed`,
|
||||
);
|
||||
}
|
||||
|
||||
private async createOrUpdateDemoUser(spec: DemoUserSpec, persistence: 'postgres' | 'inmemory'): Promise<void> {
|
||||
const userId = this.generateDeterministicId(`demo-user-${spec.email}`, persistence);
|
||||
|
||||
// Check if user exists
|
||||
const existingUser = await this.authRepository.findByEmail(EmailAddress.create(spec.email));
|
||||
|
||||
// Hash the password
|
||||
const passwordHash = await this.passwordHashingService.hash(spec.password);
|
||||
|
||||
if (existingUser) {
|
||||
// Update existing user
|
||||
const rehydrateProps: {
|
||||
id: string;
|
||||
displayName: string;
|
||||
email?: string;
|
||||
passwordHash?: PasswordHash;
|
||||
primaryDriverId?: string;
|
||||
} = {
|
||||
id: userId,
|
||||
displayName: spec.displayName,
|
||||
email: spec.email,
|
||||
passwordHash: PasswordHash.fromHash(passwordHash),
|
||||
};
|
||||
|
||||
if (spec.needsPrimaryDriverId) {
|
||||
rehydrateProps.primaryDriverId = this.generatePrimaryDriverId(spec.email, persistence);
|
||||
}
|
||||
|
||||
const updatedUser = User.rehydrate(rehydrateProps);
|
||||
|
||||
await this.authRepository.save(updatedUser);
|
||||
this.logger.debug(`[Bootstrap] Updated demo user: ${spec.email}`);
|
||||
} else {
|
||||
// Create new user
|
||||
const createProps: {
|
||||
id: UserId;
|
||||
displayName: string;
|
||||
email?: string;
|
||||
passwordHash?: PasswordHash;
|
||||
primaryDriverId?: string;
|
||||
} = {
|
||||
id: UserId.fromString(userId),
|
||||
displayName: spec.displayName,
|
||||
email: spec.email,
|
||||
passwordHash: PasswordHash.fromHash(passwordHash),
|
||||
};
|
||||
|
||||
if (spec.needsPrimaryDriverId) {
|
||||
createProps.primaryDriverId = this.generatePrimaryDriverId(spec.email, persistence);
|
||||
}
|
||||
|
||||
const user = User.create(createProps);
|
||||
|
||||
await this.authRepository.save(user);
|
||||
this.logger.debug(`[Bootstrap] Created demo user: ${spec.email}`);
|
||||
}
|
||||
|
||||
// Handle admin user if needed
|
||||
if (spec.needsAdminUser) {
|
||||
const adminUserId = this.generateDeterministicId(`demo-admin-${spec.email}`, persistence);
|
||||
const existingAdmin = await this.adminUserRepository.findByEmail(Email.create(spec.email));
|
||||
|
||||
if (existingAdmin) {
|
||||
// Admin user exists, no update needed for now
|
||||
this.logger.debug(`[Bootstrap] Admin user already exists: ${spec.email}`);
|
||||
} else {
|
||||
// Create admin user
|
||||
const adminCreateProps: {
|
||||
id: string;
|
||||
email: string;
|
||||
roles: string[];
|
||||
status: string;
|
||||
displayName: string;
|
||||
primaryDriverId?: string;
|
||||
} = {
|
||||
id: adminUserId,
|
||||
email: spec.email,
|
||||
roles: spec.roles,
|
||||
status: 'active',
|
||||
displayName: spec.displayName,
|
||||
};
|
||||
|
||||
if (spec.needsPrimaryDriverId) {
|
||||
adminCreateProps.primaryDriverId = this.generatePrimaryDriverId(spec.email, persistence);
|
||||
}
|
||||
|
||||
const adminUser = AdminUser.create(adminCreateProps);
|
||||
|
||||
await this.adminUserRepository.create(adminUser);
|
||||
this.logger.debug(`[Bootstrap] Created admin user: ${spec.email} with roles: ${spec.roles.join(', ')}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user