Änderungen: - Implementierung von neuen Methoden `getAccountSettings` und `setAccountSettings` im `SettingsService`, um Benutzerkontoeinstellungen zu verwalten. - Anpassung der E-Mail-Verschlüsselung im `User`-Modell zur Verwendung von Buffer für die Speicherung und zur Verbesserung der Fehlerbehandlung bei der Entschlüsselung. - Hinzufügung eines neuen `immutable`-Feldes im `UserParamType`-Modell, um unveränderliche Einstellungen zu kennzeichnen. - Anpassungen in den Frontend-Komponenten zur Berücksichtigung von unveränderlichen Feldern und zur Verbesserung der Benutzeroberfläche. Diese Anpassungen verbessern die Sicherheit der Benutzerdaten und erweitern die Funktionalität der Kontoeinstellungen.
387 lines
14 KiB
JavaScript
387 lines
14 KiB
JavaScript
import BaseService from './BaseService.js';
|
|
import UserParamType from '../models/type/user_param.js';
|
|
import SettingsType from '../models/type/settings.js';
|
|
import UserParam from '../models/community/user_param.js';
|
|
import User from '../models/community/user.js';
|
|
import UserParamValue from '../models/type/user_param_value.js';
|
|
import Interest from '../models/type/interest.js';
|
|
import UserInterest from '../models/community/interest.js';
|
|
import InterestTranslation from '../models/type/interest_translation.js';
|
|
import { Op } from 'sequelize';
|
|
import UserParamVisibilityType from '../models/type/user_param_visibility.js';
|
|
import UserParamVisibility from '../models/community/user_param_visibility.js';
|
|
import { generateIv } from '../utils/encryption.js';
|
|
|
|
class SettingsService extends BaseService{
|
|
async getUserParams(userId, paramDescriptions) {
|
|
return await UserParam.findAll({
|
|
where: { userId },
|
|
include: [
|
|
{
|
|
model: UserParamType,
|
|
as: 'paramType',
|
|
where: { description: { [Op.in]: paramDescriptions } },
|
|
order: [[ 'order_id', 'asc' ]]
|
|
}
|
|
]
|
|
});
|
|
}
|
|
|
|
async getFieldOptions(field) {
|
|
if (['singleselect', 'multiselect'].includes(field.datatype)) {
|
|
return await UserParamValue.findAll({
|
|
where: { userParamTypeId: field.id },
|
|
order: [[ 'order_id', 'asc' ]]
|
|
});
|
|
}
|
|
return [];
|
|
}
|
|
|
|
async filterSettings(hashedUserId, type) {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
const userParams = await this.getUserParams(user.id, ['birthdate', 'gender']);
|
|
let birthdate = null;
|
|
let gender = null;
|
|
for (const param of userParams) {
|
|
if (param.paramType.description === 'birthdate') {
|
|
birthdate = param.value;
|
|
}
|
|
if (param.paramType.description === 'gender') {
|
|
const genderResult = await UserParamValue.findOne({ where: { id: param.value } });
|
|
gender = genderResult ? genderResult.dataValues?.value : null;
|
|
}
|
|
}
|
|
const age = birthdate ? this.calculateAge(birthdate) : null;
|
|
const fields = await UserParamType.findAll({
|
|
include: [
|
|
{
|
|
model: SettingsType,
|
|
as: 'settings_type',
|
|
where: { name: type }
|
|
},
|
|
{
|
|
model: UserParam,
|
|
as: 'user_params',
|
|
required: false,
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'user',
|
|
where: { id: user.id }
|
|
},
|
|
{
|
|
model: UserParamVisibility,
|
|
as: 'param_visibilities',
|
|
required: false,
|
|
include: [
|
|
{
|
|
model: UserParamVisibilityType,
|
|
as: 'visibility_type'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
],
|
|
where: {
|
|
[Op.and]: [
|
|
{ minAge: { [Op.or]: [null, { [Op.lte]: age }] } },
|
|
{ gender: { [Op.or]: [null, gender] } }
|
|
]
|
|
}
|
|
});
|
|
return await Promise.all(fields.map(async (field) => {
|
|
const options = await this.getFieldOptions(field);
|
|
const visibilityData = field.user_params[0]?.param_visibilities?.[0];
|
|
const visibility = visibilityData
|
|
? { id: visibilityData.visibility_type?.id, description: visibilityData.visibility_type?.description }
|
|
: { id: null, description: 'Invisible' };
|
|
return {
|
|
id: field.id,
|
|
name: field.description,
|
|
minAge: field.minAge,
|
|
gender: field.gender,
|
|
datatype: field.datatype,
|
|
unit: field.unit,
|
|
immutable: field.immutable,
|
|
value: field.user_params.length > 0 ? field.user_params[0].value : null,
|
|
options: options.map(opt => ({ id: opt.id, value: opt.value })),
|
|
visibility
|
|
};
|
|
}));
|
|
}
|
|
|
|
async updateSetting(hashedUserId, settingId, value) {
|
|
try {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
const paramType = await UserParamType.findOne({ where: { id: settingId } });
|
|
if (!paramType) {
|
|
throw new Error('Parameter type not found');
|
|
}
|
|
|
|
// Prüfe ob das Feld unveränderlich ist
|
|
if (paramType.immutable) {
|
|
const userParam = await UserParam.findOne({
|
|
where: { userId: user.id, paramTypeId: settingId }
|
|
});
|
|
|
|
// Wenn bereits ein Wert existiert, ist das Feld unveränderlich
|
|
if (userParam && userParam.value) {
|
|
throw new Error('This field cannot be changed. Please contact support for modifications.');
|
|
}
|
|
}
|
|
|
|
const userParam = await UserParam.findOne({
|
|
where: { userId: user.id, paramTypeId: settingId }
|
|
});
|
|
if (userParam) {
|
|
console.log('update param with ', value)
|
|
if (typeof value === 'boolean') {
|
|
value = value ? 'true' : 'false';
|
|
}
|
|
await userParam.update({value: value});
|
|
} else {
|
|
await UserParam.create(
|
|
{
|
|
userId: user.id,
|
|
paramTypeId: settingId,
|
|
value: value
|
|
}
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating setting:', hashedUserId, settingId, value, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getTypeParamValueId(paramValue) {
|
|
const userParamValueObject = await UserParamValue.findOne({
|
|
where: { value: paramValue }
|
|
});
|
|
if (!userParamValueObject) {
|
|
throw new Error('Parameter value not found');
|
|
}
|
|
return userParamValueObject.id;
|
|
}
|
|
|
|
async getTypeParamValues(type) {
|
|
const userParamValues = await UserParamValue.findAll({
|
|
include: [
|
|
{
|
|
model: UserParamType,
|
|
as: 'user_param_value_type',
|
|
where: { description: type }
|
|
}
|
|
]
|
|
});
|
|
return userParamValues.map(type => ({ id: type.dataValues.id, name: type.dataValues.value }));
|
|
}
|
|
|
|
async getTypeParamValue(id) {
|
|
const userParamValueObject = await UserParamValue.findOne({
|
|
where: { id }
|
|
});
|
|
if (!userParamValueObject) {
|
|
throw new Error('Parameter value not found');
|
|
}
|
|
return userParamValueObject.value;
|
|
}
|
|
|
|
async addInterest(hashedUserId, name) {
|
|
try {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
|
|
const existingInterests = await Interest.findAll({ where: { name: name.toLowerCase() } });
|
|
if (existingInterests.length > 0) {
|
|
throw new Error('Interest already exists');
|
|
}
|
|
|
|
const userParam = await this.getUserParams(user.id, ['language']);
|
|
let language = 'en';
|
|
if (userParam.length > 0) {
|
|
const userParamValue = await UserParamValue.findOne({
|
|
where: { id: userParam[0].value }
|
|
});
|
|
language = userParamValue ? userParamValue.value : 'en';
|
|
}
|
|
|
|
const languageParam = await UserParamValue.findOne({ where: { value: language } });
|
|
const languageId = languageParam.id;
|
|
const interest = await Interest.create({ name: name.toLowerCase(), allowed: false, adultOnly: true });
|
|
await InterestTranslation.create({ interestsId: interest.id, language: languageId, translation: name });
|
|
return interest;
|
|
} catch (error) {
|
|
console.error('Error adding interest:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async addUserInterest(hashedUserId, interestId) {
|
|
try {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
|
|
const userParams = await this.getUserParams(user.id, ['birthdate']);
|
|
let birthdate = null;
|
|
for (const param of userParams) {
|
|
if (param.paramType.description === 'birthdate') {
|
|
birthdate = param.value;
|
|
}
|
|
}
|
|
|
|
const age = birthdate ? this.calculateAge(birthdate) : 0;
|
|
const interestsFilter = { id: interestId, allowed: true };
|
|
if (age < 18) {
|
|
interestsFilter[Op.or] = [
|
|
{ adultOnly: false },
|
|
{ adultOnly: { [Op.eq]: null } }
|
|
];
|
|
}
|
|
|
|
const existingInterests = await Interest.findAll({ where: interestsFilter });
|
|
if (existingInterests.length === 0) {
|
|
throw new Error('Interest not found');
|
|
};
|
|
|
|
const interest = await UserInterest.findAll({
|
|
where: { userId: user.id, userinterestId: interestId }
|
|
});
|
|
if (interest.length > 0) {
|
|
throw new Error('Interest already exists');
|
|
}
|
|
await UserInterest.create({ userId: user.id, userinterestId: interestId });
|
|
} catch (error) {
|
|
console.error('Error adding user interest:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async removeInterest(hashedUserId, interestId) {
|
|
try {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
const interests = await UserInterest.findAll({
|
|
where: { userId: user.id, userinterestId: interestId }
|
|
});
|
|
for (const interest of interests) {
|
|
await interest.destroy();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error removing interest:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getAccountSettings(hashedUserId) {
|
|
try {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
if (!user) {
|
|
throw new Error('User not found');
|
|
}
|
|
|
|
// Die Email wird automatisch durch den Getter entschlüsselt
|
|
// Falls die Entschlüsselung fehlschlägt, verwende null
|
|
let email = null;
|
|
try {
|
|
email = user.email; // Getter entschlüsselt automatisch
|
|
} catch (decryptError) {
|
|
console.warn('Email decryption failed, using null:', decryptError.message);
|
|
email = null;
|
|
}
|
|
|
|
return {
|
|
username: user.username,
|
|
email: email,
|
|
showinsearch: user.searchable
|
|
};
|
|
} catch (error) {
|
|
console.error('Error getting account settings:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async setAccountSettings({ userId, settings }) {
|
|
try {
|
|
const user = await this.getUserByHashedId(userId);
|
|
if (!user) {
|
|
throw new Error('User not found');
|
|
}
|
|
|
|
// Update username if provided
|
|
if (settings.username !== undefined) {
|
|
await user.update({ username: settings.username });
|
|
}
|
|
|
|
// Update email if provided
|
|
if (settings.email !== undefined) {
|
|
await user.update({ email: settings.email });
|
|
}
|
|
|
|
// Update searchable flag if provided
|
|
if (settings.showinsearch !== undefined) {
|
|
await user.update({ searchable: settings.showinsearch });
|
|
}
|
|
|
|
// Update password if provided and not empty
|
|
if (settings.newpassword && settings.newpassword.trim() !== '') {
|
|
if (!settings.oldpassword || settings.oldpassword.trim() === '') {
|
|
throw new Error('Old password is required to change password');
|
|
}
|
|
|
|
// Verify old password
|
|
const bcrypt = await import('bcrypt');
|
|
const match = await bcrypt.compare(settings.oldpassword, user.password);
|
|
if (!match) {
|
|
throw new Error('Old password is incorrect');
|
|
}
|
|
|
|
// Hash new password
|
|
const hashedPassword = await bcrypt.hash(settings.newpassword, 10);
|
|
await user.update({ password: hashedPassword });
|
|
}
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error('Error setting account settings:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async getVisibilities() {
|
|
return UserParamVisibilityType.findAll();
|
|
}
|
|
|
|
async updateVisibility(hashedUserId, userParamTypeId, visibilityId) {
|
|
try {
|
|
const user = await this.getUserByHashedId(hashedUserId);
|
|
if (!user) {
|
|
throw new Error('User not found');
|
|
}
|
|
const userParam = await UserParam.findOne({
|
|
where: { paramTypeId: userParamTypeId, userId: user.id }
|
|
});
|
|
if (!userParam) {
|
|
console.error(`UserParam not found for settingId: ${userParamTypeId} and userId: ${user.id}`);
|
|
throw new Error('User parameter not found or does not belong to the user');
|
|
}
|
|
let userParamVisibility = await UserParamVisibility.findOne({
|
|
where: { param_id: userParam.id }
|
|
});
|
|
if (userParamVisibility) {
|
|
userParamVisibility.visibility = visibilityId;
|
|
await userParamVisibility.save();
|
|
} else {
|
|
await UserParamVisibility.create({
|
|
param_id: userParam.id,
|
|
visibility: visibilityId
|
|
});
|
|
}
|
|
console.log(`Visibility updated for settingId: ${userParamTypeId} with visibilityId: ${visibilityId}`);
|
|
} catch (error) {
|
|
console.error('Error updating visibility:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
export default new SettingsService();
|