Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install and Run StandardJs Static Analysis #106

Open
wants to merge 46 commits into
base: f24
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0892712
add deadline
github-classroom[bot] Sep 9, 2024
cc38626
Added test search functionality to filter on 'test' and template sear…
alx-zhu Sep 23, 2024
7b4544b
Added a new div in votes.tpl to handle if a post has been endorsed
John-Crawshaw Sep 23, 2024
6e0f988
Modified voters.yaml in order to pass boolean to front end to show en…
John-Crawshaw Sep 24, 2024
5a38228
added for loop to check if an admin is present in the voter list: src…
Victor-Crawshaw Sep 24, 2024
4bbfd52
fixed linter error for src/api/posts.js
Victor-Crawshaw Sep 24, 2024
f530fc0
Minor change to font size in votes.tpl
John-Crawshaw Sep 24, 2024
2edbfe0
Merge pull request #12 from CMU-313/endorseFeature
John-Crawshaw Sep 24, 2024
16ac073
Merge pull request #11 from CMU-313/john-endorse
Victor-Crawshaw Sep 24, 2024
a79f205
Handled search based on topic titles using search bar with component=…
alx-zhu Sep 24, 2024
ab4756e
Removing dump.rdb and adding to gitignore.
alx-zhu Sep 24, 2024
5ca0ad0
Merge pull request #9 from CMU-313/alex/feature/filter-topics-on-sear…
alx-zhu Sep 24, 2024
8aea459
Added endorseEnabled as a new field for Groups; updated corresponding…
HeidiTao Oct 5, 2024
09e44d2
changes to backend src/api/posts.js, src/posts/votes.js, and src/topi…
Victor-Crawshaw Oct 9, 2024
1d9ab9a
changes to mocharc and topic_id.yaml to make tests run properly - fix…
Victor-Crawshaw Oct 9, 2024
2f075ec
Added topic post content to the topic data to display when matching a…
alx-zhu Oct 9, 2024
f8fc584
Merge pull request #25 from CMU-313/victorEndorse
John-Crawshaw Oct 9, 2024
bd6a988
added unit tests to test/topics.js to ensure that when an admin upvot…
John-Crawshaw Oct 9, 2024
27fa4c7
added unit tests to test/topics.js to ensure that when a a non-admin …
John-Crawshaw Oct 9, 2024
0f930f1
Merge pull request #26 from CMU-313/john-endorse-tests
Victor-Crawshaw Oct 9, 2024
6421066
initialized UserGuide.md
John-Crawshaw Oct 9, 2024
4cf7192
added instructions for how to use and user test the endorse feature
John-Crawshaw Oct 9, 2024
7bfe10d
fixed typo in UserGuide.md
John-Crawshaw Oct 9, 2024
b806bd6
Added the comma that caused the lint error in the previous commit
HeidiTao Oct 10, 2024
8cc1715
Merge pull request #17 from CMU-313/heidit_add_endorse_checkbox
HeidiTao Oct 10, 2024
f23b1f7
Fixing linter errors in topics.js and cateogry.js
alx-zhu Oct 10, 2024
ada548b
Added comments for highlighting snippets
alx-zhu Oct 10, 2024
5c3c277
Adding content to the topic object schema
alx-zhu Oct 10, 2024
9540c07
Reverting automated formatting from Prettier
alx-zhu Oct 10, 2024
7d96824
Adding test cases for content in topics.
alx-zhu Oct 10, 2024
5f1d53c
Merge pull request #20 from CMU-313/alex/feature/filter-topics-on-sea…
alx-zhu Oct 10, 2024
eb197fa
add search feature to user guide
sherryzhuge1 Oct 10, 2024
735f833
Adding user guide for search and search video guide
alx-zhu Oct 10, 2024
9febd57
added video to public folder and more detailed instructions for endor…
John-Crawshaw Oct 10, 2024
2c90860
Merge pull request #28 from CMU-313/documentation-featue
alx-zhu Oct 10, 2024
66c41f3
Edited UserGuide to include steps for changing admin group settings
HeidiTao Oct 10, 2024
8bcbb2d
Fixed a typo from the previous commit
HeidiTao Oct 10, 2024
8fe5068
Add or update the Azure App Service build and deployment workflow config
alx-zhu Oct 21, 2024
2861892
Delete .github/workflows/f24_nodebb-codebb.yml
alx-zhu Oct 21, 2024
c46874b
Update azure-deploy-f24.yml
alx-zhu Oct 21, 2024
d8cfee3
Update azure-deploy-f24.yml node-version for actions issue
alx-zhu Oct 21, 2024
e8dfab7
Adding frontend repo installation to azure-deploy-f24.yml
alx-zhu Oct 24, 2024
0aa7986
Merge pull request #31 from CMU-313/azure-deploy
Victor-Crawshaw Oct 24, 2024
3f6b3eb
Moving install frontend step after nodebb setup
alx-zhu Oct 24, 2024
63b0053
Merge pull request #32 from CMU-313/azure-deploy
alx-zhu Oct 24, 2024
0ee2cde
add standard to workflow
sherryzhuge1 Oct 24, 2024
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
14 changes: 9 additions & 5 deletions .github/workflows/azure-deploy-f24.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
./.github/workflows/test.yaml

