Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
6b042e3
feat(forward): store forwardMid
connorcarpenter15 Feb 2, 2026
ca9cde7
feat(forward): update API endpoints
connorcarpenter15 Feb 3, 2026
252df0d
Schema documentation
sittingthyme Feb 3, 2026
2288661
Add forwardMid support to chat message API endpoint
sittingthyme Feb 6, 2026
b7ea7cc
partially figuring out how adding forward message works from frontend…
LawrenceSong06 Feb 6, 2026
3ad3722
[forward message feat.] sucessfully completed the forwarded message w…
LawrenceSong06 Feb 6, 2026
d882b84
cleaned up logs
LawrenceSong06 Feb 6, 2026
6d7386d
Forward Chat Selection Popup
josecmu27 Feb 6, 2026
f5f4bc3
Merge pull request #32 from CMU-313/backend-forward-message
connorcarpenter15 Feb 6, 2026
4de3e9d
Merge pull request #31 from CMU-313/select-chat-popup
connorcarpenter15 Feb 6, 2026
4314947
forward message integrated with pop-up
LawrenceSong06 Feb 6, 2026
bf76c2e
fix(forward): add forward button
connorcarpenter15 Feb 6, 2026
69d434b
Merge branch 'dev-forward-message' of https://github.com/CMU-313/node…
LawrenceSong06 Feb 6, 2026
908e5d3
fix(view): add forward message view
connorcarpenter15 Feb 6, 2026
cc488db
language files modified, 'successfully forwarded' alert is also added
LawrenceSong06 Feb 6, 2026
fa6fb3e
restored message sending interval
LawrenceSong06 Feb 9, 2026
eb7cf45
fix(test): fix scope
connorcarpenter15 Feb 9, 2026
ba5554e
Merge pull request #33 from CMU-313/dev-forward-message
LawrenceSong06 Feb 9, 2026
ccccdae
Fix URL error and 400 chat post error
sittingthyme Feb 11, 2026
3504582
Fix lint errors
sittingthyme Feb 11, 2026
bb8f765
Merge pull request #34 from CMU-313/dev-forward-message
sittingthyme Feb 11, 2026
1e3a44c
feat(colorscheme): add per-user custom color theme settings
connorcarpenter15 Feb 20, 2026
813b5a8
Custom Skin Frontend
sittingthyme Feb 20, 2026
b0b4af6
Update skins.js
sittingthyme Feb 20, 2026
9476d03
Added Reactions Model
josecmu27 Feb 21, 2026
ce092a9
Added REST API endpoints for emoji reactions
josecmu27 Feb 21, 2026
325b1e0
Added reactions in message payload
josecmu27 Feb 21, 2026
cdfa7e6
Emit real-time socket event on reaction toggle
josecmu27 Feb 21, 2026
7989cc9
Add emoji validation for reactions
josecmu27 Feb 21, 2026
66c6ceb
Added UserGuide.md and tests for emoji reactions feature
josecmu27 Feb 22, 2026
6afb9e3
chore(workflow): update CI test
connorcarpenter15 Feb 23, 2026
ea2589b
fix CI issue
sittingthyme Feb 23, 2026
1a86352
Merge pull request #36 from CMU-313/dev-colorscheme-backend
sittingthyme Feb 23, 2026
93c39ab
fix(colorscheme): update openapi schema
connorcarpenter15 Feb 23, 2026
81e18c4
chore: resolve merge conflict with backend
connorcarpenter15 Feb 23, 2026
7b01cef
Merge pull request #39 from CMU-313/frontend-custom-theme
connorcarpenter15 Feb 23, 2026
4dbdfbb
feat(colorscheme): switch custom skin to 7-field color model
connorcarpenter15 Feb 23, 2026
1d0ae15
Change default(custom) to default and reomve duplicate custom option
sittingthyme Feb 23, 2026
bc30230
Merge pull request #44 from CMU-313/dev-colorscheme
sittingthyme Feb 24, 2026
c10b14c
Implement reaction handling for chat messages
VaridhiJain18 Feb 27, 2026
e48c5c3
Implement reaction UI in chat message template
VaridhiJain18 Feb 27, 2026
b77edd3
Add styles for chat reactions and reaction button
VaridhiJain18 Feb 27, 2026
0138d8f
Merge pull request #43 from CMU-313/reaction-backend
josecmu27 Feb 27, 2026
70fc7e4
Merge pull request #45 from CMU-313/reactions-frontend
josecmu27 Feb 27, 2026
550256f
Update test.yaml
josecmu27 Feb 27, 2026
639bd26
Merge branch 'main' into dev-reactions
josecmu27 Feb 27, 2026
f8ce7b3
Update messages.js
josecmu27 Feb 27, 2026
6fb42c3
Merge branch 'dev-reactions' of https://github.com/CMU-313/nodebb-spr…
josecmu27 Feb 27, 2026
6b6b070
Update roomid.yaml
josecmu27 Feb 27, 2026
b2d3b68
Update Chats.yaml
josecmu27 Feb 27, 2026
926d57e
fix(api): add OpenAPI schema definitions for emoji reactions endpoints
josecmu27 Feb 27, 2026
c343d44
Merge pull request #46 from CMU-313/dev-reactions
VaridhiJain18 Feb 27, 2026
cf96693
docs: add UserGuide.md for sprint features
connorcarpenter15 Feb 28, 2026
bd9ccb9
Merge pull request #47 from CMU-313/docs/userguide
josecmu27 Feb 28, 2026
4b114cc
chore(docker): add root user privileges
connorcarpenter15 Mar 9, 2026
5893243
Merge pull request #49 from CMU-313/chore/docker-compose
josecmu27 Mar 9, 2026
0681892
chore(vm): add vm workflow
connorcarpenter15 Mar 9, 2026
f3ec040
Merge pull request #50 from CMU-313/chore/vm-deploy
connorcarpenter15 Mar 9, 2026
3554bd4
feat(tools): add semgrep
connorcarpenter15 Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ on:
- main
- master
- develop
- 'dev-*'
pull_request:
branches:
- main
- master
- develop

