//NEEDS WORKS ON < PAST CODE > import { onRequest } from 'firebase-functions/v2/https'; import { logger } from 'firebase-functions/v2'; import { corsMiddlewareHandler, db, FieldValue } from '../config'; import { toErrorWithMessage } from '../utils'; import * as admin from 'firebase-admin'; // --- Function 1: registerNewUser (Admin/Role-Protected Registration) --- export const registerNewUserV2 = onRequest(async (request, response) => { return corsMiddlewareHandler(request, response, async () => { logger.info('registerNewUser: Function invoked via CORS Middleware.'); const token = request.get('Authorization')?.split('Bearer ')[1]; if (token == null || token === '') { logger.warn('registerNewUser: No auth token provided.'); response.status(401).send({ error: 'unauthenticated', message: 'You must be logged in to register a user.', }); return; } let decodedToken; try { decodedToken = await admin.auth().verifyIdToken(token); logger.info( `registerNewUser: Token verified for admin UID: ${decodedToken.uid}`, ); } catch (error: unknown) { const errorMsg = toErrorWithMessage(error).message; logger.error(`registerNewUser: Invalid token: ${errorMsg}`); response.status(401).send({ error: 'unauthenticated', message: 'Invalid token.', details: errorMsg, }); return; } // Fetch the user's role let userRole = 0; try { const userDoc = await db.collection('users').doc(decodedToken.uid).get(); if (userDoc.exists) { userRole = userDoc.data()?.role || 0; logger.info(`registerNewUser: Requesting admin role is ${userRole}.`); } else { logger.warn( `registerNewUser: Admin user document not found for UID: ${decodedToken.uid}`, ); } } catch (error: unknown) { const errorMsg = toErrorWithMessage(error).message; logger.error( `registerNewUser: Failed to fetch admin role for UID ${decodedToken.uid}: ${errorMsg}`, ); response.status(500).send({ error: 'internal', message: "Failed to fetch user's role.", details: errorMsg, }); return; } // Role Check const requiredAdminRole = 5; if (userRole < requiredAdminRole) { logger.warn( `registerNewUser: Permission denied for UID ${decodedToken.uid} with role ${userRole}.`, ); response.status(403).send({ error: 'permission-denied', message: 'Insufficient role level to register a new user.', }); return; } logger.info( `registerNewUser: Permission granted for UID ${decodedToken.uid}. Proceeding.`, ); // Proceed with user registration try { const { email, password, name, phone, membership, ...rest } = request.body; if (!email || !password || !name) { logger.error( 'registerNewUser: Missing required fields (email, password, name).', ); response.status(400).send({ error: 'missing-fields', message: 'Missing required fields: email, password, name.', }); return; } logger.info( `registerNewUser: Attempting to create user with email: ${email}`, ); // Corrected: Pass user data object to createUser const userCred = await admin.auth().createUser({ email: email, password: password, displayName: name, }); logger.info( `registerNewUser: User created successfully with UID: ${userCred.uid}`, ); await db .collection('users') .doc(userCred.uid) .set({ docId: userCred.uid, name: name, phone: phone || null, email: email, membership: membership || null, role: 1, // Default role isActive: true, created: FieldValue.serverTimestamp(), ...rest, }); logger.info( `registerNewUser: User data stored in Firestore for UID: ${userCred.uid}`, ); response.send({ success: true, uid: userCred.uid }); } catch (error: unknown) { const errorMsg = toErrorWithMessage(error).message; logger.error( `registerNewUser: Failed during user creation/write: ${errorMsg}`, { error }, ); if ( error instanceof Error && 'code' in error && error.code === 'auth/email-already-exists' ) { response.status(409).send({ error: 'email-already-exists', message: 'The email address is already in use by another account.', details: errorMsg, }); } else { response.status(500).send({ error: 'internal', message: 'Failed to register user.', details: errorMsg, }); } } }); // End of corsMiddlewareHandler callback }); // End of registerNewUser onRequest // --- Function 2: visitorRegister (Public Registration) --- export const visitorRegisterV2 = onRequest(async (request, response) => { return corsMiddlewareHandler(request, response, async () => { // Note: Add 'as any' assertion here too if needed for TS build error workaround // return corsMiddlewareHandler(request as any, response as any, async () => { logger.info('visitorRegister: Function invoked via CORS Middleware.'); // Log updated if (request.method !== 'POST') { logger.warn(`visitorRegister: Method not allowed: ${request.method}`); response.status(405).send({ message: 'Method Not Allowed.' }); return; } const { email, password, name, membership, uid, ...rest } = request.body; if (!email || !password || !name) { logger.warn( 'visitorRegister: Missing essential fields (email, password, name).', ); response.status(400).send({ error: 'missing-fields', message: 'Missing essential registration fields.', }); return; } try { logger.info(`visitorRegister: Attempting to create user: ${email}`); const userCred = await admin.auth().createUser({ email: email, password: password, displayName: name, }); logger.info(`visitorRegister: User created with UID: ${userCred.uid}`); if (uid && typeof uid === 'string') { logger.info( `visitorRegister: Attempting to link phone number from temp UID: ${uid}`, ); try { const phoneUser = await admin.auth().getUser(uid); logger.info( `visitorRegister: Fetched phone user details for temp UID ${uid}. Phone: ${phoneUser.phoneNumber}`, ); if (phoneUser.phoneNumber) { await admin.auth().updateUser(userCred.uid, { phoneNumber: phoneUser.phoneNumber, }); logger.info( `visitorRegister: Phone number ${phoneUser.phoneNumber} linked to new user UID: ${userCred.uid}`, ); } else { logger.warn( `visitorRegister: Temp user UID ${uid} exists but has no phone number.`, ); } await admin.auth().deleteUser(uid); logger.info( `visitorRegister: Deleted temporary phone auth user UID: ${uid}`, ); } catch (linkError: unknown) { const linkErrorMsg = toErrorWithMessage(linkError).message; logger.error( `visitorRegister: Error during phone linking/deletion for temp UID ${uid} (non-fatal): ${linkErrorMsg}`, { linkError }, ); } } logger.info( `visitorRegister: Storing user data in Firestore for UID: ${userCred.uid}`, ); await db .collection('users') .doc(userCred.uid) .set({ docId: userCred.uid, name: name, email: email, membership: membership || null, role: 1, isActive: true, created: FieldValue.serverTimestamp(), ...rest, }); logger.info( `visitorRegister: Stored user data in Firestore for UID: ${userCred.uid}`, ); response.send({ success: true, uid: userCred.uid }); } catch (error: unknown) { const errorMsg = toErrorWithMessage(error).message; logger.error( `visitorRegister: Failed during registration for ${email}: ${errorMsg}`, { error }, ); if ( error instanceof Error && 'code' in error && error.code === 'auth/email-already-exists' ) { response.status(409).send({ error: 'email-already-exists', message: 'The email address is already in use by another account.', details: errorMsg, }); } else { response.status(500).send({ error: 'registration-failed', message: 'Failed to register the user.', details: errorMsg, }); } } }); // End of corsMiddlewareHandler callback }); // End of visitorRegister onRequest