build-and-deploy:
if: github.repository == 'cmu-313/NodeBB'
if: github.repository == 'cmu-313/nodebb-f24-codebb'
needs: lint-and-test

runs-on: ubuntu-latest
Expand All @@ -30,11 +30,11 @@ jobs:
- name: Set up Node.js version
uses: actions/setup-node@v3
with:
node-version: '20.x'
node-version: '20.17.0'

- name: Set up NodeBB
run: |
./nodebb setup '{"url":"https://nodebb-f24.azurewebsites.net:443",
./nodebb setup '{"url":"nodebb-codebb.azurewebsites.net:443",
"admin:username": "admin",
"admin:password": "${{ secrets.ADMIN_PASSWORD }}",
"admin:password:confirm": "${{ secrets.ADMIN_PASSWORD }}",
Expand All @@ -43,12 +43,16 @@ jobs:
"redis:host": "${{ secrets.REDIS_HOST }}",
"redis:port": "6379",
"redis:password": "${{ secrets.REDIS_PASSWORD }}" }'

- name: Install frontend repo
run: |
npm install https://github.com/CMU-313/nodebb-frontend-f24-codebb.git

- name: 'Deploy to Azure Web App'
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: 'nodebb-f24'
app-name: 'nodebb-codebb'
slot-name: 'Production'
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_BFAB97B1AB1441ACA7C63280F91AD3F3 }}
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_20CFEB73ED1242B9B00348997130EDD9 }}
package: .
12 changes: 8 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ defaults:
shell: bash

permissions:
checks: write # for coverallsapp/github-action to create new checks
contents: read # for actions/checkout to fetch code
checks: write # for coverallsapp/github-action to create new checks
contents: read # for actions/checkout to fetch code

jobs:
test:
runs-on: ubuntu-latest
env:
TEST_ENV: 'production'
TEST_ENV: "production"

services:
redis:
image: 'redis:7.2.4'
image: "redis:7.2.4"
# Set health checks to wait until redis has started
options: >-
--health-cmd "redis-cli ping"
Expand Down Expand Up @@ -85,3 +85,7 @@ jobs:

- name: Test coverage
uses: coverallsapp/github-action@v2

# Add StandardJS Linting Step
- name: Run StandardJS Linter
run: npx standard
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,7 @@ link-plugins.sh
test.sh

.docker/**
!**/.gitkeep
!**/.gitkeep

# Dump
dump.rdb
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/ithVU1OO)
# ![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
54 changes: 54 additions & 0 deletions UserGuide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# USER GUIDE FOR NEW FEATURES:

### Endorse Feature:

Video Demo:
[Endorse Demo](public/EndorseVideo.mp4)

- To use the endorse you must be logged in as an admin user
- Once logged in as an admin select a group and edit its setting
- In the admin group settings page, toggle on the “Allow Endorse” checkbox and save this change
- Go to a topic and find a post
- On the post click on the upvote button
- Refresh the page and there will be a message next to the timestamp stating
that the post has been endorsed by an instructor and there will also be a
message when you click on the number of people who voted stating the same
message
- Removing the upvote and refreshing the page will cause these messages to
disappear
- To user test this feature you can try logging in as non-admin users and
upvote posts to ensure that the endorsement message is not displayed after
upovting. Then login as an admin and upvote the post to ensure it works
for admins. Also try removing the upvote as an admin to make sure the
message goes away. Note that the page must be refreshed after the upvote
action in order to see changes.