- 'dev-*'
defaults:
run:
shell: bash
Expand Down Expand Up @@ -89,4 +90,4 @@ jobs:
run: npm run coverage

- name: Test coverage
uses: coverallsapp/github-action@v2
uses: coverallsapp/github-action@v2
36 changes: 36 additions & 0 deletions .github/workflows/vm_deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: VM Deploy NodeBB

on:
push:
branches:
- main
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true

jobs:
build-and-deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Node.js version
uses: actions/setup-node@v3
with:
node-version: '20.17.0'

- name: Deploy via SSH
uses: appleboy/ssh-action@v1.2.1
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_ADMIN }}
password: ${{ secrets.ADMIN_PASSWORD }}
script: |
cd ${{ secrets.REPO_NAME }}
git pull origin main
docker compose down
docker compose -f docker-compose-redis.yml up --build -d
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,5 @@ test.sh
dump.rdb
.archiver_shadow/
.snapshots/

start-dev.sh
9 changes: 9 additions & 0 deletions .semgrepignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Semgrep ignore patterns (gitignore-style)
# node_modules/ and vendor/ are ignored by semgrep by default
node_modules/
vendor/
build/
public/language/
coverage/
.nyc_output/
*.min.js
181 changes: 181 additions & 0 deletions UserGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# User Guide — Sprint Features

This guide covers the three features implemented during this sprint: **Message Forwarding**, **Message Reactions**, and **Custom Color Scheme**.

---

## Table of Contents

