Skip to content

Commit

Permalink
Fixing errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
jullia andrei committed Oct 11, 2024
2 parents 13af3af + 398e10a commit 3969a99
Show file tree
Hide file tree
Showing 16 changed files with 221 additions and 49 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "nodebb"
"extends": "nodebb",
"parserOptions": {
"ecmaVersion": 2020 // This change in configuration is suggested by Copilot
}
}
2 changes: 1 addition & 1 deletion .mocharc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
reporter: dot
timeout: 25000
exit: true
bail: true
bail: false
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/ithVU1OO)

## Team Members
- Mia Li
- Alice Kang
- Cheyu Tu
- Jasmine Shi
- Jullia Andrei Montejo

# ![NodeBB](public/images/sm-card.png)

[![Workflow](https://github.com/CMU-313/NodeBB/actions/workflows/test.yaml/badge.svg)](https://github.com/CMU-313/NodeBB/actions/workflows/test.yaml)
Expand Down
72 changes: 72 additions & 0 deletions UserGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# User Guide for Team SWEethearts User Stories

## Table of Contents
1. [User Story 2](#user-story-2)
2. [User Story 7](#user-story-7)

## User Story 2
As a student, I want to receive an immediate notification when a course faculty member replies to my post, so that I can review their response within 24 hours.

### Feature Overview
* Real-time notifications:
* Push notifications that will appear on the notification side bar and on the main notification page when a course faculty replies to your post.
<img src="user_guide_images/ins_notif_1.png" alt="Screenshot 1" width="500"/>
<img src="user_guide_images/ins_notif_2.png" alt="Screenshot 2" width="300"/>

* These notifications are delivered separately from non-faculty reply notifications and are indicated with the "[COURSE-FACULTY]" on the title. (As shown in the above images.)


* User Preferences: Like other notifications, users are able to customize their notification settings (choose between push, email, both, or turn both off) in the account settings page.
<img src="user_guide_images/ins_notif_3.png" alt="Screenshot 3" width="500"/>

### How To Use and Test User Story 2 Feature
1. Register 2 accounts: an admin and a non-admin (student).
2. Log in to the non-admin account and make a topic in a discussion board.
3. Go to the user settings page by clicking on the top right profile icon then "Settings".
4. Scroll down until you find the course faculty notification setting as shown below. This feature's setting should be on the "Notification Only" by default. Choose your preferred setting and press Save Changes.
5. Log out of this student account and log in to the admin account.
6. Leave a reply to the student post.
7. Log out and log in the student account. There should now be a new notification that pops up on the notification sidebar and on the page.
* If this setting is turned off then there should be no notifications on the inbox or on the notification page.

**Note: For this feature we assume that every admin account is a course faculty.**

### Automated Tests - located in `test/notifications.js`
#### Test Cases: Lines 392 - 585
* Lines 442 - 448: Testing basic functionality: user should receive a notification when a course faculty replies.
* Lines 450 - 485: Test that user should not receive notification when regular user replies.
* Lines 487 - 535: Test to check that user can mark faculty replies as read.
* Lines 537 - 544: Test to check that changing notification settings work.
* Lines 546 - 571: Test to check that separate faculty replies trigger separate notifications.

#### Test Justification
We believe that these tests are sufficient as it tests the basic functionality of this new feature. The tests ensure that users receive notifications from faculty, can differentiate between faculty and regular user replies, and can manage notifications (e.g., marking them as read or adjusting settings). This ensures both the functionality and user control of the feature, making the system reliable.

## User Story 7
As a student, I want to save posts to favorites for posts that contains important information/good solutions, so that I can review them later on quickly

### Feature Overview
* Adding a Favorites category in the discussion post bar:
* Users are able to select posts as a Favorite
* Conceptually, posts marked as Favorites could be sorted and displayed to user
<img src="user_guide_images/fav_btn_1.png" alt="Screenshot 4" width="500"/>
<img src="user_guide_images/fav_btn_2.png" alt="Screenshot 5" width="500"/>

### How to Use and Test User Story
1. User needs to register; does not have to be an admin
2. Go to "General Discussion" page
3. There should be at least one topic within the discussion page. If there are none, make a test post.
4. You should be able to see a Star button signifying Favorite
5. There should also be a Favorite button in the post bar
6. The Favorite button in post bar can be toggled on and off.


### Automated tests are located in `test/topics/favorite.js`

#### Error Tests: Testing invalid inputs
* Test for invalid input

#### Valid Tests

#### Test Justification
We believe that these tests are sufficient because
Binary file modified dump.rdb
Binary file not shown.
44 changes: 24 additions & 20 deletions public/src/admin/manage/digest.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
'use strict';


define('admin/manage/digest', ['bootbox', 'alerts'], function (bootbox, alerts) {
const Digest = {};
console.log('Mia Li');
function interval_resend(action) {
const interval = action.slice(7);
bootbox.confirm('[[admin/manage/digest:resend-all-confirm]]', function (ok) {
if (ok) {
Digest.send(action, undefined, function (err) {
if (err) {
return alerts.error(err);
}
alerts.success('[[admin/manage/digest:resent-' + interval + ']]');
});
}
});
}

function single_resend(action, uid) {
Digest.send(action, uid, function (err) {
if (err) {
return alerts.error(err);
}
alerts.success('[[admin/manage/digest:resent-single]]');
});
}
Digest.init = function () {
$('.digest').on('click', '[data-action]', function () {
const action = this.getAttribute('data-action');
const uid = this.getAttribute('data-uid');

if (action.startsWith('resend-')) {
const interval = action.slice(7);
bootbox.confirm('[[admin/manage/digest:resend-all-confirm]]', function (ok) {
if (ok) {
Digest.send(action, undefined, function (err) {
if (err) {
return alerts.error(err);
}

alerts.success('[[admin/manage/digest:resent-' + interval + ']]');
});
}
});
interval_resend(action);
} else {
Digest.send(action, uid, function (err) {
if (err) {
return alerts.error(err);
}

alerts.success('[[admin/manage/digest:resent-single]]');
});
single_resend(action, uid);
}
});
};
Expand Down
13 changes: 9 additions & 4 deletions src/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,13 @@ Flags.sort = async function (flagIds, sort) {
return flagIds;
};

function checkSelfFlagError(payload) {
console.log('CHEYU TU - checkSelfFlagError');
if (parseInt(payload.id, 10) === parseInt(payload.uid, 10)) {
throw new Error('[[error:cant-flag-self]]');
}
}

Flags.validate = async function (payload) {
const [target, reporter] = await Promise.all([
Flags.getTarget(payload.type, payload.id, payload.uid),
Expand All @@ -283,7 +290,7 @@ Flags.validate = async function (payload) {
throw new Error('[[error:invalid-data]]');
} else if (target.deleted) {
throw new Error('[[error:post-deleted]]');
} else if (!reporter || !reporter.userslug) {
} else if (!reporter?.userslug) {
throw new Error('[[error:no-user]]');
} else if (reporter.banned) {
throw new Error('[[error:user-banned]]');
Expand All @@ -304,9 +311,7 @@ Flags.validate = async function (payload) {
throw new Error(`[[error:not-enough-reputation-to-flag, ${meta.config['min:rep:flag']}]]`);
}
} else if (payload.type === 'user') {
if (parseInt(payload.id, 10) === parseInt(payload.uid, 10)) {
throw new Error('[[error:cant-flag-self]]');
}
checkSelfFlagError(payload);
const editable = await privileges.users.canEdit(payload.uid, payload.id);
if (!editable && !meta.config['reputation:disabled'] && reporter.reputation < meta.config['min:rep:flag']) {
throw new Error(`[[error:not-enough-reputation-to-flag, ${meta.config['min:rep:flag']}]]`);
Expand Down
49 changes: 27 additions & 22 deletions src/groups/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,7 @@ module.exports = function (Groups) {
}
});

const payload = {
description: values.description || '',
icon: values.icon || '',
labelColor: values.labelColor || '#000000',
textColor: values.textColor || '#ffffff',
};

if (values.hasOwnProperty('userTitle')) {
payload.userTitle = values.userTitle || '';
}

if (values.hasOwnProperty('userTitleEnabled')) {
payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0';
}

if (values.hasOwnProperty('hidden')) {
payload.hidden = values.hidden ? '1' : '0';
}

if (values.hasOwnProperty('private')) {
payload.private = values.private ? '1' : '0';
}
const payload = payload_helper(values);

if (values.hasOwnProperty('disableJoinRequests')) {
payload.disableJoinRequests = values.disableJoinRequests ? '1' : '0';
Expand Down Expand Up @@ -90,6 +69,32 @@ module.exports = function (Groups) {
});
};

function payload_helper(values) {
const payload = {
description: values.description || '',
icon: values.icon || '',
labelColor: values.labelColor || '#000000',
textColor: values.textColor || '#ffffff',
};

if (values.hasOwnProperty('userTitle')) {
payload.userTitle = values.userTitle || '';
}

if (values.hasOwnProperty('userTitleEnabled')) {
payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0';
}

if (values.hasOwnProperty('hidden')) {
payload.hidden = values.hidden ? '1' : '0';
}

if (values.hasOwnProperty('private')) {
payload.private = values.private ? '1' : '0';
}
return payload;
}

async function updateVisibility(groupName, hidden) {
if (hidden) {
await db.sortedSetRemoveBulk([
Expand Down
29 changes: 28 additions & 1 deletion src/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const winston = require('winston');

const start = module.exports;

const db = require('./database');
const Topics = require('./topics');

start.start = async function () {
printStartupInfo();

addProcessHandlers();

try {
const db = require('./database');
await db.init();
await db.checkCompatibility();

Expand Down Expand Up @@ -149,3 +151,28 @@ async function shutdown(code) {
return process.exit(code || 0);
}
}

/* eslint-disable no-unused-vars */
async function getTopicIdByTitle(title) {
const topic = await db.models.topics.findOne({ title });
return topic ? topic.tid : null;
}

async function addTagsToTopic() {
try {
const tid = await getTopicIdByTitle('Welcome to your NodeBB!');
if (tid) {
console.log(`Topic ID: ${tid}`);

const timestamp = Date.now(); // Get current timestamp
const tagsToAdd = ['Homework', 'Assignment']; // Default tags

await Topics.createTags(tagsToAdd, tid, timestamp); // Add tags to the topic
} else {
console.error('Topic not found');
}
} catch (error) {
console.error('Error adding tags:', error);
}
}
/* eslint-enable no-unused-vars */
17 changes: 17 additions & 0 deletions src/webserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const topicEvents = require('./topics/events');
const privileges = require('./privileges');
const routes = require('./routes');
const auth = require('./routes/authentication');
const topics = require('./topics');

const helpers = require('./helpers');

Expand All @@ -48,6 +49,7 @@ if (nconf.get('ssl')) {

module.exports.server = server;
module.exports.app = app;
module.exports.createNewTag = createNewTag;

server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
Expand Down Expand Up @@ -86,6 +88,7 @@ exports.listen = async function () {
helpers.register();
logger.init(app);
await initializeNodeBB();
await createNewTag();
winston.info('🎉 NodeBB Ready');

require('./socket.io').server.emit('event:nodebb.ready', {});
Expand Down Expand Up @@ -334,3 +337,17 @@ exports.testSocket = async function (socketPath) {
};

require('./promisify')(exports);

async function createNewTag() {
try {
const newTag1 = 'homework';
const newTag2 = 'assignment';

await topics.createEmptyTag(newTag1);
console.log(`Tag "${newTag1}" successfully created!`);
await topics.createEmptyTag(newTag2);
console.log(`Tag "${newTag2}" successfully created!`);
} catch (err) {
console.error('Error creating tag: ', err.message);
}
}
31 changes: 31 additions & 0 deletions test/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,37 @@ describe('Flags', () => {
done();
});
});

function validateUserFlag(done) {
Flags.validate({
type: 'user',
id: 1,
uid: 3,
}, (err) => {
assert.ok(err);
assert.strictEqual('[[error:not-enough-reputation-to-flag, 50]]', err.message);
Meta.configs.set('min:rep:flag', 0, done);
});
}

it('should not pass validation if type is user, flag threshold is set and user rep does not meet it', (done) => {
Meta.configs.set('min:rep:flag', '50', (err) => {
assert.ifError(err);
validateUserFlag(done);
});
});

it('should throw an error if user tries to flag themselves', (done) => {
Flags.validate({
type: 'user',
id: 1,
uid: 1,
}, (err) => {
assert.ok(err);
assert.strictEqual('[[error:cant-flag-self]]', err.message);
done();
});
});
});

describe('.appendNote()', () => {
Expand Down
Binary file added user_guide_images/fav_btn_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added user_guide_images/fav_btn_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added user_guide_images/ins_notif_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added user_guide_images/ins_notif_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added user_guide_images/ins_notif_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3969a99

Please sign in to comment.