import BaseService from './BaseService.js'; import Forum from '../models/forum/forum.js'; import ForumPermission from '../models/forum/forum_permission.js'; import ForumUserPermission from '../models/forum/forum_user_permission.js'; import UserRight from '../models/community/user_right.js'; import UserRightType from '../models/type/user_right.js'; import { Op } from 'sequelize'; import { sequelize } from '../utils/sequelize.js'; import User from '../models/community/user.js'; import ForumForumPermission from '../models/forum/forum_forum_permission.js'; import Title from '../models/forum/title.js'; import Message from '../models/forum/message.js'; class ForumService extends BaseService { async createForum(hashedUserId, name, permissions) { const user = await this.getUserByHashedId(hashedUserId); const isAdmin = await this.hasUserRight(user.id, ['mainadmin', 'forum']); if (!isAdmin) { throw new Error('Access denied: Only admins can create forums.'); } const newForum = await Forum.create({ name }); if (permissions && permissions.length > 0) { for (const permission of permissions) { const forumPermission = await ForumPermission.findOne({ where: { name: permission.value } }); if (forumPermission) { await newForum.addAssociatedPermissions(forumPermission); } } } return newForum; } async deleteForum(hashedUserId, forumId) { const user = await this.getUserByHashedId(hashedUserId); const isAdmin = await this.hasUserRight(user.id, ['mainadmin', 'forum']); if (!isAdmin) { throw new Error('Access denied: Only admins can delete forums.'); } const forum = await Forum.findByPk(forumId); if (!forum) { throw new Error('Forum not found.'); } const transaction = await sequelize.transaction(); try { const forumFormRights = await ForumForumPermission.findAll({ where: { forumId: forumId } }); for (const forumFormRight of forumFormRights) { await forumFormRight.destroy({ transaction }); } const forumUserRights = await ForumUserPermission.findAll({ where: { forumId: forumId } }); for (const forumUserRight of forumUserRights) { await forumUserRight.destroy({ transaction }); } await forum.destroy({ transaction }); await transaction.commit(); return forum; } catch (error) { await transaction.rollback(); throw new Error(`Error deleting forum: ${error.message}`); } } async getAllForums(hashedUserId) { const user = await this.getUserByHashedId(hashedUserId); if (!user) throw new Error('User not found.'); const forums = await Forum.findAll({ include: [ { model: ForumPermission, as: 'associatedPermissions', }, { model: ForumUserPermission, as: 'userPermissions', } ] }); const accessibleForums = []; for (const forum of forums) { const hasAccess = await this.checkForumAccess(forum, user); if (hasAccess) { accessibleForums.push(forum); } } return accessibleForums; } async getForum(hashedUserId, forumId, page) { const user = await this.getUserByHashedId(hashedUserId); if (!user) throw new Error('User not found.'); const forum = await Forum.findByPk(forumId, { include: [ { model: ForumPermission, as: 'associatedPermissions', }, { model: ForumUserPermission, as: 'userPermissions', } ] }); const hasAccess = await this.checkForumAccess(forum, user); if (!hasAccess) { throw new Error('Access denied.'); } const titlesRaw = await Title.findAll({ where: { forumId }, attributes: [ 'id', 'title', 'createdBy', 'forumId', 'createdAt', 'updatedAt', [sequelize.literal(`(SELECT COUNT(*) FROM forum.message WHERE message.title_id = title.id)`), 'messageCount'], [sequelize.literal(`(SELECT MAX("created_at") FROM forum.message WHERE message.title_id = title.id)`), 'lastMessageDate'] ], include: [ { model: User, as: 'createdByUser', attributes: ['id', 'username', 'hashedId'] }, { model: Message, as: 'messages', attributes: [], include: [ { model: User, as: 'lastMessageUser', attributes: ['id', 'username'] } ] } ], offset: (page - 1) * 25, limit: 25, order: [ ['createdAt', 'DESC'] ], group: [ 'title.id', 'title.created_at', ] }); const totalTopics = await Title.count({ where: { forumId } }); const titles = titlesRaw.map(title => ({ id: title.dataValues.id, title: title.dataValues.title, createdBy: title.createdByUser.username, createdByHash: title.createdByUser.hashedId, createdAt: title.dataValues.createdAt, numberOfItems: title.dataValues.messageCount, lastMessageDate: title.dataValues.lastMessageDate })); return { name: forum.name, titles, page, totalTopics, }; } async createTopic(hashedUserId, forumId, title, content) { const user = await this.getUserByHashedId(hashedUserId); if (!user) throw new Error('User not found.'); const forum = await Forum.findByPk(forumId, { include: [ { model: ForumPermission, as: 'associatedPermissions', }, { model: ForumUserPermission, as: 'userPermissions', } ] }); const hasAccess = await this.checkForumAccess(forum, user); if (!hasAccess) { throw new Error('Access denied.'); } const newTopic = await Title.create({ title, forumId, createdBy: user.id }); await Message.create({ titleId: newTopic.id, text: content, createdBy: user.id}) return this.getForum(hashedUserId, forumId, 1); } async getTopic(hashedUserId, topicId) { console.log('[ForumService.getTopic] - start'); const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found.'); } const topic = await Title.findByPk(topicId, { include: [ { model: Message, as:'messages', include: [ { model: User, as: 'lastMessageUser', attributes: ['hashedId', 'username'], order: [['createdAt', 'ASC']] } ] }, { model: User, as: 'createdByUser', attributes: ['username', 'hashedId'] }, { model: Forum, as: 'forum', attributes: ['id', 'name'] } ] }); if (!topic) { throw new Error('Topic not found.'); } console.log('[ForumService.getTopic] - check user permissions'); const hasAccess = await this.checkForumAccess(topic.forum, user); if (!hasAccess) { throw new Error('Access denied.'); } console.log('[ForumService.getTopic] - return topic'); return topic; } async addMessage(hashedUserId, topicId, content) { console.log('[ForumService.addMessage] - start'); const user = await User.findOne({ where: { hashedId: hashedUserId } }); if (!user) { throw new Error('User not found.'); } const topic = await Title.findByPk(topicId, { include: [ { model: Message, as:'messages', include: [ { model: User, as: 'lastMessageUser', attributes: ['hashedId', 'username'], order: [['createdAt', 'ASC']] } ] }, { model: User, as: 'createdByUser', attributes: ['username', 'hashedId'] }, { model: Forum, as: 'forum', attributes: ['id', 'name'] } ] }); if (!topic) { throw new Error('Topic not found.'); } const hasAccess = await this.checkForumAccess(topic.forum, user); if (!hasAccess) { throw new Error('Access denied.'); } console.log('[ForumService.addMessage] - create new message'); await Message.create({ titleId: topicId, text: content, createdBy: user.id }); console.log('[ForumService.addMessage] - return topic'); return this.getTopic(hashedUserId, topicId); } async checkForumAccess(forum, user) { console.log('[ForumService.checkForumAccess] - start'); const { age } = user; console.log('[ForumService.checkForumAccess] - read user permissions'); const userPermission = await ForumUserPermission.findOne({ where: { userId: user.id, forumId: forum.id } }); if (userPermission) { return true; } console.log('[ForumService.checkForumAccess] - read forum permissions'); const forumPermissions = await ForumForumPermission.findAll({ where: { forumId: forum.id } }); console.log('[ForumService.checkForumAccess] - filter persmissions'); for (const permission of forumPermissions) { if (permission.permission === 'age' && age >= parseInt(permission.value, 10)) { return true; } if (permission.permission === 'all' || permission.permission === 'user') { return true; } const userRight = await UserRight.findOne({ where: { userId: user.id, }, include: { model: UserRightType, as: 'rightType', where: { [Op.or]: [ { title: 'mainadmin' }, { title: 'forum' } ] } } }); if (userRight) { return true; } } console.log('[ForumService.checkForumAccess] - not successful'); return false; } async setPermissions(forumId, permissions) { if (permissions && Array.isArray(permissions)) { for (const permission of permissions) { await ForumPermission.create({ forumId, permission: permission.type, value: permission.value }); } } } async checkAdminRights(userId) { const userRight = await UserRight.findOne({ where: { userId }, include: { model: UserRightType, as: 'rightType', where: { title: ['mainadmin', 'forum'] } } }); if (!userRight) { throw new Error('Unauthorized: Only admins can perform this action.'); } } } export default new ForumService();