From cda0238a35fbb5bd0badef148fa8ff468e58c629 Mon Sep 17 00:00:00 2001 From: Feli Date: Thu, 30 May 2024 23:42:26 -0500 Subject: [PATCH 1/4] chore: Remove unused Firebase server configuration file --- lib/configureFirebaseServer.ts | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 lib/configureFirebaseServer.ts diff --git a/lib/configureFirebaseServer.ts b/lib/configureFirebaseServer.ts deleted file mode 100644 index 8df19d9..0000000 --- a/lib/configureFirebaseServer.ts +++ /dev/null @@ -1,28 +0,0 @@ -'use server'; - -import { initializeApp } from 'firebase-admin'; -import { cert, getApp, getApps } from 'firebase-admin/app'; -import { getFirestore, initializeFirestore } from 'firebase-admin/firestore'; - -let app = null; -let firestore = null; -app = !getApps().length - ? initializeApp({ - credential: cert({ - projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!, - clientEmail: process.env.PRIVATE_FIREBASE_CLIENT_EMAIL!, - // Using JSON to handle newline problems when storing the key as a secret in Vercel. See: - // https://github.com/vercel/vercel/issues/749#issuecomment-707515089 - privateKey: JSON.parse(process.env.PRIVATE_FIREBASE_PRIVATE_KEY!), - }), - databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL!, - }) - : getApp(); - -getFirestore().settings({ ignoreUndefinedProperties: true }); - -if (app != null) { - firestore = initializeFirestore(app); -} - -export { firestore }; From 8594ee062a19856321c405548acd709869b25e23 Mon Sep 17 00:00:00 2001 From: Feli Date: Thu, 30 May 2024 23:43:19 -0500 Subject: [PATCH 2/4] feat: Add User entity, AuthRepository, UserRepository, and RegisterUserUseCase This commit adds the following changes: - Added a new file `User.ts` under `api/domain/entities` to define the User entity with properties like email, password, name, createdAt, and updatedAt. - Created `AuthRepository.ts` under `api/domain/repositories` to handle authentication-related operations using Firebase Admin SDK. - Implemented `UserRepository.ts` under `api/domain/repositories` to handle user-related operations using Firebase Admin SDK. - Added `RegisterUserUseCase.ts` under `api/usecases` to handle the registration of a new user by saving the user to the database and creating a user record in Firebase Auth. These changes are necessary to support user registration functionality in the application. --- api/domain/entities/User.ts | 49 +++++++++++++++++++++++ api/domain/repositories/AuthRepository.ts | 28 +++++++++++++ api/domain/repositories/UserRepository.ts | 23 +++++++++++ api/usecases/RegisterUser.ts | 24 +++++++++++ lib/firebase.admin.config.ts | 24 +++++++++++ lib/main.admin.ts | 6 +++ src/app/api/register/route.tsx | 28 +++++++++++++ 7 files changed, 182 insertions(+) create mode 100644 api/domain/entities/User.ts create mode 100644 api/domain/repositories/AuthRepository.ts create mode 100644 api/domain/repositories/UserRepository.ts create mode 100644 api/usecases/RegisterUser.ts create mode 100644 lib/firebase.admin.config.ts create mode 100644 lib/main.admin.ts create mode 100644 src/app/api/register/route.tsx diff --git a/api/domain/entities/User.ts b/api/domain/entities/User.ts new file mode 100644 index 0000000..78a976f --- /dev/null +++ b/api/domain/entities/User.ts @@ -0,0 +1,49 @@ +// domain/entities/User.ts +export class User { + private email: string; + private password: string; + private name: string; + private createdAt: Date; + private updatedAt: Date; + + constructor(email: string, password: string, name: string) { + this.email = email; + this.password = password; + this.name = name; + this.createdAt = new Date(); + this.updatedAt = new Date(); + } + + public getEmail(): string { + return this.email; + } + + public getPassword(): string { + return this.password; + } + + public getName(): string { + return this.name; + } + + public getCreatedAt(): Date { + return this.createdAt; + } + + public getUpdatedAt(): Date { + return this.updatedAt; + } + + public static create(email: string, password: string, name: string): User { + return new User(email, password, name); + } + + public toPlainObject(): { [key: string]: any } { + return { + email: this.email, + name: this.name, + createdAt: this.createdAt.toISOString(), + updatedAt: this.updatedAt.toISOString(), + }; + } +} diff --git a/api/domain/repositories/AuthRepository.ts b/api/domain/repositories/AuthRepository.ts new file mode 100644 index 0000000..1ffe284 --- /dev/null +++ b/api/domain/repositories/AuthRepository.ts @@ -0,0 +1,28 @@ +// domain/repositories/AuthRepository.ts + +import { Auth } from 'firebase-admin/auth'; +import { auth } from '../../../lib/main.admin'; + +export class AuthRepository { + private auth!: Auth; + + constructor() { + this.initializeAuth(); + } + + private async initializeAuth() { + this.auth = await auth(); + } + + public async createUser(email: string, password: string): Promise { + try { + const userRecord = await this.auth.createUser({ + email, + password, + }); + return userRecord; + } catch (error) { + throw new Error('Error creating user: ' + (error as any).message); + } + } +} diff --git a/api/domain/repositories/UserRepository.ts b/api/domain/repositories/UserRepository.ts new file mode 100644 index 0000000..1061aad --- /dev/null +++ b/api/domain/repositories/UserRepository.ts @@ -0,0 +1,23 @@ +import { Firestore } from 'firebase-admin/firestore'; +import { User } from '../entities/User'; +import { firestore } from '../../../lib/main.admin'; + +export class UserRepository { + private db!: Firestore; + + constructor() { + this.initializeFirestore(); + } + + private async initializeFirestore() { + this.db = await firestore(); + } + + public async save(user: User): Promise { + try { + await this.db.collection('users').doc().set(user.toPlainObject()); + } catch (error) { + throw new Error('Error saving user: ' + (error as Error).message); + } + } +} diff --git a/api/usecases/RegisterUser.ts b/api/usecases/RegisterUser.ts new file mode 100644 index 0000000..38a2bc9 --- /dev/null +++ b/api/usecases/RegisterUser.ts @@ -0,0 +1,24 @@ +import { User } from '../domain/entities/User'; +import { AuthRepository } from '../domain/repositories/AuthRepository'; +import { UserRepository } from '../domain/repositories/UserRepository'; + +export class RegisterUserUseCase { + private userRepository: UserRepository; + private authRepository: AuthRepository; + + constructor(userRepository: UserRepository, authRepository: AuthRepository) { + this.userRepository = userRepository; + this.authRepository = authRepository; + } + + public async execute( + userEmail: string, + userPassword: string, + userName: string + ): Promise { + const user = User.create(userEmail, userPassword, userName); + await this.userRepository.save(user); + await this.authRepository.createUser(userEmail, userPassword); + return user; + } +} diff --git a/lib/firebase.admin.config.ts b/lib/firebase.admin.config.ts new file mode 100644 index 0000000..a4f897b --- /dev/null +++ b/lib/firebase.admin.config.ts @@ -0,0 +1,24 @@ +'use server'; +// firebase.config.ts +import { initializeApp, getApps, getApp, cert } from 'firebase-admin/app'; +import { getFirestore as getFirestoreInstance } from 'firebase-admin/firestore'; +import { getAuth as getAuthInstance } from 'firebase-admin/auth'; + +const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!; +const clientEmail = process.env.PRIVATE_FIREBASE_CLIENT_EMAIL!; +const privateKey = JSON.parse(process.env.PRIVATE_FIREBASE_PRIVATE_KEY!); +const databaseURL = process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL!; + +const app = !getApps().length + ? initializeApp({ + credential: cert({ + projectId, + clientEmail, + privateKey, + }), + databaseURL, + }) + : getApp(); + +export const getFirestore = () => getFirestoreInstance(app); +export const getAuth = () => getAuthInstance(app); diff --git a/lib/main.admin.ts b/lib/main.admin.ts new file mode 100644 index 0000000..d3bceb7 --- /dev/null +++ b/lib/main.admin.ts @@ -0,0 +1,6 @@ +import { getAuth, getFirestore } from './firebase.admin.config'; + +const firestore = async () => await getFirestore(); +const auth = async () => await getAuth(); + +export { firestore, auth }; diff --git a/src/app/api/register/route.tsx b/src/app/api/register/route.tsx new file mode 100644 index 0000000..e26a75f --- /dev/null +++ b/src/app/api/register/route.tsx @@ -0,0 +1,28 @@ +import { User } from '../../../../api/domain/entities/User'; +import { UserRepository } from '../../../../api/domain/repositories/UserRepository'; +import { AuthRepository } from '../../../../api/domain/repositories/AuthRepository'; +import { RegisterUserUseCase } from '../../../../api/usecases/RegisterUser'; + +const userRepository = new UserRepository(); +const authRepository = new AuthRepository(); +const registerUserUseCase = new RegisterUserUseCase( + userRepository, + authRepository +); + +export async function POST(req: Request) { + const { userEmail, userPassword, userName } = await req.json(); + + try { + const user = await registerUserUseCase.execute( + userEmail, + userPassword, + userName + ); + + return Response.json(user); + } catch (error) { + console.error('Error creating user:', error); + return Response.json({ error: 'Failed to create user' }, { status: 500 }); + } +} From 830917180f1953c413d0a9676b5f3de40f7e20f4 Mon Sep 17 00:00:00 2001 From: Feli Date: Thu, 30 May 2024 23:44:25 -0500 Subject: [PATCH 3/4] refactor: Remove unused imports and files in User entity and AuthRepository --- api/domain/entities/User.ts | 1 - api/domain/repositories/AuthRepository.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/api/domain/entities/User.ts b/api/domain/entities/User.ts index 78a976f..9374179 100644 --- a/api/domain/entities/User.ts +++ b/api/domain/entities/User.ts @@ -1,4 +1,3 @@ -// domain/entities/User.ts export class User { private email: string; private password: string; diff --git a/api/domain/repositories/AuthRepository.ts b/api/domain/repositories/AuthRepository.ts index 1ffe284..119c4c0 100644 --- a/api/domain/repositories/AuthRepository.ts +++ b/api/domain/repositories/AuthRepository.ts @@ -1,5 +1,3 @@ -// domain/repositories/AuthRepository.ts - import { Auth } from 'firebase-admin/auth'; import { auth } from '../../../lib/main.admin'; From d722e105bf87e60fdb728758e08c283508904fb3 Mon Sep 17 00:00:00 2001 From: Feli Date: Thu, 30 May 2024 23:49:16 -0500 Subject: [PATCH 4/4] feat: Refactor user registration process The code changes in `RegisterUser.ts` improve the user registration process by first creating a user record in Firebase Auth and then saving the user to the database. This change ensures that the user is properly authenticated before saving their information. This refactor aligns with the recent changes made to the User entity, AuthRepository, UserRepository, and RegisterUserUseCase. --- api/usecases/RegisterUser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/usecases/RegisterUser.ts b/api/usecases/RegisterUser.ts index 38a2bc9..5684d1a 100644 --- a/api/usecases/RegisterUser.ts +++ b/api/usecases/RegisterUser.ts @@ -17,8 +17,8 @@ export class RegisterUserUseCase { userName: string ): Promise { const user = User.create(userEmail, userPassword, userName); - await this.userRepository.save(user); await this.authRepository.createUser(userEmail, userPassword); + await this.userRepository.save(user); return user; } }