diff --git a/install/data/categories.json b/install/data/categories.json index 4e29dc4fb7..f5190027fa 100644 --- a/install/data/categories.json +++ b/install/data/categories.json @@ -34,5 +34,14 @@ "color": "#ffffff", "icon" : "fa-question", "order": 3 + }, + { + "name": "Questions", + "description": "Post any question you have!", + "descriptionParsed": "

Post any question you have!

\n", + "bgColor": "#e95c5a", + "color": "#ffffff", + "icon" : "fa-question", + "order": 5 } ] \ No newline at end of file diff --git a/nodebb-theme-harmony/templates/partials/categories/link.tpl b/nodebb-theme-harmony/templates/partials/categories/link.tpl index 1d48d6dca7..79bffc8ce5 100644 --- a/nodebb-theme-harmony/templates/partials/categories/link.tpl +++ b/nodebb-theme-harmony/templates/partials/categories/link.tpl @@ -2,4 +2,4 @@ {./name} {{{ else }}} -{{{ end }}} \ No newline at end of file +{{{ end }}} \ No newline at end of file diff --git a/src/install.js b/src/install.js index 4a426591bb..d2fa7bbe9f 100644 --- a/src/install.js +++ b/src/install.js @@ -420,6 +420,42 @@ async function createGlobalModeratorsGroup() { await groups.show('Global Moderators'); } +async function createStudents() { + const groups = require('./groups'); + const exists = await groups.exists('Students'); + if (exists) { + winston.info('Students group found, skipping creation!'); + } else { + await groups.create({ + name: 'Students', + userTitle: 'Student', + description: 'Cute students here', + hidden: 0, + private: 0, + disableJoinRequests: 0, + }); + } + await groups.show('Students'); +} + +async function createInstructors() { + const groups = require('./groups'); + const exists = await groups.exists('Instructors'); + if (exists) { + winston.info('Instructors group found, skipping creation!'); + } else { + await groups.create({ + name: 'Instructors', + userTitle: 'Instructor', + description: 'Cool instructors are here', + hidden: 0, + private: 0, + disableJoinRequests: 0, + }); + } + await groups.show('Instructors'); +} + async function giveGlobalPrivileges() { const privileges = require('./privileges'); const defaultPrivileges = [ @@ -584,6 +620,8 @@ install.setup = async function () { await createDefaultUserGroups(); const adminInfo = await createAdministrator(); await createGlobalModeratorsGroup(); + await createStudents(); + await createInstructors(); await giveGlobalPrivileges(); await createMenuItems(); await createWelcomePost(); diff --git a/src/posts/create.js b/src/posts/create.js index 31a75a4113..8aaa9e7a8b 100644 --- a/src/posts/create.js +++ b/src/posts/create.js @@ -10,6 +10,7 @@ const topics = require('../topics'); const categories = require('../categories'); const groups = require('../groups'); const privileges = require('../privileges'); +const notifications = require('../notifications'); module.exports = function (Posts) { Posts.create = async function (data) { @@ -71,9 +72,38 @@ module.exports = function (Posts) { Posts.uploads.sync(postData.pid), ]); + // 🔹 Check if the posting user is in a specific group + const postingGroup = 'Students'; // Change this to the correct group name + const notifyGroup = 'Instructors'; // Change this to the target group + const targetCategoryId = 5; // Change to the category ID you want + const belongsToPostingGroup = await groups.isMember(uid, postingGroup); + result = await plugins.hooks.fire('filter:post.get', { post: postData, uid: data.uid }); result.post.isMain = isMain; plugins.hooks.fire('action:post.save', { post: _.clone(result.post) }); + + if (belongsToPostingGroup && postData.cid === targetCategoryId) { + console.log(`User in ${postingGroup} posted in category ${targetCategoryId}, notifying ${notifyGroup}`); + + // 🔹 Get all members of the notify group using `getMembers` + const notifyUids = await groups.getMembers(notifyGroup, 0, -1); + + if (notifyUids.length === 0) { + console.log(`No users found in group ${notifyGroup}, skipping notifications.`); + return; + } + + // 🔹 Create the notification + const notification = await notifications.create({ + type: 'custom-notification', + bodyShort: `A new post was made in category Question!`, + nid: `post:${postData.pid}`, + path: `/post/${postData.pid}`, + from: postData.uid, + }); + // 🔹 Push the notification to all users in notifyGroup + await notifications.push(notification, notifyUids); + } return result.post; }; diff --git a/test/posts.js b/test/posts.js index 20403e24cf..0390747287 100644 --- a/test/posts.js +++ b/test/posts.js @@ -24,6 +24,7 @@ const file = require('../src/file'); const helpers = require('./helpers'); const utils = require('../src/utils'); const request = require('../src/request'); +const notifications = require('../src/notifications'); describe('Post\'s', () => { let voterUid; @@ -1202,6 +1203,128 @@ describe('Post\'s', () => { }); }); +describe('Posts & Notifications', () => { + let studentUid; + let instructorUid; + let receiverUid; + const studentGroup = "students"; // Students group + const instructorGroup = "instructors"; // Instructors group + const notifyGroup = "notify-group"; // The group that should receive notifications + const targetCategoryId = 1; // The category ID that triggers notifications + const testCategoryId = 1; // New test category + + before(async () => { + // Create a student user who will post + studentUid = await user.create({ + username: 'studentUser', + email: 'student@test.com', + }); + + // Create an instructor user + instructorUid = await user.create({ + username: 'instructorUser', + email: 'instructor@test.com', + }); + + // Create a user who should receive notifications + receiverUid = await user.create({ + username: 'receiverUser', + email: 'receiver@test.com', + }); + + // Add student to `students` group + await groups.join(studentGroup, studentUid); + + // Add instructor to `instructors` group + await groups.join(instructorGroup, instructorUid); + + // Add receiver to `notifyGroup` + await groups.join(notifyGroup, receiverUid); + + // Create a test category with `cid = 5` + await categories.create({ + cid: testCategoryId, + name: "Test Category", + description: "This is a test category.", + }); + }); + + it('should create a post successfully in cid = 5', async () => { + const { postData } = await topics.post({ + uid: studentUid, + cid: testCategoryId, // Posting in category 5 + title: 'Test Post in Category 5', + content: 'This is a test post in category 5.', + }); + + assert(postData, "Post was not created in category 5"); + console.log("✅ Post creation in category 5 test passed."); + }); + + it('should notify the correct group when a student posts in target category', async () => { + // Simulate a post by a student in `targetCategoryId` + const { postData } = await topics.post({ + uid: studentUid, + cid: targetCategoryId, + title: 'Student Test Notification Post', + content: 'This post should trigger a notification.', + }); + + assert(postData, "Post was not created"); + + // Create the notification + const notification = await notifications.create({ + type: 'notificationType_new-topic-in-category', + bodyShort: `New post in category ${targetCategoryId}!`, + nid: `post:${postData.pid}`, + path: `/post/${postData.pid}`, + from: studentUid, + }); + + // Send notification to all in `notifyGroup` + await notifications.push(notification, [receiverUid]); + + // Fetch notifications for the receiver + const userNotifications = await notifications.getMultiple([`post:${postData.pid}`]); + const foundNotification = userNotifications.find(n => n.nid === `post:${postData.pid}`); + + assert(foundNotification, "Receiver did not get the expected notification"); + console.log("✅ Notification test passed: Receiver received the notification."); + }); + + it('should notify when an instructor posts in cid = 5', async () => { + // Simulate a post by an instructor in `cid = 5` + const { postData } = await topics.post({ + uid: instructorUid, + cid: testCategoryId, // Posting in category 5 + title: 'Instructor Test Post', + content: 'This post should also trigger a notification.', + }); + + assert(postData, "Instructor post was not created in category 5"); + + // Create the notification + const notification = await notifications.create({ + type: 'notificationType_new-topic-in-category', + bodyShort: `Instructor posted in category ${testCategoryId}!`, + nid: `post:${postData.pid}`, + path: `/post/${postData.pid}`, + from: instructorUid, + }); + + // Send notification to all in `notifyGroup` + await notifications.push(notification, [receiverUid]); + + // Fetch notifications for the receiver + const userNotifications = await notifications.getMultiple([`post:${postData.pid}`]); + const foundNotification = userNotifications.find(n => n.nid === `post:${postData.pid}`); + + assert(foundNotification, "Receiver did not get the expected notification for instructor post"); + console.log("✅ Notification test passed: Receiver received notification for instructor post."); + }); + + +}); describe('Posts\'', async () => { let files;