### Endorse Testing:
- Testing for endorse can be found in [test/topics.js](test/topics.js#L2508)
- These tests ensure that when admins upvote the boolean showendorse is set to true
and if they are not an admin then showendorse is kept as false
- These tests are sufficient as they cover the possible scnearios of both admin and
non-admin users upvoting.

### Search Feature:

Video:
[Search Demo](public/SearchScreenshot.mov)

- To use the search feature you must be logged in
- Once logged in, navigate to any category (Announcements, General Discussion, Comments, Blog)
- Add at least 2 new topics if there are no topics present.
- Find the search bar next to the New Topic Button in the tool bar.
- Enter a query: type in any keyword found in a topic you created. Only posts with the keyword in it will be displayed.
- If the keyword does not exist in any content or title, a message No topics match the search term \_\_\_ will be displayed.
- If the search query is in the content, a small snippet will show under the topic, with the query term bolded.
- Clicking on results will take you directly to post.
- To user test this feature try searching for a common keyword and ensure
relevant posts show up. You can also create a new post and search for a term that exists in the post to verify. Search for a word that does not exist and ensure "No topics match the search term" message displays.

#### Search Testing:

- Testing backend changes can be found in [test/categories.js](test/categories.js#L140)
- Added tests to getCategoryTopics tests, which was the only backend function changed, to ensure that each topic has a content field and that the content fields have no html tags.
- Otherwise, no other backend changes were made for Search that can be tested.
Binary file added public/EndorseVideo.mp4
Binary file not shown.
Binary file added public/SearchScreenshot.mov
Binary file not shown.
1 change: 1 addition & 0 deletions public/language/ar/admin/manage/groups.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"edit.label-color": "Group Label Color",
"edit.text-color": "Group Text Color",
"edit.show-badge": "Show Badge",
"edit.show-endorse": "Allow Endorse",
"edit.private-details": "If enabled, joining of groups requires approval from a group owner.",
"edit.private-override": "Warning: Private groups is disabled at system level, which overrides this option.",
"edit.disable-join": "Disable join requests",
Expand Down
1 change: 1 addition & 0 deletions public/language/en-GB/groups.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"details.change-text-colour": "Change Text Colour",
"details.badge-text": "Badge Text",
"details.userTitleEnabled": "Show Badge",
"details.endorseEnabled": "Allow Endorse",
"details.private-help": "If enabled, joining of groups requires approval from a group owner",
"details.hidden": "Hidden",
"details.hidden-help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually",
Expand Down
4 changes: 4 additions & 0 deletions public/openapi/components/schemas/GroupObject.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ GroupFullObject:
description: Same as userTitle but with translation tokens escaped, used to display raw userTitle in group management
userTitleEnabled:
type: number
endorseEnabled:
type: number
description:
type: string
description: The group description
Expand Down Expand Up @@ -170,6 +172,8 @@ GroupDataObject:
description: Same as userTitle but with translation tokens escaped, used to display raw userTitle in group management
userTitleEnabled:
type: number
endorseEnabled:
type: number
description:
type: string
description: The group description
Expand Down
4 changes: 4 additions & 0 deletions public/openapi/components/schemas/TopicObject.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ TopicObject:
tid:
type: number
description: A topic identifier
content:
type: string
nullable: true
description: Content of the original topic post for showing search previews.
thumb:
type: string
pinExpiry:
Expand Down
3 changes: 3 additions & 0 deletions public/openapi/read/admin/manage/groups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ get:
type: string
userTitleEnabled:
type: number
endorseEnabled:
type: number
disableJoinRequests:
type: number
disableLeave:
Expand Down Expand Up @@ -88,6 +90,7 @@ get:
- cover:url
- cover:position
- userTitleEnabled
- endorseEnabled
- disableJoinRequests
- disableLeave
- nameEncoded
Expand Down
2 changes: 2 additions & 0 deletions public/openapi/read/groups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ get:
type: number
userTitleEnabled:
type: number
endorseEnabled:
type: number
disableJoinRequests:
type: number
disableLeave:
Expand Down
2 changes: 2 additions & 0 deletions public/openapi/read/topic/topic_id.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ get:
type: boolean
downvoted:
type: boolean
showendorse:
type: boolean
replies:
type: object
properties:
Expand Down
2 changes: 2 additions & 0 deletions public/openapi/write/posts/pid/voters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ get:
type: array
downvoters:
type: array
showEndorse:
type: boolean

1 change: 1 addition & 0 deletions public/src/admin/manage/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ define('admin/manage/group', [
labelColor: changeGroupLabelColor.val(),
textColor: changeGroupTextColor.val(),
userTitleEnabled: $('#group-userTitleEnabled').is(':checked'),
endorseEnabled: $('#group-endorseEnabled').is(':checked'),
private: $('#group-private').is(':checked'),
hidden: $('#group-hidden').is(':checked'),
memberPostCids: $('#memberPostCids').val(),
Expand Down
56 changes: 56 additions & 0 deletions public/src/client/category.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ define('forum/category', [
},
});

handleTopicSearch();

hooks.fire('action:topics.loaded', { topics: ajaxify.data.topics });
hooks.fire('action:category.loaded', { cid: ajaxify.data.cid });
};
Expand Down Expand Up @@ -112,6 +114,60 @@ define('forum/category', [
});
}

// Search for topics in the category based on the search term.
function handleTopicSearch() {
const searchEl = $('[component="topic-search"]');
const topicEls = $('[component="category/topic"]');

if (!searchEl.length) {
return;
}

searchEl.on('keyup', function () {
const searchTerm = searchEl.val().toLowerCase();

topicEls.each(function () {
const topicEl = $(this);
const titleEl = topicEl.find('[component="topic/header"] a');
const title = titleEl.text().toLowerCase();
const titleMatch = title.indexOf(searchTerm) !== -1;
const contentEl = topicEl.find('[component="topic/hidden-content"]');
const content = contentEl.text().toLowerCase();
const contentIdx = content.indexOf(searchTerm);
const hasMatch = (titleMatch || (contentIdx !== -1));
const searchContentEl = topicEl.find('[component="topic/search-content"]');

// Hide topics that don't match the search term in their title or their content
topicEl.toggleClass('hidden', !hasMatch);

// Use topic/search-content placeholder to display the 100 character preview around the search term.
// Only do this if the search is more than 2 characters
if (contentIdx !== -1 && searchTerm.length >= 2) {
const start = Math.max(0, contentIdx - 50);
const end = Math.min(content.length, contentIdx + searchTerm.length + 50);
const snippet = content.substring(start, end);

// Make the search term come out bold in the search preview
const highlightedSnippet = snippet.replace(searchTerm, `<strong>${searchTerm}</strong>`);
searchContentEl.html(`...${highlightedSnippet}...`);
} else {
searchContentEl.html('');
}
});

// Show the alert for no matches if there are no matched topics, otherwise keep it hidden.
const visibleTopics = topicEls.filter(':not(.hidden)');
const alertComponent = $('[component="category/topic/no-matches"]');
if (visibleTopics.length === 0) {
alertComponent.removeClass('hidden');
alertComponent.html(`No topics match the search term ${searchTerm}.`);
} else {
alertComponent.addClass('hidden');
alertComponent.html('');
}
});
}

Category.toTop = function () {
navigator.scrollTop(0);
};
Expand Down
12 changes: 12 additions & 0 deletions src/api/posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,13 +335,25 @@ postsAPI.getVoters = async function (caller, data) {
user.getUsersFields(downvoteUids, ['username', 'userslug', 'picture']),
]);

