const PersonalUser = require('../../models/PersonalUser'); const CompanyUser = require('../../models/CompanyUser'); const User = require('../../models/User'); const { logger } = require('../../middleware/logger'); class UserRepository { constructor(unitOfWork) { this.unitOfWork = unitOfWork; } async createUser(email, hashedPassword, userType) { logger.info('UserRepository.createUser:start', { email, userType }); try { const conn = this.unitOfWork.connection; const query = ` INSERT INTO users (email, password, user_type, role) VALUES (?, ?, ?, 'user') `; const [result] = await conn.query(query, [email, hashedPassword, userType]); logger.info('UserRepository.createUser:success', { email, userType, userId: result.insertId }); return result.insertId; } catch (error) { logger.error('UserRepository.createUser:error', { email, userType, error: error.message }); throw error; } } async findUserByEmail(email) { logger.info('UserRepository.findUserByEmail:start', { email }); try { const conn = this.unitOfWork.connection; // Query user, company profile, and personal profile data const query = ` SELECT u.*, cp.company_name, cp.registration_number, cp.phone as company_phone, cp.contact_person_name, cp.contact_person_phone, pp.first_name, pp.last_name, pp.phone as personal_phone, pp.date_of_birth FROM users u LEFT JOIN company_profiles cp ON u.id = cp.user_id LEFT JOIN personal_profiles pp ON u.id = pp.user_id WHERE u.email = ? `; const [rows] = await conn.query(query, [email]); if (rows.length > 0) { logger.info('UserRepository.findUserByEmail:found', { email, userId: rows[0].id }); const row = rows[0]; if (row.user_type === 'personal') { return new PersonalUser( row.id, row.email, row.password, row.first_name || '', row.last_name || '', row.phone || '', row.date_of_birth || null, null, row.created_at, row.updated_at, row.role ); } else if (row.user_type === 'company') { return new CompanyUser( row.id, row.email, row.password, row.company_name || '', row.company_phone || '', row.contact_person_name || '', row.contact_person_phone || '', row.registration_number || '', row.created_at, row.updated_at, row.role ); } else { return new User( row.id, row.email, row.password, row.user_type, row.created_at, row.updated_at, row.role ); } } logger.info('UserRepository.findUserByEmail:not_found', { email }); return null; } catch (error) { logger.error('UserRepository.findUserByEmail:error', { email, error: error.message }); throw error; } } async createPersonalProfile(userId, profileData) { logger.info('UserRepository.createPersonalProfile:start', { userId }); try { const conn = this.unitOfWork.connection; const { firstName, lastName, phone } = profileData; const query = ` INSERT INTO personal_profiles (user_id, first_name, last_name, phone) VALUES (?, ?, ?, ?) `; await conn.query(query, [userId, firstName, lastName, phone]); logger.info('UserRepository.createPersonalProfile:success', { userId }); } catch (error) { logger.error('UserRepository.createPersonalProfile:error', { userId, error: error.message }); throw error; } } async findPersonalUserByEmail(email) { logger.info('UserRepository.findPersonalUserByEmail:start', { email }); try { const conn = this.unitOfWork.connection; const query = ` SELECT u.*, pp.first_name, pp.last_name, pp.phone, pp.date_of_birth FROM users u LEFT JOIN personal_profiles pp ON u.id = pp.user_id WHERE u.email = ? AND u.user_type = 'personal' `; const [rows] = await conn.query(query, [email]); if (rows.length > 0) { logger.info('UserRepository.findPersonalUserByEmail:found', { email, userId: rows[0].id }); const row = rows[0]; return new PersonalUser( row.id, row.email, row.password, row.first_name, row.last_name, row.phone, row.date_of_birth, null, row.created_at, row.updated_at ); } logger.info('UserRepository.findPersonalUserByEmail:not_found', { email }); return null; } catch (error) { logger.error('UserRepository.findPersonalUserByEmail:error', { email, error: error.message }); throw error; } } async createCompanyProfile(userId, profileData) { logger.info('UserRepository.createCompanyProfile:start', { userId }); try { const conn = this.unitOfWork.connection; const { companyName, registrationNumber, companyPhone, contactPersonName } = profileData; const query = ` INSERT INTO company_profiles (user_id, company_name, registration_number, phone, contact_person_name) VALUES (?, ?, ?, ?, ?) `; await conn.query(query, [userId, companyName, registrationNumber, companyPhone, contactPersonName]); logger.info('UserRepository.createCompanyProfile:success', { userId }); } catch (error) { logger.error('UserRepository.createCompanyProfile:error', { userId, error: error.message }); throw error; } } async findCompanyUserByEmail(email) { logger.info('UserRepository.findCompanyUserByEmail:start', { email }); try { const conn = this.unitOfWork.connection; const query = ` SELECT u.*, cp.company_name, cp.registration_number, cp.phone as company_phone, cp.contact_person_name FROM users u LEFT JOIN company_profiles cp ON u.id = cp.user_id WHERE u.email = ? AND u.user_type = 'company' `; const [rows] = await conn.query(query, [email]); if (rows.length > 0) { logger.info('UserRepository.findCompanyUserByEmail:found', { email, userId: rows[0].id }); const row = rows[0]; return new CompanyUser( row.id, row.email, row.password, row.company_name, row.company_phone, row.contact_person_name, null, row.registration_number, row.created_at, row.updated_at ); } logger.info('UserRepository.findCompanyUserByEmail:not_found', { email }); return null; } catch (error) { logger.error('UserRepository.findCompanyUserByEmail:error', { email, error: error.message }); throw error; } } async createUserStatus(userId) { logger.info('UserRepository.createUserStatus:start', { userId }); try { const conn = this.unitOfWork.connection; const query = ` INSERT INTO user_status (user_id, status, email_verified, profile_completed, registration_completed) VALUES (?, 'pending', FALSE, TRUE, FALSE) `; await conn.query(query, [userId]); logger.info('UserRepository.createUserStatus:success', { userId }); } catch (error) { logger.error('UserRepository.createUserStatus:error', { userId, error: error.message }); throw error; } } async findUserByEmailOrId(identifier) { logger.info('UserRepository.findUserByEmailOrId:start', { identifier }); try { const conn = this.unitOfWork.connection; let query, params; if (typeof identifier === 'number' || /^\d+$/.test(identifier)) { query = ` SELECT u.*, cp.company_name, cp.registration_number, cp.phone as company_phone, cp.contact_person_name, cp.contact_person_phone, pp.first_name, pp.last_name, pp.phone as personal_phone, pp.date_of_birth FROM users u LEFT JOIN company_profiles cp ON u.id = cp.user_id LEFT JOIN personal_profiles pp ON u.id = pp.user_id WHERE u.id = ? `; params = [identifier]; } else { query = ` SELECT u.*, cp.company_name, cp.registration_number, cp.phone as company_phone, cp.contact_person_name, cp.contact_person_phone, pp.first_name, pp.last_name, pp.phone as personal_phone, pp.date_of_birth FROM users u LEFT JOIN company_profiles cp ON u.id = cp.user_id LEFT JOIN personal_profiles pp ON u.id = pp.user_id WHERE u.email = ? `; params = [identifier]; } const [rows] = await conn.query(query, params); if (rows.length > 0) { logger.info('UserRepository.findUserByEmailOrId:found', { identifier, userId: rows[0].id }); const row = rows[0]; if (row.user_type === 'company') { return new CompanyUser( row.id, row.email, row.password, row.company_name || '', row.company_phone || '', row.contact_person_name || '', row.contact_person_phone || '', row.registration_number || '', row.created_at, row.updated_at ); } else if (row.user_type === 'personal') { return new PersonalUser( row.id, row.email, row.password, row.first_name || '', row.last_name || '', row.personal_phone || '', row.date_of_birth || null, null, row.created_at, row.updated_at ); } else { return new User( row.id, row.email, row.password, row.user_type, row.created_at, row.updated_at ); } } logger.info('UserRepository.findUserByEmailOrId:not_found', { identifier }); return null; } catch (error) { logger.error('UserRepository.findUserByEmailOrId:error', { identifier, error: error.message }); throw error; } } async getIban(userId) { logger.info('UserRepository.getIban:start', { userId }); try { const conn = this.unitOfWork.connection; const [rows] = await conn.query( `SELECT iban FROM users WHERE id = ? LIMIT 1`, [userId] ); logger.info('UserRepository.getIban:success', { userId, iban: rows.length ? rows[0].iban : null }); return rows.length ? rows[0].iban : null; } catch (error) { logger.error('UserRepository.getIban:error', { userId, error: error.message }); throw error; } } async getProfile(userId, userType) { logger.info('UserRepository.getProfile:start', { userId, userType }); try { const conn = this.unitOfWork.connection; if (userType === 'personal') { const [rows] = await conn.query( `SELECT * FROM personal_profiles WHERE user_id = ? LIMIT 1`, [userId] ); logger.info('UserRepository.getProfile:success', { userId, userType }); return rows.length ? rows[0] : null; } else if (userType === 'company') { const [rows] = await conn.query( `SELECT * FROM company_profiles WHERE user_id = ? LIMIT 1`, [userId] ); logger.info('UserRepository.getProfile:success', { userId, userType }); return rows.length ? rows[0] : null; } logger.info('UserRepository.getProfile:not_found', { userId, userType }); return null; } catch (error) { logger.error('UserRepository.getProfile:error', { userId, userType, error: error.message }); throw error; } } async getReferralEmail(userId, userType) { logger.info('UserRepository.getReferralEmail:start', { userId, userType }); try { const conn = this.unitOfWork.connection; const [rows] = await conn.query( `SELECT u.email AS referralEmail FROM referral_token_usage rtu JOIN referral_tokens rt ON rtu.referral_token_id = rt.id JOIN users u ON rt.created_by_user_id = u.id WHERE rtu.used_by_user_id = ? LIMIT 1`, [userId] ); logger.info('UserRepository.getReferralEmail:success', { userId, referralEmail: rows.length ? rows[0].referralEmail : null }); return rows.length ? rows[0].referralEmail : null; } catch (error) { logger.error('UserRepository.getReferralEmail:error', { userId, userType, error: error.message }); throw error; } } async getPermissions(userId) { logger.info('UserRepository.getPermissions:start', { userId }); try { const conn = this.unitOfWork.connection; const [permRows] = await conn.query( `SELECT p.name FROM user_permissions up JOIN permissions p ON up.permission_id = p.id WHERE up.user_id = ? AND p.is_active = TRUE`, [userId] ); logger.info('UserRepository.getPermissions:success', { userId, count: permRows.length }); return permRows.map(row => row.name); } catch (error) { logger.error('UserRepository.getPermissions:error', { userId, error: error.message }); throw error; } } async getUserStatus(userId) { logger.info('UserRepository.getUserStatus:start', { userId }); try { const conn = this.unitOfWork.connection; const [rows] = await conn.query( `SELECT * FROM user_status WHERE user_id = ? LIMIT 1`, [userId] ); logger.info('UserRepository.getUserStatus:success', { userId, found: rows.length > 0 }); return rows.length ? rows[0] : null; } catch (error) { logger.error('UserRepository.getUserStatus:error', { userId, error: error.message }); throw error; } } async getContracts(userId) { logger.info('UserRepository.getContracts:start', { userId }); try { const conn = this.unitOfWork.connection; const [rows] = await conn.query( `SELECT * FROM user_documents WHERE user_id = ? AND document_type = 'contract'`, [userId] ); logger.info('UserRepository.getContracts:success', { userId, count: rows.length }); return rows; } catch (error) { logger.error('UserRepository.getContracts:error', { userId, error: error.message }); throw error; } } async getIdDocuments(userId) { logger.info('UserRepository.getIdDocuments:start', { userId }); try { const conn = this.unitOfWork.connection; const [rows] = await conn.query( `SELECT * FROM user_id_documents WHERE user_id = ?`, [userId] ); logger.info('UserRepository.getIdDocuments:success', { userId, count: rows.length }); return rows; } catch (error) { logger.error('UserRepository.getIdDocuments:error', { userId, error: error.message }); throw error; } } async deleteUserById(userId) { logger.info('UserRepository.deleteUserById:start', { userId }); try { const conn = this.unitOfWork.connection; await conn.query(`DELETE FROM users WHERE id = ?`, [userId]); logger.info('UserRepository.deleteUserById:success', { userId }); } catch (error) { logger.error('UserRepository.deleteUserById:error', { userId, error: error.message }); throw error; } } async getStatusByUserId(userId) { logger.info('UserRepository.getStatusByUserId:start', { userId }); try { const conn = this.unitOfWork.connection; const [rows] = await conn.query( `SELECT email_verified, documents_uploaded, profile_completed, contract_signed, is_admin_verified, email_verified_at, documents_uploaded_at, profile_completed_at, contract_signed_at FROM user_status WHERE user_id = ? LIMIT 1`, [userId] ); if (rows.length) { const row = rows[0]; logger.info('UserRepository.getStatusByUserId:success', { userId, status: row }); return { email_verified: row.email_verified, documents_uploaded: row.documents_uploaded, profile_completed: row.profile_completed, contract_signed: row.contract_signed, is_admin_verified: row.is_admin_verified, email_verified_at: row.email_verified_at, documents_uploaded_at: row.documents_uploaded_at, profile_completed_at: row.profile_completed_at, contract_signed_at: row.contract_signed_at }; } logger.info('UserRepository.getStatusByUserId:not_found', { userId }); return null; } catch (error) { logger.error('UserRepository.getStatusByUserId:error', { userId, error: error.message }); throw error; } } } module.exports = UserRepository;