191 lines
6.2 KiB
JavaScript
191 lines
6.2 KiB
JavaScript
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);
|
|
for (const friend of friends) {
|
|
await notifyUser(friend.hashedId, 'friendloginchanged', {
|
|
userId: user.hashedId,
|
|
status: 'online',
|
|
});
|
|
}
|
|
const sessionData = {
|
|
id: user.hashedId,
|
|
username: user.username,
|
|
active: user.active,
|
|
authCode,
|
|
timestamp: Date.now()
|
|
};
|
|
await setUserSession(user.id, sessionData);
|
|
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 };
|
|
});
|
|
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' };
|
|
};
|