let hasAdminUpvoted = false;

const uidPromises = upvoteUids.map(uid => groups.isMemberOfGroups(uid, ['administrators']));
const results = await Promise.all(uidPromises);
for (const isAdmin of results) {
if (isAdmin[0]) {
hasAdminUpvoted = true;
break; // Exit loop as soon as an admin is found
}
}

return {
upvoteCount: upvoters.length,
downvoteCount: downvoters.length,
showUpvotes: showUpvotes,
showDownvotes: showDownvotes,
upvoters: upvoters,
downvoters: downvoters,
showEndorse: hasAdminUpvoted,
};
};

Expand Down
11 changes: 11 additions & 0 deletions src/categories/topics.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const sanitizeHtml = require('sanitize-html');
const db = require('../database');
const topics = require('../topics');
const plugins = require('../plugins');
Expand All @@ -17,6 +18,16 @@ module.exports = function (Categories) {
let topicsData = await topics.getTopicsByTids(tids, data.uid);
topicsData = await user.blocks.filter(data.uid, topicsData);

// Add actual post content to the topicsData to show search previews
const mainPosts = await topics.getMainPosts(tids, data.uid);
topicsData.forEach((topic, idx) => {
// Clean all html, allowing no tags or attributes
topic.content = sanitizeHtml(mainPosts[idx].content, {
allowedTags: [],
allowedAttributes: {},
});
});

if (!topicsData.length) {
return { topics: [], uid: data.uid };
}
Expand Down
1 change: 1 addition & 0 deletions src/groups/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module.exports = function (Groups) {
createtime: timestamp,
userTitle: data.userTitle || data.name,
userTitleEnabled: parseInt(data.userTitleEnabled, 10) === 1 ? 1 : 0,
endorseEnabled: parseInt(data.endorseEnabled, 10) === 1 ? 1 : 0,
description: data.description || '',
memberCount: memberCount,
hidden: isHidden ? 1 : 0,
Expand Down
3 changes: 2 additions & 1 deletion src/groups/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const translator = require('../translator');

const intFields = [
'createtime', 'memberCount', 'hidden', 'system', 'private',
'userTitleEnabled', 'disableJoinRequests', 'disableLeave',
'userTitleEnabled', 'disableJoinRequests', 'disableLeave', 'endorseEnabled',
];

module.exports = function (Groups) {
Expand Down Expand Up @@ -71,6 +71,7 @@ function modifyGroup(group, fields) {

escapeGroupData(group);
group.userTitleEnabled = ([null, undefined].includes(group.userTitleEnabled)) ? 1 : group.userTitleEnabled;
group.endorseEnabled = ([null, undefined].includes(group.endorseEnabled)) ? 1 : group.endorseEnabled;
group.labelColor = validator.escape(String(group.labelColor || '#000000'));
group.textColor = validator.escape(String(group.textColor || '#ffffff'));
group.icon = validator.escape(String(group.icon || ''));
Expand Down
Loading
Loading