import bcrypt from 'bcrypt'; import crypto from 'crypto'; import { v4 as uuidv4 } from 'uuid'; import User from '../models/community/user.js'; import UserParam from '../models/community/user_param.js'; import UserParamType from '../models/type/user_param.js'; import { sendAccountActivationEmail, sendPasswordResetEmail } from './emailService.js'; import { sequelize } from '../utils/sequelize.js'; import { Op } from 'sequelize'; import { setUserSession, deleteUserSession } from '../utils/redis.js'; import { encrypt } from '../utils/encryption.js'; import { notifyUser } from '../utils/socket.js'; import Friendship from '../models/community/friendship.js'; const saltRounds = 10; const getFriends = async (userId) => { console.log('getFriends', userId); try { const friendships = await Friendship.findAll({ where: { [Op.or]: [ { user1Id: userId }, { user2Id: userId }, ], accepted: true, }, include: [ { model: User, as: 'friendSender', attributes: ['hashedId', 'username'], }, { model: User, as: 'friendReceiver', attributes: ['hashedId', 'username'], }, ], }); console.log('did read out friends'); return friendships.map((friendship) => { if (friendship.user1Id === userId) { return friendship.friendReceiver; } else { return friendship.friendSender; } }); } catch (error) { console.error('Error fetching friends:', error); throw error; } }; export const registerUser = async ({ email, username, password, language }) => { const encryptedEmail = encrypt(email); const query = ` SELECT id FROM community.user WHERE email = :encryptedEmail `; const existingUser = await sequelize.query(query, { replacements: { encryptedEmail }, type: sequelize.QueryTypes.SELECT, }); if (existingUser.length > 0) { throw new Error('emailinuse'); } const hashedPassword = await bcrypt.hash(password, saltRounds); const resetToken = uuidv4(); const user = await User.create({ email: email, username, password: hashedPassword, resetToken: resetToken, active: false, registration_date: new Date() }); const languageType = await UserParamType.findOne({ where: { description: 'language' } }); if (!languageType) { throw new Error('languagenotfound'); } const languageParam = await UserParam.create({ userId: user.id, paramTypeId: languageType.id, value: language }); const activationLink = `${process.env.FRONTEND_URL}/activate?token=${resetToken}`; await sendAccountActivationEmail(email, activationLink, username, resetToken, language); const authCode = crypto.randomBytes(20).toString('hex'); return { id: user.hashedId, username: user.username, active: user.active, param: [languageParam], authCode }; }; export const loginUser = async ({ username, password }) => { const user = await User.findOne({ where: { username } }); if (!user) { throw new Error('credentialsinvalid'); } const match = await bcrypt.compare(password, user.password); if (!match) { throw new Error('credentialsinvalid'); } const authCode = crypto.randomBytes(20).toString('hex'); user.authCode = authCode; await user.save(); const friends = await getFriends(user.id); console.log('send login to friends'); for (const friend of friends) { await notifyUser(friend.hashedId, 'friendloginchanged', { userId: user.hashedId, status: 'online', }); } console.log('set user session'); const sessionData = { id: user.hashedId, username: user.username, active: user.active, authCode, timestamp: Date.now() }; await setUserSession(user.id, sessionData); console.log('get user params'); const params = await UserParam.findAll({ where: { userId: user.id }, include: { model: UserParamType, as: 'paramType', where: { description: ['birthdate', 'gender', 'language'] } } }); const mappedParams = params.map(param => { return { 'name': param.paramType.description, 'value': param.value }; }); console.log('return user'); return { id: user.hashedId, username: user.username, active: user.active, param: mappedParams, authCode }; }; export const logoutUser = async (hashedUserId) => { try { const user = await User.findOne({ where: { hashedId: hashedUserId } }) if (!user) { return; } const friends = await getFriends(user.id); for (const friend of friends) { await notifyUser(friend.hashedId, 'friendloginchanged', { userId: user.hashedId, status: 'online', }); } await deleteUserSession(user.id); } catch (error) { console.error('Fehler beim Logout:', error); throw new Error('logoutfailed'); } }; export const handleForgotPassword = async ({ email }) => { const user = await User.findOne({ where: { email } }); if (!user) { throw new Error('Email not found'); } const resetToken = uuidv4(); const resetLink = `${process.env.FRONTEND_URL}/reset-password?token=${resetToken}`; await user.update({ reset_token: resetToken }); const languageParam = await UserParam.findOne({ where: { user_id: user.id, param_type_id: languageType.id } }); const userLanguage = languageParam ? languageParam.value : 'en'; await sendPasswordResetEmail(email, resetLink, userLanguage); return { message: 'Password reset email sent' }; }; export const activateUserAccount = async ({ token }) => { const user = await User.findOne({ where: { reset_token: token } }); if (!user) { throw new Error('Invalid token'); } await user.update({ active: true, reset_token: null }); return { message: 'Account activated' }; };