feat: add accounts and movies tables in migrations

- Created migration for accounts table with fields: id, username, password, role_id, created_at, updated_at.
- Created migration for movies table with fields: id, title, overview, poster_path, backdrop_path, release_date, tmdb_id.

refactor: update package.json scripts and dependencies

- Changed dev script to use bun instead of tsx.
- Added build:migrate script for migration.
- Updated devDependencies for bun and oxlint.

fix: refactor database connection and migration execution

- Updated PgDatabase to use SQL from bun.
- Refactored migration execution logic to read SQL files and execute them.

feat: implement account creation and validation logic

- Updated AccountEntity to use username instead of email.
- Added validation for username format and password strength.
- Implemented account repository methods for finding by username and inserting accounts.

test: add tests for account entity, repository, and service

- Created tests for AccountEntity to validate username and password.
- Added tests for AccountRepository to ensure correct database interactions.
- Implemented tests for AccountService to validate registration and login logic.

chore: remove outdated tests and files

- Deleted old tests related to email-based account management.
- Cleaned up unused imports and files to streamline the codebase.
This commit is contained in:
2025-10-02 20:54:41 +00:00
parent 91c14f750e
commit aaa0ca5a54
28 changed files with 617 additions and 654 deletions

View File

@@ -1,30 +1,22 @@
import bcrypt from "bcrypt";
import {
InvalidEmailFormatError,
InvalidUsernameFormatError,
WeakPasswordError,
} from "../errors/AccountErrors";
import {
EMAIL_REGEX,
MAX_USERNAME_LENGTH,
MIN_PASSWORD_LENGTH,
MIN_USERNAME_LENGTH,
} from "../validation/AccountValidation";
export class AccountEntity {
constructor(
public readonly id: string,
public readonly email: string,
public readonly id: number,
public readonly username: string,
private password: string,
public readonly roleId: number,
public readonly createdAt: Date,
public readonly updatedAt: Date,
) {
this.validateEmail(email);
}
private validateEmail(email: string): void {
if (!EMAIL_REGEX.test(email)) {
throw new InvalidEmailFormatError(email);
}
}
) {}
private static validatePassword(password: string): void {
if (password.length < MIN_PASSWORD_LENGTH) {
@@ -32,26 +24,41 @@ export class AccountEntity {
}
}
public verifyPassword(plainPassword: string): boolean {
return bcrypt.compareSync(plainPassword, this.password);
private static validateUsername(username: string): void {
if (
username.length < MIN_USERNAME_LENGTH ||
username.length > MAX_USERNAME_LENGTH
) {
throw new InvalidUsernameFormatError(username);
}
}
public async verifyPassword(plainPassword: string): Promise<boolean> {
return await Bun.password.verify(plainPassword, this.password);
}
public get hashedPassword(): string {
return this.password;
}
static create(email: string, password: string): AccountEntity {
static async create(
username: string,
password: string,
): Promise<CreateAccountEntity> {
AccountEntity.validatePassword(password);
AccountEntity.validateUsername(username);
const now = new Date();
const id = crypto.randomUUID();
const hashedPassword = bcrypt.hashSync(password, 10);
const hashedPassword = await Bun.password.hash(password);
return new AccountEntity(id, email, hashedPassword, 1, now, now);
return {
username,
hashedPassword,
roleId: 1,
};
}
}
export type CreateAccountDto = {
email: string;
password: string;
};
export type CreateAccountEntity = Omit<
AccountEntity,
"id" | "verifyPassword" | "createdAt" | "updatedAt"
>;