const { User } = require('../models/user'); const { MyGroup } = require('../models/mygroup'); const { Circuit } = require('../models/circuit'); const { SendNotif } = require('../models/sendnotif'); const { Province } = require('../models/province'); const tools = require('../tools/general'); const shared_consts = require('../tools/shared_nodejs'); const server_constants = require('../tools/server_constants'); const CronMod = require('../modules/CronMod'); class UserService { /** * Get user profile with friends */ async getUserProfile(idapp, username, usernameOrig, perm) { try { const profile = await User.getUserProfileByUsername( idapp, username, usernameOrig, false, perm ); const friends = await User.getFriendsByUsername(idapp, usernameOrig); // Get extra info if viewing own profile if (username === usernameOrig) { const userProfile = await User.getExtraInfoByUsername(idapp, profile.username); profile.profile = userProfile; } return { user: profile, friends }; } catch (error) { console.error('Error in getUserProfile:', error.message); throw error; } } /** * Get user activities profile (public version) */ async getUserActivitiesProfile(idapp, username, usernameOrig, perm, isAuthenticated) { try { const profile = await User.getUserProfileByUsername( idapp, username, usernameOrig, false, perm ); const friends = await User.getFriendsByUsername(idapp, usernameOrig); let userProfile; if (isAuthenticated) { userProfile = await User.getExtraInfoByUsername(idapp, profile.username); } else { userProfile = await User.getProfilePerActivitiesByUsername(idapp, profile.username); // Hide sensitive data for non-authenticated users profile.aportador_solidario = ''; profile.date_reg = ''; profile.email = ''; } profile.profile = userProfile; return { user: profile, friends }; } catch (error) { console.error('Error in getUserActivitiesProfile:', error.message); throw error; } } /** * Update user balance and get notifications */ async updateUserBalance(idapp, username, circuitId, groupname, lastdr = '') { try { const userProfile = await User.getExtraInfoByUsername(idapp, username); const arrRecNotif = await SendNotif.findAllNotifByUsernameIdAndIdApp( username, lastdr, idapp, shared_consts.LIMIT_NOTIF_FOR_USER, shared_consts.QualiNotifs.OTHERS ); const arrRecNotifCoins = await SendNotif.findAllNotifByUsernameIdAndIdApp( username, lastdr, idapp, shared_consts.LIMIT_NOTIFCOINS_FOR_USER, shared_consts.QualiNotifs.CIRCUITS ); return { userprofile: userProfile, arrrecnotif: arrRecNotif, arrrecnotifcoins: arrRecNotifCoins }; } catch (error) { console.error('Error in updateUserBalance:', error.message); throw error; } } /** * Get user's friends list */ async getUserFriends(idapp, username) { try { return await User.getFriendsByUsername(idapp, username); } catch (error) { console.error('Error in getUserFriends:', error.message); throw error; } } /** * Get user's groups */ async getUserGroups(idapp, username, req) { try { return await MyGroup.getGroupsByUsername(idapp, username, req); } catch (error) { console.error('Error in getUserGroups:', error.message); throw error; } } /** * Get user's circuits */ async getUserCircuits(idapp, username, user, nummovTodownload) { try { return await Circuit.getCircuitsByUsername( idapp, username, user, nummovTodownload ); } catch (error) { console.error('Error in getUserCircuits:', error.message); throw error; } } /** * Execute friend command (add, remove, handshake, etc.) */ async executeFriendCommand(req, idapp, usernameOrig, usernameDest, cmd, value) { try { // Normalize usernames const realUsernameOrig = await User.getRealUsernameByUsername(idapp, usernameOrig); const realUsernameDest = await User.getRealUsernameByUsername(idapp, usernameDest); return await User.setFriendsCmd( req, idapp, realUsernameOrig, realUsernameDest, cmd, value ); } catch (error) { console.error('Error in executeFriendCommand:', error.message); throw error; } } /** * Execute group command */ async executeGroupCommand(idapp, usernameOrig, groupnameDest, cmd, value, usernameLogged) { try { return await User.setGroupsCmd( idapp, usernameOrig, groupnameDest, cmd, value, usernameLogged ); } catch (error) { console.error('Error in executeGroupCommand:', error.message); throw error; } } /** * Execute circuit command */ async executeCircuitCommand(idapp, usernameOrig, circuitname, cmd, value, usernameLogged, extrarec) { try { const result = await User.setCircuitCmd( idapp, usernameOrig, circuitname, cmd, value, usernameLogged, extrarec ); // Mark notification as read if present if (extrarec?.idnotif) { await this.markNotificationAsRead(idapp, usernameOrig, extrarec.idnotif); } return result; } catch (error) { console.error('Error in executeCircuitCommand:', error.message); throw error; } } /** * Mark notification as read */ async markNotificationAsRead(idapp, username, idnotif) { try { if (idnotif) { await SendNotif.setNotifAsRead(idapp, username, idnotif); } } catch (error) { console.error('Error in markNotificationAsRead:', error.message); // Non-critical error, don't throw } } /** * Check if username exists */ async checkUsernameExists(idapp, username) { try { let user = await User.findByUsername(idapp, username, false, true); if (!user) { user = await User.findByUsernameTelegram(idapp, username, false, true); } return !!user; } catch (error) { console.error('Error in checkUsernameExists:', error.message); throw error; } } /** * Set user permissions */ async setUserPermissions(userId, data) { try { await User.setPermissionsById(userId, data); } catch (error) { console.error('Error in setUserPermissions:', error.message); throw error; } } /** * Execute database operation (admin only) */ async executeDbOperation(idapp, mydata, req, res) { try { const cronMod = new CronMod(); return await cronMod.eseguiDbOp(idapp, mydata, req, res); } catch (error) { console.error('Error in executeDbOperation:', error.message); throw error; } } /** * Execute user-specific database operation */ async executeUserDbOperation(idapp, mydata, username) { try { let result = await User.DbOp(idapp, mydata); // Handle specific operations await this._handleSpecificDbOperations(mydata); if (!result) { result = {}; } return await User.updateMyData(result, idapp, username); } catch (error) { console.error('Error in executeUserDbOperation:', error.message); throw error; } } /** * Get map information (provinces with user counts) */ async getMapInformation(idapp) { try { const query = [ { $lookup: { from: 'users', localField: 'prov', foreignField: 'profile.resid_province', as: 'users' } }, { $addFields: { userCount: { $size: '$users' } } }, { $lookup: { from: 'provinces', localField: 'prov', foreignField: 'prov', as: 'provinceInfo' } }, { $addFields: { provinceDescr: { $arrayElemAt: ['$provinceInfo.descr', 0] } } }, { $project: { _id: 0, province: '$prov', descr: '$provinceDescr', userCount: 1, lat: 1, long: 1 } } ]; return await Province.aggregate(query); } catch (error) { console.error('Error in getMapInformation:', error.message); throw error; } } /** * Send command to user */ async sendCommand(req, idapp, usernameOrig, usernameDest, cmd, value) { try { const realUsernameOrig = await User.getRealUsernameByUsername(idapp, usernameOrig); const realUsernameDest = await User.getRealUsernameByUsername(idapp, usernameDest); return await User.sendCmd( req, idapp, realUsernameOrig, realUsernameDest, cmd, value ); } catch (error) { console.error('Error in sendCommand:', error.message); throw error; } } /** * Get user panel information (admin/manager view) */ async getUserPanelInfo(idapp, username) { try { const user = await User.findOne( { idapp, username }, { username: 1, name: 1, surname: 1, email: 1, verified_by_aportador: 1, aportador_solidario: 1, lasttimeonline: 1, deleted: 1, sospeso: 1, blocked: 1, reported: 1, username_who_report: 1, date_report: 1, profile: 1 } ).lean(); if (!user) { throw new Error('Utente non trovato'); } return user; } catch (error) { console.error('Error in getUserPanelInfo:', error.message); throw error; } } /** * Handle specific database operations * @private */ async _handleSpecificDbOperations(mydata) { const operations = { 'saveStepTut': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.stepTutorial': mydata.value } } ), 'noNameSurname': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.noNameSurname': mydata.value } } ), 'telegram_verification_skipped': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.telegram_verification_skipped': mydata.value } } ), 'noCircuit': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.noCircuit': mydata.value } } ), 'noCircIta': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.noCircIta': mydata.value } } ), 'insert_circuito_ita': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.insert_circuito_ita': mydata.value } } ), 'noFoto': () => User.findOneAndUpdate( { _id: mydata._id }, { $set: { 'profile.noFoto': mydata.value } } ), 'pwdLikeAdmin': () => User.setPwdComeQuellaDellAdmin(mydata), 'ripristinaPwdPrec': () => User.ripristinaPwdPrec(mydata) }; const operation = operations[mydata.dbop]; if (operation) { await operation(); } } } module.exports = UserService;