import FalukantService from '../services/falukantService.js'; function extractHashedUserId(req) { return req.headers?.userid; } class FalukantController { constructor() { this.service = FalukantService; // No-user endpoints this.randomFirstName = this._wrapNoUser(this.service.randomFirstName.bind(this.service), { successStatus: 200, transform: gender => ({ name: gender }) }); this.randomLastName = this._wrapNoUser(this.service.randomLastName.bind(this.service), { successStatus: 200, transform: name => ({ name }) }); // User-scoped endpoints this.getUser = this._wrapWithUser((userId) => this.service.getUser(userId)); this.createUser = this._wrapWithUser((userId, req) => { const { gender, firstname, lastname } = req.body; return this.service.createUser(userId, gender, firstname, lastname); }, { successStatus: 201 }); this.getInfo = this._wrapWithUser((userId) => this.service.getInfo(userId)); this.getBranches = this._wrapWithUser((userId) => this.service.getBranches(userId)); this.createBranch = this._wrapWithUser((userId, req) => this.service.createBranch(userId, req.body.cityId, req.body.branchTypeId)); this.getBranchTypes = this._wrapWithUser((userId) => this.service.getBranchTypes(userId)); this.getBranch = this._wrapWithUser((userId, req) => this.service.getBranch(userId, req.params.branch)); this.upgradeBranch = this._wrapWithUser((userId, req) => this.service.upgradeBranch(userId, req.body.branchId)); this.createProduction = this._wrapWithUser((userId, req) => { const { branchId, productId, quantity } = req.body; return this.service.createProduction(userId, branchId, productId, quantity); }, { successStatus: 201 }); this.getProduction = this._wrapWithUser((userId, req) => this.service.getProduction(userId, req.params.branchId)); this.getStock = this._wrapWithUser((userId, req) => this.service.getStock(userId, req.params.branchId || null)); this.createStock = this._wrapWithUser((userId, req) => { const { branchId, stockTypeId, stockSize } = req.body; return this.service.createStock(userId, branchId, stockTypeId, stockSize); }, { successStatus: 201 }); this.getProducts = this._wrapWithUser((userId) => this.service.getProducts(userId)); this.getInventory = this._wrapWithUser((userId, req) => this.service.getInventory(userId, req.params.branchId)); this.sellProduct = this._wrapWithUser((userId, req) => { const { branchId, productId, quality, quantity } = req.body; return this.service.sellProduct(userId, branchId, productId, quality, quantity); }, { successStatus: 201 }); this.sellAllProducts = this._wrapWithUser((userId, req) => { const { branchId } = req.body; return this.service.sellAllProducts(userId, branchId); }, { successStatus: 201 }); this.moneyHistory = this._wrapWithUser((userId, req) => { let { page, filter } = req.body; if (!page) page = 1; return this.service.moneyHistory(userId, page, filter); }); this.getStorage = this._wrapWithUser((userId, req) => this.service.getStorage(userId, req.params.branchId)); this.buyStorage = this._wrapWithUser((userId, req) => { const { branchId, amount, stockTypeId } = req.body; return this.service.buyStorage(userId, branchId, amount, stockTypeId); }, { successStatus: 201 }); this.sellStorage = this._wrapWithUser((userId, req) => { const { branchId, amount, stockTypeId } = req.body; return this.service.sellStorage(userId, branchId, amount, stockTypeId); }, { successStatus: 202 }); this.getStockTypes = this._wrapSimple(() => this.service.getStockTypes()); this.getStockOverview = this._wrapSimple(() => this.service.getStockOverview()); this.getAllProductions = this._wrapWithUser((userId) => this.service.getAllProductions(userId)); this.getDirectorProposals = this._wrapWithUser((userId, req) => { console.log('🔍 getDirectorProposals called with userId:', userId, 'branchId:', req.body.branchId); return this.service.getDirectorProposals(userId, req.body.branchId); }); this.convertProposalToDirector = this._wrapWithUser((userId, req) => this.service.convertProposalToDirector(userId, req.body.proposalId)); this.getDirectorForBranch = this._wrapWithUser((userId, req) => this.service.getDirectorForBranch(userId, req.params.branchId)); this.getAllDirectors = this._wrapWithUser((userId) => this.service.getAllDirectors(userId)); this.updateDirector = this._wrapWithUser((userId, req) => { const { directorId, income } = req.body; return this.service.updateDirector(userId, directorId, income); }); this.setSetting = this._wrapWithUser((userId, req) => { const { branchId, directorId, settingKey, value } = req.body; return this.service.setSetting(userId, branchId, directorId, settingKey, value); }); this.getFamily = this._wrapWithUser(async (userId) => { const result = await this.service.getFamily(userId); if (!result) throw { status: 404, message: 'No family data found' }; return result; }); this.acceptMarriageProposal = this._wrapWithUser((userId, req) => this.service.acceptMarriageProposal(userId, req.body.proposalId)); this.getGifts = this._wrapWithUser((userId) => { console.log('🔍 getGifts called with userId:', userId); return this.service.getGifts(userId); }); this.getChildren = this._wrapWithUser((userId) => this.service.getChildren(userId)); this.sendGift = this._wrapWithUser((userId, req) => this.service.sendGift(userId, req.body.giftId)); this.getTitlesOfNobility = this._wrapWithUser((userId) => this.service.getTitlesOfNobility(userId)); this.getHouseTypes = this._wrapWithUser((userId) => this.service.getHouseTypes(userId)); this.getMoodAffect = this._wrapWithUser((userId) => this.service.getMoodAffect(userId)); this.getCharacterAffect = this._wrapWithUser((userId) => this.service.getCharacterAffect(userId)); this.getUserHouse = this._wrapWithUser((userId) => this.service.getUserHouse(userId)); this.getBuyableHouses = this._wrapWithUser((userId) => this.service.getBuyableHouses(userId)); this.buyUserHouse = this._wrapWithUser((userId, req) => this.service.buyUserHouse(userId, req.body.houseId), { successStatus: 201 }); this.getPartyTypes = this._wrapWithUser((userId) => this.service.getPartyTypes(userId)); this.createParty = this._wrapWithUser((userId, req) => { const { partyTypeId, musicId, banquetteId, nobilityIds, servantRatio } = req.body; return this.service.createParty(userId, partyTypeId, musicId, banquetteId, nobilityIds, servantRatio); }, { successStatus: 201 }); this.getParties = this._wrapWithUser((userId) => this.service.getParties(userId)); this.getNotBaptisedChildren = this._wrapWithUser((userId) => this.service.getNotBaptisedChildren(userId)); this.baptise = this._wrapWithUser((userId, req) => { const { characterId: childId, firstName } = req.body; return this.service.baptise(userId, childId, firstName); }); this.getEducation = this._wrapWithUser((userId) => this.service.getEducation(userId)); this.sendToSchool = this._wrapWithUser((userId, req) => { const { item, student, studentId } = req.body; return this.service.sendToSchool(userId, item, student, studentId); }); this.getBankOverview = this._wrapWithUser((userId) => this.service.getBankOverview(userId)); this.getBankCredits = this._wrapWithUser((userId) => this.service.getBankCredits(userId)); this.takeBankCredits = this._wrapWithUser((userId, req) => this.service.takeBankCredits(userId, req.body.height)); this.getNobility = this._wrapWithUser((userId) => this.service.getNobility(userId)); this.advanceNobility = this._wrapWithUser((userId) => this.service.advanceNobility(userId)); this.getHealth = this._wrapWithUser((userId) => this.service.getHealth(userId)); this.healthActivity = this._wrapWithUser((userId, req) => this.service.healthActivity(userId, req.body.measureTr)); this.getPoliticsOverview = this._wrapWithUser((userId) => this.service.getPoliticsOverview(userId)); this.getOpenPolitics = this._wrapWithUser((userId) => this.service.getOpenPolitics(userId)); this.getElections = this._wrapWithUser((userId) => this.service.getElections(userId)); this.vote = this._wrapWithUser((userId, req) => this.service.vote(userId, req.body.votes)); this.applyForElections = this._wrapWithUser((userId, req) => this.service.applyForElections(userId, req.body.electionIds)); this.getRegions = this._wrapWithUser((userId) => this.service.getRegions(userId)); this.getProductPriceInRegion = this._wrapWithUser((userId, req) => { const productId = parseInt(req.query.productId, 10); const regionId = parseInt(req.query.regionId, 10); if (Number.isNaN(productId) || Number.isNaN(regionId)) { throw new Error('productId and regionId are required'); } return this.service.getProductPriceInRegion(userId, productId, regionId); }); this.getProductPricesInCities = this._wrapWithUser((userId, req) => { const productId = parseInt(req.query.productId, 10); const currentPrice = parseFloat(req.query.currentPrice); const currentRegionId = req.query.currentRegionId ? parseInt(req.query.currentRegionId, 10) : null; if (Number.isNaN(productId) || Number.isNaN(currentPrice)) { throw new Error('productId and currentPrice are required'); } return this.service.getProductPricesInCities(userId, productId, currentPrice, currentRegionId); }); this.renovate = this._wrapWithUser((userId, req) => this.service.renovate(userId, req.body.element)); this.renovateAll = this._wrapWithUser((userId) => this.service.renovateAll(userId)); this.getUndergroundTypes = this._wrapWithUser((userId) => this.service.getUndergroundTypes(userId)); this.getNotifications = this._wrapWithUser((userId) => this.service.getNotifications(userId)); this.getAllNotifications = this._wrapWithUser((userId, req) => this.service.getAllNotifications(userId, req.query.page, req.query.size)); this.markNotificationsShown = this._wrapWithUser((userId) => this.service.markNotificationsShown(userId), { successStatus: 202 }); this.getUndergroundTargets = this._wrapWithUser((userId) => this.service.getPoliticalOfficeHolders(userId)); this.searchUsers = this._wrapWithUser((userId, req) => { const q = req.query.q?.trim() || ''; if (q.length < 1) return []; return this.service.searchUsers(userId, q); }); this.createUndergroundActivity = this._wrapWithUser((userId, req) => { const payload = req.body; if (!payload.typeId) { throw { status: 400, message: 'typeId is required' }; } if (payload.typeId === 'sabotage' && !payload.target) { throw { status: 400, message: 'target is required for sabotage' }; } if (payload.typeId === 'corrupt_politician' && !payload.goal) { throw { status: 400, message: 'goal is required for corrupt_politician' }; } return this.service.createUndergroundActivity(userId, payload); }, { successStatus: 201 }); this.getUndergroundAttacks = this._wrapWithUser((userId, req) => { const direction = (req.query.direction || '').toLowerCase(); return this.service.getUndergroundAttacks(userId).then(result => { if (direction === 'sent') return result.sent; if (direction === 'received') return result.received; return result; // both }); }); this.getVehicleTypes = this._wrapWithUser((userId) => this.service.getVehicleTypes(userId)); this.buyVehicles = this._wrapWithUser( (userId, req) => this.service.buyVehicles(userId, req.body), { successStatus: 201 } ); this.getVehicles = this._wrapWithUser( (userId, req) => this.service.getVehicles(userId, req.query.regionId) ); this.createTransport = this._wrapWithUser( (userId, req) => this.service.createTransport(userId, req.body), { successStatus: 201 } ); this.getTransportRoute = this._wrapWithUser( (userId, req) => this.service.getTransportRoute(userId, req.query) ); this.getBranchTransports = this._wrapWithUser( (userId, req) => this.service.getBranchTransports(userId, req.params.branchId) ); } _wrapWithUser(fn, { successStatus = 200, postProcess } = {}) { return async (req, res) => { try { const hashedUserId = extractHashedUserId(req); if (!hashedUserId) { return res.status(400).json({ error: 'Missing user identifier' }); } const result = await fn(hashedUserId, req, res); const toSend = postProcess ? postProcess(result) : result; res.status(successStatus).json(toSend); } catch (error) { console.error('Controller error:', error); const status = error.status && typeof error.status === 'number' ? error.status : 500; res.status(status).json({ error: error.message || 'Internal error' }); } }; } _wrapSimple(fn, { successStatus = 200, postProcess } = {}) { return async (req, res) => { try { const result = await fn(req, res); const toSend = postProcess ? postProcess(result) : result; res.status(successStatus).json(toSend); } catch (error) { console.error('Controller error:', error); const status = error.status && typeof error.status === 'number' ? error.status : 500; res.status(status).json({ error: error.message || 'Internal error' }); } }; } _wrapNoUser(fn, { successStatus = 200, transform } = {}) { return async (req, res) => { try { let result; if (req.params && Object.keys(req.params).length) { result = await fn(req.params.gender); } else { result = await fn(); } if (transform) result = transform(result); res.status(successStatus).json(result); } catch (error) { console.error('Controller error:', error); res.status(500).json({ error: error.message || 'Internal error' }); } }; } } export default FalukantController;