From f1b6dd74f70c56d677faf33f88782bae16ddf5eb Mon Sep 17 00:00:00 2001 From: Torsten Schulz Date: Sat, 21 Sep 2024 15:26:29 +0200 Subject: [PATCH] Changed controllers to classes, added image functionality --- backend/controllers/adminController.js | 159 +++++---- backend/controllers/authController.js | 84 +++-- backend/controllers/chatController.js | 116 ++++-- backend/controllers/contactController.js | 24 +- backend/controllers/navigationController.js | 127 ++++--- backend/controllers/settingsController.js | 296 +++++++-------- .../controllers/socialnetworkController.js | 48 +++ backend/models/associations.js | 14 + backend/models/community/folder.js | 41 +++ backend/models/community/image.js | 54 +++ backend/models/index.js | 4 + backend/routers/adminRouter.js | 19 +- backend/routers/authRouter.js | 11 +- backend/routers/chatRouter.js | 16 +- backend/routers/contactRouter.js | 21 +- backend/routers/navigationRouter.js | 7 +- backend/routers/settingsRouter.js | 32 +- backend/routers/socialnetworkRouter.js | 6 + backend/services/socialnetworkService.js | 336 +++++++++--------- .../src/i18n/locales/de/socialnetwork.json | 2 +- 20 files changed, 836 insertions(+), 581 deletions(-) create mode 100644 backend/models/community/folder.js create mode 100644 backend/models/community/image.js diff --git a/backend/controllers/adminController.js b/backend/controllers/adminController.js index 2963eef..506686d 100644 --- a/backend/controllers/adminController.js +++ b/backend/controllers/adminController.js @@ -1,79 +1,94 @@ import AdminService from '../services/adminService.js'; import Joi from 'joi'; -export const getOpenInterests = async (req, res) => { - try { - const { userid: userId} = req.headers; - const openInterests = await AdminService.getOpenInterests(userId); - res.status(200).json(openInterests); - } catch (error) { - res.status(403).json({error: error.message }); +class AdminController { + constructor() { + this.getOpenInterests = this.getOpenInterests.bind(this); + this.changeInterest = this.changeInterest.bind(this); + this.deleteInterest = this.deleteInterest.bind(this); + this.changeTranslation = this.changeTranslation.bind(this); + this.getOpenContacts = this.getOpenContacts.bind(this); + this.answerContact = this.answerContact.bind(this); } -} -export const changeInterest = async (req, res) => { - try { - const { userid: userId } = req.headers; - const { id: interestId, active, adult: adultOnly} = req.body; - AdminService.changeInterest(userId, interestId, active, adultOnly); - res.status(200).json(AdminService.getOpenInterests(userId)); - } catch (error) { - res.status(403).json({ error: error.message }); - } -} - -export const deleteInterest = async (req, res) => { - try { - const { userid: userId } = req.headers; - const { id: interestId } = req.params; - AdminService.deleteInterest(userId, interestId); - res.status(200).json(AdminService.getOpenInterests(userId)); - } catch (error) { - res.status(403).json({ error: error.message }); - } -} - -export const changeTranslation = async (req, res) => { - try { - const { userid: userId } = req.headers; - const { id: interestId, translations } = req.body; - AdminService.changeTranslation(userId, interestId, translations); - res.status(200).json(AdminService.getOpenInterests(userId)) - } catch(error) { - res.status(403).json({ error: error.message }); - } -} - -export const getOpenContacts = async (req, res) => { - try { - const { userid: userId } = req.headers; - const openContacts = await AdminService.getOpenContacts(userId); - res.status(200).json(openContacts); - } catch (error) { - res.status(403).json({ error: error.message }); - } -} - -export const answerContact = async (req, res) => { - try { - const schema = Joi.object({ - id: Joi.number().integer().required(), - answer: Joi.string().min(1).required() - }); - - const { error, value } = schema.validate(req.body); - - if (error) { - return res.status(400).json({ error: error.details[0].message }); + async getOpenInterests(req, res) { + try { + const { userid: userId } = req.headers; + const openInterests = await AdminService.getOpenInterests(userId); + res.status(200).json(openInterests); + } catch (error) { + res.status(403).json({ error: error.message }); } - - const { id, answer } = value; - - await AdminService.answerContact(id, answer); - - res.status(200).json({ status: 'ok' }); - } catch (error) { - console.error('Error in answerContact:', error); - res.status(error.status || 500).json({ error: error.message || 'Internal Server Error' }); } -}; \ No newline at end of file + + async changeInterest(req, res) { + try { + const { userid: userId } = req.headers; + const { id: interestId, active, adult: adultOnly } = req.body; + await AdminService.changeInterest(userId, interestId, active, adultOnly); + const updatedInterests = await AdminService.getOpenInterests(userId); + res.status(200).json(updatedInterests); + } catch (error) { + res.status(403).json({ error: error.message }); + } + } + + async deleteInterest(req, res) { + try { + const { userid: userId } = req.headers; + const { id: interestId } = req.params; + await AdminService.deleteInterest(userId, interestId); + const updatedInterests = await AdminService.getOpenInterests(userId); + res.status(200).json(updatedInterests); + } catch (error) { + res.status(403).json({ error: error.message }); + } + } + + async changeTranslation(req, res) { + try { + const { userid: userId } = req.headers; + const { id: interestId, translations } = req.body; + await AdminService.changeTranslation(userId, interestId, translations); + const updatedInterests = await AdminService.getOpenInterests(userId); + res.status(200).json(updatedInterests); + } catch (error) { + res.status(403).json({ error: error.message }); + } + } + + async getOpenContacts(req, res) { + try { + const { userid: userId } = req.headers; + const openContacts = await AdminService.getOpenContacts(userId); + res.status(200).json(openContacts); + } catch (error) { + res.status(403).json({ error: error.message }); + } + } + + async answerContact(req, res) { + try { + const schema = Joi.object({ + id: Joi.number().integer().required(), + answer: Joi.string().min(1).required(), + }); + + const { error, value } = schema.validate(req.body); + + if (error) { + return res.status(400).json({ error: error.details[0].message }); + } + + const { id, answer } = value; + + await AdminService.answerContact(id, answer); + res.status(200).json({ status: 'ok' }); + } catch (error) { + console.error('Error in answerContact:', error); + res.status(error.status || 500).json({ error: error.message || 'Internal Server Error' }); + } + } +} + +export default AdminController; diff --git a/backend/controllers/authController.js b/backend/controllers/authController.js index 17174de..43576c5 100644 --- a/backend/controllers/authController.js +++ b/backend/controllers/authController.js @@ -1,49 +1,57 @@ import * as userService from '../services/authService.js'; -export const register = async (req, res) => { - const { email, username, password, language } = req.body; - - try { - const result = await userService.registerUser({ email, username, password, language }); - res.status(201).json(result); - } catch (error) { - console.log(error); - res.status(500).json({ error: error.message }); +class AuthController { + constructor() { + this.register = this.register.bind(this); + this.login = this.login.bind(this); + this.forgotPassword = this.forgotPassword.bind(this); + this.activateAccount = this.activateAccount.bind(this); } -}; -export const login = async (req, res) => { - const { username, password } = req.body; - try { - const result = await userService.loginUser({ username, password }); - res.status(200).json(result); - } catch (error) { - if (error.message === 'credentialsinvalid') { - res.status(404).json({ error: error.message }) - } else { + async register(req, res) { + const { email, username, password, language } = req.body; + try { + const result = await userService.registerUser({ email, username, password, language }); + res.status(201).json(result); + } catch (error) { + console.log(error); res.status(500).json({ error: error.message }); } } -}; -export const forgotPassword = async (req, res) => { - const { email } = req.body; - - try { - const result = await userService.handleForgotPassword({ email }); - res.status(200).json(result); - } catch (error) { - res.status(500).json({ error: error.message }); + async login(req, res) { + const { username, password } = req.body; + try { + const result = await userService.loginUser({ username, password }); + res.status(200).json(result); + } catch (error) { + if (error.message === 'credentialsinvalid') { + res.status(404).json({ error: error.message }); + } else { + res.status(500).json({ error: error.message }); + } + } } -}; -export const activateAccount = async (req, res) => { - const { token } = req.body; - - try { - const result = await userService.activateUserAccount({ token }); - res.status(200).json(result); - } catch (error) { - res.status(500).json({ error: error.message }); + async forgotPassword(req, res) { + const { email } = req.body; + try { + const result = await userService.handleForgotPassword({ email }); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + } } -}; + + async activateAccount(req, res) { + const { token } = req.body; + try { + const result = await userService.activateUserAccount({ token }); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } +} + +export default AuthController; diff --git a/backend/controllers/chatController.js b/backend/controllers/chatController.js index eb7e1a4..01084ef 100644 --- a/backend/controllers/chatController.js +++ b/backend/controllers/chatController.js @@ -1,43 +1,85 @@ -import { getMessages as getMessagesService, findMatch, registerUser as registerUserService, addMessage, endChat } from '../services/chatService.js'; +import { + getMessages as getMessagesService, + findMatch, + registerUser as registerUserService, + addMessage, + endChat, + removeUser as removeUserService +} from '../services/chatService.js'; -export const getMessages = (req, res) => { - const { to, from } = req.body; - const messages = getMessagesService(to, from); - res.status(200).json(messages); -}; - -export const findRandomChatMatch = (req, res) => { - const { genders, age, id } = req.body; - const match = findMatch(genders, age, id); - if (match) { - res.status(200).json({ status: 'matched', user: match }); - } else { - res.status(200).json({ status: 'waiting' }); +class ChatController { + constructor() { + this.getMessages = this.getMessages.bind(this); + this.findRandomChatMatch = this.findRandomChatMatch.bind(this); + this.registerUser = this.registerUser.bind(this); + this.sendMessage = this.sendMessage.bind(this); + this.stopChat = this.stopChat.bind(this); + this.removeUser = this.removeUser.bind(this); } -}; -export const registerUser = (req, res) => { - const { gender, age } = req.body; - const userId = registerUserService(gender, age); - res.status(200).json({ id: userId }); -}; + async getMessages(req, res) { + const { to, from } = req.body; + try { + const messages = await getMessagesService(to, from); + res.status(200).json(messages); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } -export const sendMessage = (req, res) => { - const from = req.body.from; - const to = req.body.to; - const text = req.body.text; - const message = addMessage(from, to, text); - res.status(200).json(message); -}; + async findRandomChatMatch(req, res) { + const { genders, age, id } = req.body; + try { + const match = await findMatch(genders, age, id); + if (match) { + res.status(200).json({ status: 'matched', user: match }); + } else { + res.status(200).json({ status: 'waiting' }); + } + } catch (error) { + res.status(500).json({ error: error.message }); + } + } -export const removeUser = (req, res) => { - const { id } = req.body; - removeUserService(id); - res.sendStatus(200); -}; + async registerUser(req, res) { + const { gender, age } = req.body; + try { + const userId = await registerUserService(gender, age); + res.status(200).json({ id: userId }); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } -export const stopChat = (req, res) => { - const { id } = req.body; - endChat(id); - res.sendStatus(200); -} \ No newline at end of file + async sendMessage(req, res) { + const { from, to, text } = req.body; + try { + const message = await addMessage(from, to, text); + res.status(200).json(message); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } + + async removeUser(req, res) { + const { id } = req.body; + try { + await removeUserService(id); + res.sendStatus(200); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } + + async stopChat(req, res) { + const { id } = req.body; + try { + await endChat(id); + res.sendStatus(200); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } +} + +export default ChatController; diff --git a/backend/controllers/contactController.js b/backend/controllers/contactController.js index dbff2c2..a0803d2 100644 --- a/backend/controllers/contactController.js +++ b/backend/controllers/contactController.js @@ -1,11 +1,19 @@ import ContactService from '../services/ContactService.js'; -export const addContactMessage = async(req, res) => { - try { - const { email, name, message, acceptDataSave } = req.body; - await ContactService.addContactMessage(email, name, message, acceptDataSave); - res.status(200).json({ status: 'ok' }); - } catch (error) { - res.status(409).json({ error: error }); +class ContactController { + constructor() { + this.addContactMessage = this.addContactMessage.bind(this); } -} \ No newline at end of file + + async addContactMessage(req, res) { + try { + const { email, name, message, acceptDataSave } = req.body; + await ContactService.addContactMessage(email, name, message, acceptDataSave); + res.status(200).json({ status: 'ok' }); + } catch (error) { + res.status(409).json({ error: error.message }); + } + } +} + +export default ContactController; diff --git a/backend/controllers/navigationController.js b/backend/controllers/navigationController.js index 2f25c21..08e1461 100644 --- a/backend/controllers/navigationController.js +++ b/backend/controllers/navigationController.js @@ -2,7 +2,7 @@ import User from '../models/community/user.js'; import UserParam from '../models/community/user_param.js'; import UserRight from '../models/community/user_right.js'; import UserRightType from '../models/type/user_right.js'; -import UserParamType from '../models/type/user_param.js'; +import UserParamType from '../models/type/user_param.js'; const menuStructure = { home: { @@ -14,7 +14,7 @@ const menuStructure = { friends: { visible: ["all"], children: { - manageFriends : { + manageFriends: { visible: ["all"], path: "/socialnetwork/friends", icon: "friends24.png" @@ -70,7 +70,7 @@ const menuStructure = { visible: ["over12"], action: "openRanomChat" } - } + } }, falukant: { visible: ["all"], @@ -220,75 +220,74 @@ const menuStructure = { } }; -const calculateAge = (birthDate) => { - const today = new Date(); - const birthDateObj = new Date(birthDate); - let age = today.getFullYear() - birthDateObj.getFullYear(); - const monthDiff = today.getMonth() - birthDateObj.getMonth(); - if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDateObj.getDate())) { - age--; +class NavigationController { + constructor() { + this.menu = this.menu.bind(this); } - return age; -}; + calculateAge(birthDate) { + const today = new Date(); + const birthDateObj = new Date(birthDate); + let age = today.getFullYear() - birthDateObj.getFullYear(); + const monthDiff = today.getMonth() - birthDateObj.getMonth(); + if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDateObj.getDate())) { + age--; + } + return age; + } -const filterMenu = (menu, rights, age) => { - const filteredMenu = {}; - for (const [key, value] of Object.entries(menu)) { - if (value.visible.includes("all") - || value.visible.some(v => rights.includes(v) - || (value.visible.includes("anyadmin") && rights.length > 0)) - || (value.visible.includes("over14") && age >= 14)) { - const { visible, ...itemWithoutVisible } = value; - filteredMenu[key] = { ...itemWithoutVisible }; - if (value.children) { - filteredMenu[key].children = filterMenu(value.children, rights, age); + filterMenu(menu, rights, age) { + const filteredMenu = {}; + for (const [key, value] of Object.entries(menu)) { + if (value.visible.includes("all") + || value.visible.some(v => rights.includes(v) + || (value.visible.includes("anyadmin") && rights.length > 0)) + || (value.visible.includes("over14") && age >= 14)) { + const { visible, ...itemWithoutVisible } = value; + filteredMenu[key] = { ...itemWithoutVisible }; + if (value.children) { + filteredMenu[key].children = this.filterMenu(value.children, rights, age); + } } } + return filteredMenu; } - return filteredMenu; -}; -export const menu = async (req, res) => { - try { - const { userid } = req.params; - const user = await User.findOne({ where: { hashedId: userid } }); - if (!user) { - return res.status(404).json({ error: 'User not found' }); - } - const userRights = await UserRight.findAll({ - where: { userId: user.id }, - include: [{ - model: UserRightType, - as: 'rightType', - required: false - }] - }); - const userBirthdateParams = await UserParam.findAll({ - where: { - userId: user.id - }, - include: [ - { - model: UserParamType, - as: 'paramType', - where: { - description: 'birthdate' + async menu(req, res) { + try { + const { userid } = req.params; + const user = await User.findOne({ where: { hashedId: userid } }); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + const userRights = await UserRight.findAll({ + where: { userId: user.id }, + include: [{ + model: UserRightType, + as: 'rightType', + required: false + }] + }); + const userBirthdateParams = await UserParam.findAll({ + where: { userId: user.id }, + include: [ + { + model: UserParamType, + as: 'paramType', + where: { description: 'birthdate' } } - } - ] - }); - const ageFunction = function() { + ] + }); const birthDate = userBirthdateParams.length > 0 ? userBirthdateParams[0].value : (new Date()).toDateString(); - const age = calculateAge(birthDate); - return age; + const age = this.calculateAge(birthDate); + const rights = userRights.map(ur => ur.rightType.title); + const filteredMenu = this.filterMenu(menuStructure, rights, age); + res.status(200).json(filteredMenu); + } catch (error) { + console.error('Error fetching menu:', error); + res.status(500).json({ error: 'An error occurred while fetching the menu' }); } - const age = ageFunction(); - const rights = userRights.map(ur => ur.rightType.title); - const filteredMenu = filterMenu(menuStructure, rights, age); - res.status(200).json(filteredMenu); - } catch (error) { - console.error('Error fetching menu:', error); - res.status(500).json({ error: 'An error occurred while fetching the menu' }); } -}; \ No newline at end of file +} + +export default NavigationController; diff --git a/backend/controllers/settingsController.js b/backend/controllers/settingsController.js index 574db9d..5aad797 100644 --- a/backend/controllers/settingsController.js +++ b/backend/controllers/settingsController.js @@ -1,157 +1,161 @@ import settingsService from '../services/settingsService.js'; -export const filterSettings = async (req, res) => { - const { userid, type } = req.body; - try { - const responseFields = await settingsService.filterSettings(userid, type); - res.status(200).json(responseFields); - } catch (error) { - console.error('Error filtering settings:', error); - res.status(500).json({ error: 'An error occurred while filtering the settings' }); +class SettingsController { + async filterSettings(req, res) { + const { userid, type } = req.body; + try { + const responseFields = await settingsService.filterSettings(userid, type); + res.status(200).json(responseFields); + } catch (error) { + console.error('Error filtering settings:', error); + res.status(500).json({ error: 'An error occurred while filtering the settings' }); + } } -}; -export const updateSetting = async (req, res) => { - const { userid, settingId, value } = req.body; - try { - await settingsService.updateSetting(userid, settingId, value); - res.status(200).json({ message: 'Setting updated successfully' }); - } catch (error) { - console.error('Error updating user setting:', error); - res.status(500).json({ error: 'Internal server error' }); + async updateSetting(req, res) { + const { userid, settingId, value } = req.body; + try { + await settingsService.updateSetting(userid, settingId, value); + res.status(200).json({ message: 'Setting updated successfully' }); + } catch (error) { + console.error('Error updating user setting:', error); + res.status(500).json({ error: 'Internal server error' }); + } } -}; -export const getTypeParamValueId = async (req, res) => { - const { paramValue } = req.body; - try { - const paramValueId = await settingsService.getTypeParamValueId(paramValue); - res.status(200).json({ paramValueId }); - } catch (error) { - console.error('Error retrieving parameter value ID:', error); - res.status(404).json({ error: "notfound" }); + async getTypeParamValueId(req, res) { + const { paramValue } = req.body; + try { + const paramValueId = await settingsService.getTypeParamValueId(paramValue); + res.status(200).json({ paramValueId }); + } catch (error) { + console.error('Error retrieving parameter value ID:', error); + res.status(404).json({ error: "notfound" }); + } } -}; -export const getTypeParamValues = async (req, res) => { - const { type } = req.body; - try { - const paramValues = await settingsService.getTypeParamValues(type); - res.status(200).json(paramValues); - } catch (error) { - console.error('Error retrieving parameter values:', error); - res.status(500).json({ error: 'An error occurred while retrieving the parameter values' }); + async getTypeParamValues(req, res) { + const { type } = req.body; + try { + const paramValues = await settingsService.getTypeParamValues(type); + res.status(200).json(paramValues); + } catch (error) { + console.error('Error retrieving parameter values:', error); + res.status(500).json({ error: 'An error occurred while retrieving the parameter values' }); + } + } + + async getTypeParamValue(req, res) { + const { id } = req.params; + try { + const paramValue = await settingsService.getTypeParamValue(id); + res.status(200).json({ paramValue }); + } catch (error) { + console.error('Error retrieving parameter value:', error); + res.status(404).json({ error: "notfound" }); + } + } + + async getAccountSettings(req, res) { + try { + const { userId } = req.body; + const accountSettings = await settingsService.getAccountSettings(userId); + res.status(200).json(accountSettings); + } catch (error) { + console.error('Error retrieving account settings:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async setAccountSettings(req, res) { + try { + await settingsService.setAccountSettings(req.body); + res.status(200).json({ message: 'Account settings updated successfully' }); + } catch (error) { + console.error('Error updating account settings:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async getPossibleInterests(req, res) { + try { + const { userid: userId } = req.headers; + const interests = await settingsService.getPossibleInterests(userId); + res.status(200).json(interests); + } catch (error) { + console.error('Error retrieving possible interests:', error); + res.status(500).json({ error: 'An error occurred while retrieving the possible interests' }); + } + } + + async getInterests(req, res) { + try { + const { userid: userId } = req.headers; + const interests = await settingsService.getInterests(userId); + res.status(200).json(interests); + } catch (error) { + console.error('Error retrieving interests:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async addInterest(req, res) { + try { + const { userid: userId } = req.headers; + const { name } = req.body; + const interest = await settingsService.addInterest(userId, name); + res.status(200).json({ interest }); + } catch (error) { + console.error('Error adding interest:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async addUserInterest(req, res) { + try { + const { userid: userId } = req.headers; + const { interestid: interestId } = req.body; + await settingsService.addUserInterest(userId, interestId); + res.status(200).json({ message: 'User interest added successfully' }); + } catch (error) { + console.error('Error adding user interest:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async removeInterest(req, res) { + try { + const { userid: userId } = req.headers; + const { id: interestId } = req.params; + await settingsService.removeInterest(userId, interestId); + res.status(200).json({ message: 'Interest removed successfully' }); + } catch (error) { + console.error('Error removing interest:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async getVisibilities(req, res) { + try { + const visibilities = await settingsService.getVisibilities(); + res.status(200).json(visibilities); + } catch (error) { + console.error('Error retrieving visibilities:', error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async updateVisibility(req, res) { + const { userParamTypeId, visibilityId } = req.body; + const hashedUserId = req.headers.userid; + try { + await settingsService.updateVisibility(hashedUserId, userParamTypeId, visibilityId); + res.status(200).json({ message: 'Visibility updated successfully' }); + } catch (error) { + console.error('Error updating visibility:', error); + res.status(500).json({ error: 'Internal server error' }); + } } } -export const getTypeParamValue = async (req, res) => { - const { id } = req.params; - try { - const paramValue = await settingsService.getTypeParamValue(id); - res.status(200).json({ paramValue }); - } catch (error) { - console.error('Error retrieving parameter value:', error); - res.status(404).json({ error: "notfound" }); - } -}; - -export const getAccountSettings = async (req, res) => { - try { - const { userId } = req.body; - const accountSettings = await settingsService.getAccountSettings(userId); - res.status(200).json(accountSettings); - } catch (error) { - console.error('Error retrieving account settings:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}; - -export const setAccountSettings = async (req, res) => { - try { - await settingsService.setAccountSettings(req.body); - res.status(200).json({ message: 'Account settings updated successfully' }); - } catch (error) { - console.error('Error updating account settings:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}; - -export const getPossibleInterests = async (req, res) => { - try { - const { userid: userId } = req.headers; - const interests = await settingsService.getPossibleInterests(userId); - res.status(200).json(interests); - } catch (error) { - console.error('Error retrieving possible interests:', error); - res.status(500).json({ error: 'An error occurred while retrieving the possible interests' }); - } -} - -export const getInterests = async (req, res) => { - try { - const { userid: userId } = req.headers; - const interests = await settingsService.getInterests(userId); - res.status(200).json(interests); - } catch (error) { - console.error('Error retrieving interests:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export const addInterest = async (req, res) => { - try { - const { userid: userId } = req.headers; - const { name } = req.body; - const interest = await settingsService.addInterest(userId, name); - res.status(200).json({ interest }); - } catch (error) { - console.error('Error adding interest:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export const addUserInterest = async (req, res) => { - try { - const { userid: userId } = req.headers; - const { interestid: interestId } = req.body; - await settingsService.addUserInterest(userId, interestId); - res.status(200).json({ message: 'User interest added successfully' }); - } catch (error) { - console.error('Error adding user interest:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export const removeInterest = async (req, res) => { - try { - const { userid: userId } = req.headers; - const { id: interestId } = req.params; - await settingsService.removeInterest(userId, interestId); - res.status(200).json({ message: 'Interest removed successfully' }); - } catch (error) { - console.error('Error removing interest:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export const getVisibilities = async (req, res) => { - try { - const visibilities = await settingsService.getVisibilities(); - res.status(200).json(visibilities); - } catch (error) { - console.error('Error retrieving visibilities:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export const updateVisibility = async (req, res) => { - const { userParamTypeId, visibilityId } = req.body; - const hashedUserId = req.headers.userid; - try { - await settingsService.updateVisibility(hashedUserId, userParamTypeId, visibilityId); - res.status(200).json({ message: 'Visibility updated successfully' }); - } catch (error) { - console.error('Error updating visibility:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}; +export default SettingsController; diff --git a/backend/controllers/socialnetworkController.js b/backend/controllers/socialnetworkController.js index 4709038..223ba72 100644 --- a/backend/controllers/socialnetworkController.js +++ b/backend/controllers/socialnetworkController.js @@ -5,6 +5,10 @@ class SocialNetworkController { this.socialNetworkService = new SocialNetworkService(); this.userSearch = this.userSearch.bind(this); this.profile = this.profile.bind(this); + this.createFolder = this.createFolder.bind(this); + this.getFolders = this.getFolders.bind(this); + this.uploadImage = this.uploadImage.bind(this); + this.getImage = this.getImage.bind(this); } async userSearch(req, res) { @@ -32,6 +36,50 @@ class SocialNetworkController { res.status(500).json({ error: error.message }); } } + + async createFolder(req, res) { + try { + const folderData = req.body; + const folder = await this.socialNetworkService.createFolder(folderData); + res.status(201).json(folder); + } catch (error) { + console.error('Error in createFolder:', error); + res.status(500).json({ error: error.message }); + } + } + + async getFolders(req, res) { + try { + const userId = req.headers.userid; + const folders = await this.socialNetworkService.getFolders(userId); + res.status(200).json(folders); + } catch (error) { + console.error('Error in getFolders:', error); + res.status(500).json({ error: error.message }); + } + } + + async uploadImage(req, res) { + try { + const imageData = req.body; + const image = await this.socialNetworkService.uploadImage(imageData); + res.status(201).json(image); + } catch (error) { + console.error('Error in uploadImage:', error); + res.status(500).json({ error: error.message }); + } + } + + async getImage(req, res) { + try { + const { imageId } = req.params; + const image = await this.socialNetworkService.getImage(imageId); + res.status(200).json(image); + } catch (error) { + console.error('Error in getImage:', error); + res.status(500).json({ error: error.message }); + } + } } export default SocialNetworkController; diff --git a/backend/models/associations.js b/backend/models/associations.js index d2449ad..e0b9cbe 100644 --- a/backend/models/associations.js +++ b/backend/models/associations.js @@ -10,6 +10,8 @@ import InterestTranslationType from './type/interest_translation.js'; import Interest from './community/interest.js'; import UserParamVisibilityType from './type/user_param_visibility.js'; import UserParamVisibility from './community/user_param_visibility.js'; +import Folder from './community/folder.js'; +import Image from './community/image.js'; export default function setupAssociations() { SettingsType.hasMany(UserParamType, { foreignKey: 'settingsId', as: 'user_param_types' }); @@ -43,4 +45,16 @@ export default function setupAssociations() { UserParamVisibility.belongsTo(UserParamVisibilityType, { foreignKey: 'visibility', as: 'visibility_type' }); UserParamVisibilityType.hasMany(UserParamVisibility, { foreignKey: 'visibility', as: 'user_param_visibilities' }); + + Folder.belongsTo(User, { foreignKey: 'userId' }); + User.hasMany(Folder, { foreignKey: 'userId' }); + + Folder.belongsTo(Folder, { foreignKey: 'parentId', as: 'parent' }); + Folder.hasMany(Folder, { foreignKey: 'parentId', as: 'children' }); + + Image.belongsTo(Folder, { foreignKey: 'folderId' }); + Folder.hasMany(Image, { foreignKey: 'folderId' }); + + Image.belongsTo(User, { foreignKey: 'userId' }); + User.hasMany(Image, { foreignKey: 'userId' }); } diff --git a/backend/models/community/folder.js b/backend/models/community/folder.js new file mode 100644 index 0000000..798ab5b --- /dev/null +++ b/backend/models/community/folder.js @@ -0,0 +1,41 @@ +import { sequelize } from '../../utils/sequelize.js'; +import { DataTypes } from 'sequelize'; +import UserParamVisibilityType from '../type/user_param_visibility.js'; + +const Folder = sequelize.define('folder', { + name: { + type: DataTypes.STRING, + allowNull: false, + }, + parentId: { + type: DataTypes.INTEGER, + allowNull: true, + references: { + model: 'folder', + key: 'id', + }, + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'user', + key: 'id', + }, + }, + visibilityType: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: UserParamVisibilityType, + key: 'id', + }, + }, +}, { + tableName: 'folder', + schema: 'community', + underscored: true, + timestamps: true, +}); + +export default Folder; diff --git a/backend/models/community/image.js b/backend/models/community/image.js new file mode 100644 index 0000000..879486a --- /dev/null +++ b/backend/models/community/image.js @@ -0,0 +1,54 @@ +import { sequelize } from '../../utils/sequelize.js'; +import { DataTypes } from 'sequelize'; +import UserParamVisibilityType from '../type/user_param_visibility.js'; + +const Image = sequelize.define('image', { + title: { + type: DataTypes.STRING, + allowNull: false, + }, + description: { + type: DataTypes.TEXT, + allowNull: true, + }, + originalFileName: { + type: DataTypes.STRING, + allowNull: false, + }, + hash: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + folderId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'folder', + key: 'id', + }, + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'user', + key: 'id', + }, + }, + visibilityType: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: UserParamVisibilityType, + key: 'id', + }, + }, +}, { + tableName: 'image', + schema: 'community', + underscored: true, + timestamps: true, +}); + +export default Image; diff --git a/backend/models/index.js b/backend/models/index.js index a773ece..fc270b3 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -12,6 +12,8 @@ import Interest from './community/interest.js'; import ContactMessage from './service/contactmessage.js'; import UserParamVisibilityType from './type/user_param_visibility.js'; import UserParamVisibility from './community/user_param_visibility.js'; +import Folder from './community/folder.js'; +import Image from './community/image.js'; const models = { SettingsType, @@ -28,6 +30,8 @@ const models = { ContactMessage, UserParamVisibilityType, UserParamVisibility, + Folder, + Image, }; export default models; diff --git a/backend/routers/adminRouter.js b/backend/routers/adminRouter.js index ee476c7..d99b3fc 100644 --- a/backend/routers/adminRouter.js +++ b/backend/routers/adminRouter.js @@ -1,16 +1,15 @@ import { Router } from 'express'; import { authenticate } from '../middleware/authMiddleware.js'; -import { getOpenInterests, changeInterest, deleteInterest, changeTranslation, getOpenContacts, answerContact } from '../controllers/adminController.js'; +import AdminController from '../controllers/adminController.js'; const router = Router(); +const adminController = new AdminController(); -router.get('/interests/open', authenticate, getOpenInterests); -router.post('/interest', authenticate, changeInterest); -router.post('/interest/translation', authenticate, changeTranslation); -router.delete('/interest/:id', authenticate, deleteInterest); +router.get('/interests/open', authenticate, adminController.getOpenInterests); +router.post('/interest', authenticate, adminController.changeInterest); +router.post('/interest/translation', authenticate, adminController.changeTranslation); +router.delete('/interest/:id', authenticate, adminController.deleteInterest); +router.get('/opencontacts', authenticate, adminController.getOpenContacts); +router.post('/contacts/answer', authenticate, adminController.answerContact); -router.get('/opencontacts', authenticate, getOpenContacts); -router.post('/contacts/answer', answerContact); - - -export default router; \ No newline at end of file +export default router; diff --git a/backend/routers/authRouter.js b/backend/routers/authRouter.js index 47396bc..c507027 100644 --- a/backend/routers/authRouter.js +++ b/backend/routers/authRouter.js @@ -1,11 +1,12 @@ import { Router } from 'express'; -import { register, login, forgotPassword, activateAccount } from '../controllers/authController.js'; +import AuthController from '../controllers/authController.js'; const router = Router(); +const authController = new AuthController(); -router.post('/register', register); -router.post('/login', login); -router.post('/forgot-password', forgotPassword); -router.post('/activate', activateAccount); +router.post('/register', authController.register); +router.post('/login', authController.login); +router.post('/forgot-password', authController.forgotPassword); +router.post('/activate', authController.activateAccount); export default router; diff --git a/backend/routers/chatRouter.js b/backend/routers/chatRouter.js index 19f455e..5cee572 100644 --- a/backend/routers/chatRouter.js +++ b/backend/routers/chatRouter.js @@ -1,14 +1,14 @@ import { Router } from 'express'; -import { getMessages, findRandomChatMatch, registerUser, sendMessage, stopChat, removeUser } from '../controllers/chatController.js'; +import ChatController from '../controllers/chatController.js'; const router = Router(); +const chatController = new ChatController(); -router.get('/messages', getMessages); -router.post('/findMatch', findRandomChatMatch); -router.post('/register', registerUser); -router.post('/sendMessage', sendMessage); -router.post('/getMessages', getMessages); -router.post('/leave', stopChat); -router.post('/exit', removeUser); +router.get('/messages', chatController.getMessages); +router.post('/findMatch', chatController.findRandomChatMatch); +router.post('/register', chatController.registerUser); +router.post('/sendMessage', chatController.sendMessage); +router.post('/leave', chatController.stopChat); +router.post('/exit', chatController.removeUser); export default router; diff --git a/backend/routers/contactRouter.js b/backend/routers/contactRouter.js index 2c6d06c..a0803d2 100644 --- a/backend/routers/contactRouter.js +++ b/backend/routers/contactRouter.js @@ -1,8 +1,19 @@ -import { Router } from 'express'; -import { addContactMessage } from '../controllers/contactController.js'; +import ContactService from '../services/ContactService.js'; -const router = Router(); +class ContactController { + constructor() { + this.addContactMessage = this.addContactMessage.bind(this); + } -router.post('/', addContactMessage); + async addContactMessage(req, res) { + try { + const { email, name, message, acceptDataSave } = req.body; + await ContactService.addContactMessage(email, name, message, acceptDataSave); + res.status(200).json({ status: 'ok' }); + } catch (error) { + res.status(409).json({ error: error.message }); + } + } +} -export default router; \ No newline at end of file +export default ContactController; diff --git a/backend/routers/navigationRouter.js b/backend/routers/navigationRouter.js index 42d8f31..c41da7b 100644 --- a/backend/routers/navigationRouter.js +++ b/backend/routers/navigationRouter.js @@ -1,10 +1,11 @@ import { Router } from 'express'; -import { menu } from '../controllers/navigationController.js'; +import NavigationController from '../controllers/navigationController.js'; import { authenticate } from '../middleware/authMiddleware.js'; const router = Router(); +const navigationController = new NavigationController(); router.use(authenticate); -router.get('/:userid', menu); +router.get('/:userid', navigationController.menu); -export default router; \ No newline at end of file +export default router; diff --git a/backend/routers/settingsRouter.js b/backend/routers/settingsRouter.js index d1df743..3cabda2 100644 --- a/backend/routers/settingsRouter.js +++ b/backend/routers/settingsRouter.js @@ -1,24 +1,22 @@ import { Router } from 'express'; -import { filterSettings, updateSetting, getTypeParamValueId, getTypeParamValues, getTypeParamValue, getAccountSettings, - getPossibleInterests, getInterests, addInterest, addUserInterest, removeInterest, getVisibilities, updateVisibility } - from '../controllers/settingsController.js'; +import SettingsController from '../controllers/settingsController.js'; import { authenticate } from '../middleware/authMiddleware.js'; const router = Router(); +const settingsController = new SettingsController(); -router.post('/filter', authenticate, filterSettings); -router.post('/update', authenticate, updateSetting); -router.post('/account', authenticate, getAccountSettings); - -router.post('/getparamvalues', getTypeParamValues); -router.post('/getparamvalueid', getTypeParamValueId); -router.post('/getparamvalue/:id', getTypeParamValue); -router.get('/getpossibleinterests', authenticate, getPossibleInterests); -router.get('/getuserinterests', authenticate, getInterests); -router.post('/addinterest', authenticate, addInterest); -router.post('/setinterest', authenticate, addUserInterest); -router.get('/removeinterest/:id', authenticate, removeInterest); -router.get('/visibilities', authenticate, getVisibilities); -router.post('/update-visibility', authenticate, updateVisibility); +router.post('/filter', authenticate, settingsController.filterSettings.bind(settingsController)); +router.post('/update', authenticate, settingsController.updateSetting.bind(settingsController)); +router.post('/account', authenticate, settingsController.getAccountSettings.bind(settingsController)); +router.post('/getparamvalues', settingsController.getTypeParamValues.bind(settingsController)); +router.post('/getparamvalueid', settingsController.getTypeParamValueId.bind(settingsController)); +router.post('/getparamvalue/:id', settingsController.getTypeParamValue.bind(settingsController)); +router.get('/getpossibleinterests', authenticate, settingsController.getPossibleInterests.bind(settingsController)); +router.get('/getuserinterests', authenticate, settingsController.getInterests.bind(settingsController)); +router.post('/addinterest', authenticate, settingsController.addInterest.bind(settingsController)); +router.post('/setinterest', authenticate, settingsController.addUserInterest.bind(settingsController)); +router.get('/removeinterest/:id', authenticate, settingsController.removeInterest.bind(settingsController)); +router.get('/visibilities', authenticate, settingsController.getVisibilities.bind(settingsController)); +router.post('/update-visibility', authenticate, settingsController.updateVisibility.bind(settingsController)); export default router; diff --git a/backend/routers/socialnetworkRouter.js b/backend/routers/socialnetworkRouter.js index ad98799..f7fe174 100644 --- a/backend/routers/socialnetworkRouter.js +++ b/backend/routers/socialnetworkRouter.js @@ -7,5 +7,11 @@ const socialNetworkController = new SocialNetworkController(); router.post('/usersearch', authenticate, socialNetworkController.userSearch); router.get('/profile/:userId', authenticate, socialNetworkController.profile); +router.post('/usersearch', authenticate, socialNetworkController.userSearch); +router.get('/profile/:userId', authenticate, socialNetworkController.profile); +router.post('/folders', authenticate, socialNetworkController.createFolder); +router.get('/folders', authenticate, socialNetworkController.getFolders); +router.post('/images', authenticate, socialNetworkController.uploadImage); +router.get('/images/:imageId', authenticate, socialNetworkController.getImage); export default router; diff --git a/backend/services/socialnetworkService.js b/backend/services/socialnetworkService.js index 6e2ec56..73b52c7 100644 --- a/backend/services/socialnetworkService.js +++ b/backend/services/socialnetworkService.js @@ -1,186 +1,188 @@ import BaseService from './BaseService.js'; -import { Op, col } from 'sequelize'; +import { Op } from 'sequelize'; import User from '../models/community/user.js'; import UserParam from '../models/community/user_param.js'; import UserParamType from '../models/type/user_param.js'; import UserParamValue from '../models/type/user_param_value.js'; import UserParamVisibility from '../models/community/user_param_visibility.js'; import UserParamVisibilityType from '../models/type/user_param_visibility.js'; +import Folder from '../models/community/folder.js'; +import Image from '../models/community/image.js'; class SocialNetworkService extends BaseService { async searchUsers({ username, ageFrom, ageTo, genders }) { - try { - const whereClause = { - active: true, - searchable: true - }; - if (username) { - whereClause.username = { [Op.iLike]: `%${username}%` }; - } - const users = await User.findAll({ - where: whereClause, - include: [ - { - model: UserParam, - as: 'user_params', - include: [ - { - model: UserParamType, - as: 'paramType', - where: { - description: { - [Op.in]: ['gender', 'birthdate'] - } - }, - required: true - } - ], - required: true - } - ] - }); - const results = []; - for (const user of users) { - const id = user.hashedId; - const birthdateParam = user.user_params.find(param => param.paramType.description === 'birthdate'); - const genderParam = user.user_params.find(param => param.paramType.description === 'gender'); - const age = birthdateParam ? this.calculateAge(birthdateParam.value) : null; - const decryptedGenderValue = genderParam ? genderParam.value : null; - let gender = null; - if (decryptedGenderValue) { - const genderValue = await UserParamValue.findOne({ - where: { - id: decryptedGenderValue - } - }); - gender = genderValue ? genderValue.value : null; - } - const isWithinAgeRange = (!ageFrom || age >= ageFrom) && (!ageTo || age <= ageTo); - if (isWithinAgeRange && (!genders || !genders.length || (gender && genders.includes(gender))) && age >= 14) { - results.push({ - id: id, - username: user.username, - email: user.email, - gender: gender, - age: age - }); - } - } - return results; - } catch (error) { - console.error('Error in searchUsers:', error); - throw new Error('Error searching users'); - } + const whereClause = this.buildSearchWhereClause(username); + const users = await User.findAll({ where: whereClause, include: this.getUserParamsInclude() }); + return this.filterUsersByCriteria(users, ageFrom, ageTo, genders); } async getProfile(hashedUserId, requestingUserId) { - try { - const requestingUser = await this.getUserByHashedId(requestingUserId); - const requestingUserParams = await this.getUserParams(requestingUser.id, ['birthdate']); - let requestingUserAge = 0; + await this.checkUserAccess(requestingUserId); + const user = await this.fetchUserProfile(hashedUserId); + if (!user) return null; + return this.constructUserProfile(user, requestingUserId); + } - for (const param of requestingUserParams) { - if (param.paramType.description === 'birthdate') { - requestingUserAge = this.calculateAge(param.value); - break; - } - } - const user = await User.findOne({ - where: { - hashedId: hashedUserId, - active: true, - searchable: true, - }, - include: [ - { - model: UserParam, - as: 'user_params', - include: [ - { - model: UserParamType, - as: 'paramType', - }, - { - model: UserParamVisibility, - as: 'param_visibilities', - include: [ - { - model: UserParamVisibilityType, - as: 'visibility_type' - } - ] - } - ], - order: [[ 'order_id', 'asc']] - } - ] - }); - if (user) { - const userParams = {}; - await Promise.all(user.user_params.map(async (param) => { - const visibilityData = param.param_visibilities?.[0]?.visibility_type; - const visibility = visibilityData ? visibilityData.description : 'Invisible'; - let paramValue = param.value; - let paramValueChanged = false; - try { - const parsedValue = JSON.parse(paramValue); - if (Array.isArray(parsedValue)) { - paramValue = await Promise.all(parsedValue.map(async (value) => { - if (/^\d+$/.test(value)) { - const userParamValue = await UserParamValue.findOne({ - where: { - id: parseInt(value, 10), - userParamTypeId: param.paramTypeId - } - }); - paramValueChanged = true; - return userParamValue ? userParamValue.value : value; - } - return value; - })); - } - } catch (e) { - } - if (!paramValueChanged) { - if (/^\d+$/.test(paramValue)) { - const userParamValue = await UserParamValue.findOne({ - where: { - id: parseInt(paramValue, 10), - userParamTypeId: param.paramTypeId - } - }); - if (userParamValue) { - paramValue = userParamValue.value; - } - } - } - const paramTypeDescription = param.paramType.description; - if (visibility === 'Invisible') { - return; - } - if (visibility === 'All' || (visibility === 'FriendsAndAdults' && requestingUserAge >= 18) || (visibility === 'AdultsOnly' && requestingUserAge >= 18)) { - userParams[paramTypeDescription] = { - type: param.paramType.datatype, - value: paramValue - }; - if (paramTypeDescription === 'birthdate') { - userParams['age'] = { value: this.calculateAge(Date.parse(paramValue)), type: "int"}; - } - } - })); - const userProfile = { - username: user.username, - registrationDate: user.registrationDate, - params: userParams - }; + async createFolder(data) { + this.validateFolderData(data); + await this.checkUserAccess(data.userId); + return await Folder.create(data); + } - return userProfile; - } - return null; - } catch (error) { - console.error('Error in getProfile:', error); - throw new Error('Error getting profile'); + async getFolders(userId) { + await this.checkUserAccess(userId); + return await Folder.findAll({ where: { userId } }); + } + + async uploadImage(imageData) { + this.validateImageData(imageData); + await this.checkUserAccess(imageData.userId); + return await Image.create(imageData); + } + + async getImage(imageId) { + const image = await Image.findByPk(imageId); + if (!image) throw new Error('Image not found'); + await this.checkUserAccess(image.userId); + return image; + } + + async checkUserAccess(userId) { + const user = await User.findByPk(userId); + if (!user || !user.active) throw new Error('Access denied: User not found or inactive'); + } + + validateFolderData(data) { + if (!data.name || typeof data.name !== 'string') throw new Error('Invalid folder data: Name is required'); + } + + validateImageData(imageData) { + if (!imageData.url || typeof imageData.url !== 'string') throw new Error('Invalid image data: URL is required'); + } + + buildSearchWhereClause(username) { + const whereClause = { active: true, searchable: true }; + if (username) { + whereClause.username = { [Op.iLike]: `%${username}%` }; } + return whereClause; + } + + getUserParamsInclude() { + return [ + { + model: UserParam, + as: 'user_params', + include: [{ model: UserParamType, as: 'paramType', required: true }] + } + ]; + } + + filterUsersByCriteria(users, ageFrom, ageTo, genders) { + const results = []; + for (const user of users) { + const userDetails = this.extractUserDetails(user); + if (this.isUserValid(userDetails, ageFrom, ageTo, genders)) { + results.push(userDetails); + } + } + return results; + } + + extractUserDetails(user) { + const birthdateParam = user.user_params.find(param => param.paramType.description === 'birthdate'); + const genderParam = user.user_params.find(param => param.paramType.description === 'gender'); + const age = birthdateParam ? this.calculateAge(birthdateParam.value) : null; + const gender = genderParam ? this.getGenderValue(genderParam.value) : null; + return { + id: user.hashedId, + username: user.username, + email: user.email, + gender, + age + }; + } + + async getGenderValue(genderId) { + const genderValue = await UserParamValue.findOne({ where: { id: genderId } }); + return genderValue ? genderValue.value : null; + } + + isUserValid(userDetails, ageFrom, ageTo, genders) { + const { age, gender } = userDetails; + const isWithinAgeRange = (!ageFrom || age >= ageFrom) && (!ageTo || age <= ageTo); + const isGenderValid = !genders || !genders.length || (gender && genders.includes(gender)); + return isWithinAgeRange && isGenderValid && age >= 14; + } + + async fetchUserProfile(hashedUserId) { + return await User.findOne({ + where: { hashedId: hashedUserId, active: true, searchable: true }, + include: [ + { + model: UserParam, + as: 'user_params', + include: [ + { model: UserParamType, as: 'paramType' }, + { model: UserParamVisibility, as: 'param_visibilities', include: [{ model: UserParamVisibilityType, as: 'visibility_type' }] } + ], + order: [['order_id', 'asc']] + } + ] + }); + } + + async constructUserProfile(user, requestingUserId) { + const userParams = {}; + const requestingUserAge = await this.getUserAge(requestingUserId); + for (const param of user.user_params) { + const visibility = param.param_visibilities?.[0]?.visibility_type?.description || 'Invisible'; + if (visibility === 'Invisible') continue; + if (this.isVisibleToUser(visibility, requestingUserAge)) { + userParams[param.paramType.description] = { + type: param.paramType.datatype, + value: await this.getParamValue(param) + }; + } + } + return { + username: user.username, + registrationDate: user.registrationDate, + params: userParams + }; + } + + async getUserAge(userId) { + const params = await this.getUserParams(userId, ['birthdate']); + const birthdateParam = params.find(param => param.paramType.description === 'birthdate'); + return birthdateParam ? this.calculateAge(birthdateParam.value) : 0; + } + + isVisibleToUser(visibility, requestingUserAge) { + return visibility === 'All' || + (visibility === 'FriendsAndAdults' && requestingUserAge >= 18) || + (visibility === 'AdultsOnly' && requestingUserAge >= 18); + } + + async getParamValue(param) { + let paramValue = param.value; + try { + const parsedValue = JSON.parse(paramValue); + if (Array.isArray(parsedValue)) { + paramValue = await Promise.all(parsedValue.map(value => this.getValueFromDatabase(value, param.paramTypeId))); + } else if (/^\d+$/.test(paramValue)) { + paramValue = await this.getValueFromDatabase(paramValue, param.paramTypeId); + } + } catch (e) { + } + return paramValue; + } + + async getValueFromDatabase(value, paramTypeId) { + const userParamValue = await UserParamValue.findOne({ + where: { id: parseInt(value, 10), userParamTypeId: paramTypeId } + }); + return userParamValue ? userParamValue.value : value; } } diff --git a/frontend/src/i18n/locales/de/socialnetwork.json b/frontend/src/i18n/locales/de/socialnetwork.json index 55ad6ea..3dcf0ec 100644 --- a/frontend/src/i18n/locales/de/socialnetwork.json +++ b/frontend/src/i18n/locales/de/socialnetwork.json @@ -22,7 +22,7 @@ "tab": { "general": "Allgemeines", "sexuality": "Sexualität", - "images": "Bilder", + "images": "Galerie", "guestbook": "Gästebuch" }, "values": {