1. [Message Forwarding](#1-message-forwarding)
2. [Message Reactions](#2-message-reactions)
3. [Custom Color Scheme](#3-custom-color-scheme)
4. [Automated Tests](#4-automated-tests)

---

## 1. Message Forwarding

### Overview

Message Forwarding allows a registered user to share a chat message from one chat room to another. The forwarded message appears in the destination room with a visual reference to the original message and its sender.

### How to Use

1. **Open a chat room** — Navigate to your chats and open any conversation.
2. **Hover over a message** — Hover over the message you want to forward. A toolbar of action buttons will appear.
3. **Click the Forward button** — Click the **share icon** (<i class="fa fa-share"></i>) in the message toolbar.
4. **Select a destination** — A dropdown appears listing all of your other chat rooms (both private and public). You can **search** for a specific room using the search bar at the top of the dropdown.
5. **Click a chat to forward** — Click the desired room. A confirmation alert will appear, and the message will be sent to the selected room.
6. **View the forwarded message** — In the destination room, the forwarded message appears with:
- A **share icon** and the **original sender's avatar and name**
- A **preview of the original message content**
- The new message body (labeled "(Forwarded Message)")

### User Testing Steps

| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | Open a chat room with at least one message | Messages display normally |
| 2 | Hover over a message | Action toolbar appears (reply, forward, ellipsis menu) |
| 3 | Click the forward (share) button | A "Forward to:" dropdown opens with a search bar and a list of your other chat rooms |
| 4 | Type in the search field | Room list filters in real time |
| 5 | Click a room in the list | A success alert ("Message forwarded") appears, and the dropdown closes |
| 6 | Navigate to the destination room | The forwarded message appears with the original sender info and content preview |
| 7 | Click the forward button again, then click the ✕ close button on the dropdown | The dropdown closes without forwarding |
| 8 | Click outside the dropdown | The dropdown closes |

---

## 2. Message Reactions

### Overview

Message Reactions allow registered users to react to any chat message with an emoji. Reactions are visible to all room members and update in **real time** via WebSocket events.

### How to Use

1. **Open a chat room** — Navigate to a chat conversation.
2. **Add a reaction** — Below each message, click the **smiley face button** (😊). An emoji picker will appear.
3. **Select an emoji** — Choose any emoji from the picker. A **reaction pill** will appear below the message, showing the emoji and a count of `1`.
4. **Toggle a reaction** — Click an existing reaction pill to add your reaction (if you haven't reacted with that emoji) or to remove it (if you already have).
5. **View who reacted** — Reaction pills you've personally used are highlighted with a distinct "reacted" style.
6. **Real-time updates** — When another user in the room adds or removes a reaction, your view updates automatically.

### User Testing Steps

| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | Open a chat room with messages | Messages appear normally, with a small smiley button visible below each message |
| 2 | Click the smiley (add reaction) button on a message | An emoji picker dialog opens |
| 3 | Select an emoji (e.g., 👍) | A reaction pill appears below the message with the emoji and count "1" |
| 4 | Click the same reaction pill again | The reaction toggles off — the pill disappears (count drops to 0) |
| 5 | Add a reaction, then have a **second user** react with the same emoji | The count on the pill increases to "2"; the first user's pill shows the "reacted" highlight |
| 6 | As the second user, view the reaction pill | The pill appears without the "reacted" highlight (since it reflects only the current user's state) |
| 7 | Send an invalid emoji string via the API (e.g., `notanemoji`) | The server returns a 400 error |
| 8 | Attempt to react as a user **not in the room** | The server returns a 403 error |

---

## 3. Custom Color Scheme

### Overview

Custom Color Scheme lets each registered user create a personalized color theme for their NodeBB interface. When the **"Custom"** skin is selected, 7 color pickers appear, allowing the user to control header, body, link, and button colors.

### How to Use

1. **Go to Account Settings** — Click your profile picture → **Settings** (or navigate to `/user/<your-username>/settings`).
2. **Select the "Custom" skin** — In the **Skin** dropdown, choose **"Custom"**.
3. **Adjust colors** — Seven color picker groups will appear:

| Setting | What It Controls |
|---------|-----------------|
| Header Background | Background color of the sidebar / navigation areas |
| Header Text | Text color in the sidebar / navigation areas |
| Body Background | Main page background color |
| Body Text | Default text color across the page |
| Link Color | Color of all hyperlinks |
| Button Background | Background color of primary buttons |
| Button Text | Text color on primary buttons |

4. **Preview in real time** — Colors are applied instantly as you pick them, so you can see the result before saving.
5. **Save** — Click **"Save Changes"** at the bottom of the settings page. Your custom colors are stored and will persist across sessions and page reloads.
6. **Reset** — Click the **"Reset Colors"** button to clear all custom color values and revert to the defaults.
7. **Switch skins** — Selecting a different skin from the dropdown hides the color pickers and applies the selected Bootswatch theme instead. Switching back to "Custom" restores your previously saved colors.

### User Testing Steps

| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | Navigate to Account → Settings | Settings page loads with a Skin dropdown |
| 2 | Select "Custom" from the Skin dropdown | Seven color pickers appear below the dropdown |
| 3 | Set a Body Background color (e.g., `#1a1a2e`) | The page background changes immediately |
| 4 | Set Header Background / Text colors | Both sidebars and the brand area update |
| 5 | Set Button Background / Text colors | All primary buttons (including pagination, badges, etc.) update |
| 6 | Set a Link Color | All hyperlinks change color |
| 7 | Click "Save Changes", then reload the page | All custom colors persist after reload (no flash of unstyled content) |
| 8 | Click "Reset Colors" | All color pickers clear and the page reverts to default styling |
| 9 | Switch to a different skin (e.g., Darkly) | Color pickers disappear; the Darkly theme is applied |
| 10 | Switch back to "Custom" | Color pickers reappear with previously saved colors |
| 11 | Enter an invalid color value via the API (e.g., `not-a-color`) | The server rejects it with error `[[error:invalid-theme-color]]` |
| 12 | Open a new browser/incognito window and log in | Custom colors load immediately on every page (FOUC prevention) |

---

## 4. Automated Tests

### Message Forwarding Tests

- **File:** [`test/messaging.js`](test/messaging.js) — `forwardMid` describe block (lines 631–674)
- **How to run:**
```bash
npx mocha test/messaging.js --grep "forwardMid" --timeout 60000
```

| Test | What It Validates |
|------|-------------------|
| `should fail if forwardMid is not a number` | Rejects non-numeric `forwardMid` values with "Invalid Chat Message ID" |
| `should forward firstMid using forwardMid` | A forwarded message round-trips correctly — `forwardedMessage` is present in the response with the correct `mid` and `content` |

**Why these tests are sufficient:** They cover the two critical paths: input validation (rejecting invalid IDs) and the full end-to-end flow (sending a forwarded message and verifying the forwarded content is correctly linked and returned in the message payload).

---

### Message Reactions Tests

- **File:** [`test/messaging.js`](test/messaging.js) — `Emoji Reactions` describe block (lines 880–941)
- **How to run:**
```bash
npx mocha test/messaging.js --grep "Emoji Reactions" --timeout 60000
```

| Test | What It Validates |
|------|-------------------|
| `should allow a user to add a reaction` | A user can successfully add a reaction; response confirms `added: true` |
| `should toggle off a reaction if the same emoji is sent again` | Sending the same emoji again removes the reaction (`added: false`) |
| `should return reactions with correct count and self flag` | Two users reacting with the same emoji yields `count: 2` and the requesting user sees `self: true` |
| `should reflect self as false for a user who has not reacted` | A non-reacting user sees `self: false` |
| `should reject an invalid emoji` | Non-emoji strings are rejected with a 400 error |
| `should reject a reaction from a user not in the room` | Unauthorized users receive a 403 error |
| `should include reactions in message payload` | Reactions are automatically included when fetching a message |

**Why these tests are sufficient:** They cover adding, toggling, counting, per-user state (`self` flag), input validation (invalid emoji), authorization (non-member rejection), and payload integration. Together, these tests exercise every backend code path in the reactions module.

---

### Custom Color Scheme Tests

- **File:** [`test/user.js`](test/user.js) — `custom theme` tests
- **How to run:**
```bash
npx mocha test/user.js --grep "custom theme" --timeout 60000
```

| Test | What It Validates |
|------|-------------------|
| `should save custom theme color settings` | All 7 color fields round-trip correctly through save and load |
| `should reject invalid custom theme color values` | Non-hex values are rejected with `[[error:invalid-theme-color]]` |
| `should allow empty custom theme color values` | Empty strings are accepted (allows users to clear individual colors) |
| `should sanitize custom theme color values on read` | Raw `<script>` tags stored in the DB are escaped to `&lt;script&gt;` on read (XSS prevention) |

**Why these tests are sufficient:** They validate the complete settings lifecycle — saving, loading, validation, clearing, and sanitization. The validation test ensures CSS injection is blocked, and the sanitization test confirms XSS protection at the data layer. These cover all server-side logic for the feature.
1 change: 1 addition & 0 deletions docker-compose-redis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ version: '3.8'

services:
nodebb:
user: '0'
build: .
# image: ghcr.io/nodebb/nodebb:latest
restart: unless-stopped
Expand Down
4 changes: 2 additions & 2 deletions install/data/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"disableChat": 0,
"chatEditDuration": 0,
"chatDeleteDuration": 0,
"chatMessageDelay": 2000,
"newbieChatMessageDelay": 120000,
"chatMessageDelay": 1000,
"newbieChatMessageDelay": 2000,
"notificationSendDelay": 60,
"newbieReputationThreshold": 3,
"postQueue": 1,
Expand Down
116 changes: 116 additions & 0 deletions message_reactions_user_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Emoji Reactions Feature - User Guide

## Overview
Registered users can react to chat messages with emojis. Reactions are visible to all users in the room and update in real time.

---

## How to Use

> *This section for frontend details*

- How to open the reaction picker
- How to add a reaction to a message
- How to remove a reaction (click again to toggle off)
- Where reaction counts are displayed
- How real-time updates appear

---

## API Reference (Backend)

The following REST endpoints are available for emoji reactions:

### Get Reactions for a Message
```
GET /api/v3/chats/:roomId/messages/:mid/reactions
```
Returns all reactions on a message, including count and whether the requesting user has reacted.

**Response:**
```json
{
"reactions": [
{ "emoji": "👍", "count": 3, "self": true },
{ "emoji": "😂", "count": 1, "self": false }
]
}
```

### Add or Remove a Reaction (Toggle)
```
POST /api/v3/chats/:roomId/messages/:mid/reactions
```
**Request body:**
```json
{ "emoji": "👍" }
```
**Response:**
```json
{ "added": true, "emoji": "👍" }
```
If the user has already reacted with that emoji, the reaction is removed and `added` will be `false`.

### Reactions in Message Payload
Reactions are also included automatically when fetching messages:
```
GET /api/v3/chats/:roomId/messages/:mid
```
The message object will include a `reactions` array in the same format as above.

---

## Real-Time Behavior
When any user adds or removes a reaction, all users currently in the room receive a socket event `event:chats.reaction` with the following payload:
```json
{
"mid": 123,
"uid": 456,
"emoji": "👍",
"added": true,
"reactions": [ ... ]
}
```
The full updated reactions array is included so the UI can re-render without any additional API calls.

---

## Validation & Authorization
- Only registered users who are members of the room can react to messages
- Only valid emoji characters are accepted — plain text will be rejected with a 400 error
- Each user can only have one reaction per emoji per message (toggling removes it)
- Reactions work on both regular and deleted messages

---

## Automated Tests

**Location**: `test/messaging.js` — search for the `Emoji Reactions` describe block near the bottom of the file.

**How to run:**
```bash
./node_modules/.bin/mocha test/messaging.js
```

### What is tested and why

| Test | Why |
|------|-----|
| User can add a reaction | Confirms the happy path works end to end |
| Toggling same emoji removes it | Confirms toggle behavior from the data model |
| Reaction count and self flag are correct | Confirms multi-user reactions aggregate correctly and self is user-specific |
| Self is false for a user who hasn't reacted | Confirms self flag isn't incorrectly true for all users |
| Invalid emoji is rejected | Confirms input validation |
| User not in room is rejected | Confirms authorization |
| Reactions included in message payload | Confirms reactions are bundled with messages automatically |

These tests cover all acceptance criteria: adding/removing reactions, correct aggregation, per-user self flag, authorization, validation, and message payload integration.

---

## Frontend Testing Guide

> *This section for frontend details*

- Step by step instructions for manually testing the feature in the browser
- Expected behavior for edge cases (e.g. reacting to your own message, multiple users reacting)
Loading