diff --git a/README.md b/README.md
index 6ef180f..ab5b0d0 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+Team Sunglasses:
+
+Members: Aryan Jain, Eric Due, Emily Xie, Kayo Kuri, Justin Zou
+
+
# 
[](https://github.com/CMU-313/NodeBB/actions/workflows/test.yaml)
diff --git a/dump.rdb b/dump.rdb
index 0f9b366..aa9f7e2 100644
Binary files a/dump.rdb and b/dump.rdb differ
diff --git a/nodebb-theme-harmony/scss/topic.scss b/nodebb-theme-harmony/scss/topic.scss
index 4214054..e8c495a 100644
--- a/nodebb-theme-harmony/scss/topic.scss
+++ b/nodebb-theme-harmony/scss/topic.scss
@@ -86,22 +86,28 @@ body.template-topic {
}
.admin-star {
- width: 60px;
- height: 60px;
- background-color: gold;
- clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: bold;
- font-size: 10px;
- color: black;
- text-transform: uppercase;
- text-align: right;
- box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
- border-radius: 5px;
- top: 10px;
- left: 10px;
+ width: 16px; // Tiny but visible
+ height: 16px;
+ background: linear-gradient(145deg, #3a8dde, #1e5aa6); // Modern blue gradient
+ clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%,
+ 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: white;
+ font-size: 6px;
+ text-align: center;
+ font-weight: bold;
+ text-shadow: 0px 0px 2px rgba(255, 255, 255, 0.8);
+ box-shadow: 0px 2px 5px rgba(0, 0, 255, 0.3), inset 0px -2px 3px rgba(0, 0, 0, 0.2);
+ border-radius: 3px;
+ position: relative;
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
+
+ &:hover {
+ transform: scale(1.1);
+ box-shadow: 0px 3px 8px rgba(0, 0, 255, 0.5);
+ }
}
[component="post/replies/container"] {
diff --git a/nodebb-theme-harmony/templates/partials/topic/post.tpl b/nodebb-theme-harmony/templates/partials/topic/post.tpl
index 3c7fa28..97f378a 100644
--- a/nodebb-theme-harmony/templates/partials/topic/post.tpl
+++ b/nodebb-theme-harmony/templates/partials/topic/post.tpl
@@ -19,8 +19,8 @@
- {{{ if privileges.isAdminOrMod}}}
-
+ {{{if !posts.anonymous }}}
{posts.user.displayname}
+ {{{ else }}}
+
Anonymous
+ {{{ end }}}
{{{ each posts.user.selectedGroups }}}
{{{ if posts.user.selectedGroups.slug }}}
diff --git a/nodebb-theme-harmony/templates/partials/topic/quickreply.tpl b/nodebb-theme-harmony/templates/partials/topic/quickreply.tpl
index d26fdea..877d99d 100644
--- a/nodebb-theme-harmony/templates/partials/topic/quickreply.tpl
+++ b/nodebb-theme-harmony/templates/partials/topic/quickreply.tpl
@@ -17,7 +17,7 @@
diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml
index e7c77c5..be68c50 100644
--- a/public/openapi/components/schemas/Chats.yaml
+++ b/public/openapi/components/schemas/Chats.yaml
@@ -55,6 +55,8 @@ MessageObject:
type: number
isOwner:
type: boolean
+ groupTitle:
+ type: string
fromUser:
type: object
properties:
diff --git a/public/openapi/components/schemas/PostObject.yaml b/public/openapi/components/schemas/PostObject.yaml
index 8ca14ba..4d8b4fa 100644
--- a/public/openapi/components/schemas/PostObject.yaml
+++ b/public/openapi/components/schemas/PostObject.yaml
@@ -7,6 +7,8 @@ PostObject:
tid:
type: number
description: A topic identifier
+ anonymous:
+ type: number
content:
type: string
uid:
diff --git a/public/openapi/components/schemas/TopicObject.yaml b/public/openapi/components/schemas/TopicObject.yaml
index ee34558..663e44b 100644
--- a/public/openapi/components/schemas/TopicObject.yaml
+++ b/public/openapi/components/schemas/TopicObject.yaml
@@ -279,6 +279,8 @@ TopicObjectSlim:
tid:
type: number
description: A topic identifier
+ adminrole:
+ type: boolean
numThumbs:
type: number
description: The number of thumbnails associated with this topic
diff --git a/public/openapi/read/topic/topic_id.yaml b/public/openapi/read/topic/topic_id.yaml
index aff53aa..45df4f6 100644
--- a/public/openapi/read/topic/topic_id.yaml
+++ b/public/openapi/read/topic/topic_id.yaml
@@ -59,6 +59,8 @@ get:
tid:
type: number
description: A topic identifier
+ anonymous:
+ type: number
content:
type: string
timestamp:
@@ -91,6 +93,8 @@ get:
user:
type: object
properties:
+ adminrole:
+ type: boolean
uid:
type: number
description: A user identifier
diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml
index 6466a40..62999c4 100644
--- a/public/openapi/read/user/userslug/chats/roomid.yaml
+++ b/public/openapi/read/user/userslug/chats/roomid.yaml
@@ -84,6 +84,9 @@ get:
type: number
messageId:
type: number
+ groupTitle:
+ type: string
+ nullable: true
fromUser:
type: object
properties:
diff --git a/public/openapi/write/posts/pid.yaml b/public/openapi/write/posts/pid.yaml
index 4cd29c7..1449af6 100644
--- a/public/openapi/write/posts/pid.yaml
+++ b/public/openapi/write/posts/pid.yaml
@@ -32,6 +32,8 @@ get:
tid:
type: number
description: A topic identifier
+ anonymous:
+ type: number
content:
type: string
english:
diff --git a/public/openapi/write/posts/pid/isEndorsed.yaml b/public/openapi/write/posts/pid/isEndorsed.yaml
index c92b845..0f63ee6 100644
--- a/public/openapi/write/posts/pid/isEndorsed.yaml
+++ b/public/openapi/write/posts/pid/isEndorsed.yaml
@@ -18,5 +18,8 @@ get:
application/json:
schema:
type: object
- properties: {}
+ properties:
+ endorsed:
+ type: boolean
+ description: Indicates whether the post is endorsed or not
diff --git a/public/src/modules/quickreply.js b/public/src/modules/quickreply.js
index 55aea0b..d6a7552 100644
--- a/public/src/modules/quickreply.js
+++ b/public/src/modules/quickreply.js
@@ -58,11 +58,14 @@ define('quickreply', [
}
const replyMsg = components.get('topic/quickreply/text').val();
+ const anonymousCheckbox = components.get('topic/quickreply/anonymous').get(0).checked;
const replyData = {
tid: ajaxify.data.tid,
handle: undefined,
content: replyMsg,
+ anonymous: anonymousCheckbox,
};
+
const replyLen = replyMsg.length;
if (replyLen < parseInt(config.minimumPostLength, 10)) {
return alerts.error('[[error:content-too-short, ' + config.minimumPostLength + ']]');
diff --git a/src/api/posts.js b/src/api/posts.js
index 15b554f..0e1389b 100644
--- a/src/api/posts.js
+++ b/src/api/posts.js
@@ -173,11 +173,11 @@ postsAPI.setPostEndorsement = async function (pid, endorsed = true) {
};
postsAPI.getPostEndorsement = async function (pid) {
- db.isObjectField(`post:${pid}`, 'endorsed', (err, isField) => {
- if (err) {
- console.log(err);
- }
- return isField;
+ return new Promise((resolve, reject) => {
+ db.isObjectField(`post:${pid}`, 'endorsed', (err, isField) => {
+ if (err) reject(err);
+ else resolve(!!isField);
+ });
});
};
@@ -411,13 +411,13 @@ async function canSeeVotes(uid, cids, type) {
const cidToAllowed = _.zipObject(uniqCids, canRead);
const checks = cids.map(
(cid, index) => isAdmin || isMod[index] ||
- (
- cidToAllowed[cid] &&
(
- meta.config[type] === 'all' ||
- (meta.config[type] === 'loggedin' && parseInt(uid, 10) > 0)
+ cidToAllowed[cid] &&
+ (
+ meta.config[type] === 'all' ||
+ (meta.config[type] === 'loggedin' && parseInt(uid, 10) > 0)
+ )
)
- )
);
return isArray ? checks : checks[0];
}
diff --git a/src/api/users.js b/src/api/users.js
index c4f4add..b883443 100644
--- a/src/api/users.js
+++ b/src/api/users.js
@@ -180,7 +180,7 @@ usersAPI.follow = async function (caller, data) {
toUid: data.uid,
});
- const userData = await user.getUserFields(caller.uid, ['username', 'userslug']);
+ const userData = await user.getUserFields(caller.uid, ['username', 'userslug', 'adminrole']);
const { displayname } = userData;
const notifObj = await notifications.create({
diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js
index cb7056b..6f7b3bc 100644
--- a/src/categories/recentreplies.js
+++ b/src/categories/recentreplies.js
@@ -172,7 +172,7 @@ module.exports = function (Categories) {
]);
await batch.processArray(pids, async (pids) => {
- const postData = await posts.getPostsFields(pids, ['pid', 'deleted', 'uid', 'timestamp', 'upvotes', 'downvotes']);
+ const postData = await posts.getPostsFields(pids, ['pid', 'anonymous', 'deleted', 'uid', 'timestamp', 'upvotes', 'downvotes']);
const bulkRemove = [];
const bulkAdd = [];
diff --git a/src/categories/topics.js b/src/categories/topics.js
index 12a009e..f4c86d5 100644
--- a/src/categories/topics.js
+++ b/src/categories/topics.js
@@ -16,6 +16,23 @@ module.exports = function (Categories) {
const tids = await Categories.getTopicIds(results);
let topicsData = await topics.getTopicsByTids(tids, data.uid);
topicsData = await user.blocks.filter(data.uid, topicsData);
+
+ const adminRole = await Promise.all(
+ topicsData.map(async (topic) => {
+ const isAdmin = await user.isAdministrator(topic.uid);
+ if (isAdmin) {
+ return 'Admin';
+ }
+ return 'user';
+ })
+ );
+ topicsData.forEach((topic, index) => {
+ if (adminRole[index] === 'Admin') {
+ topic.adminrole = 'Admin';
+ } else {
+ topic.adminrole = 'User';
+ }
+ });
if (!topicsData.length) {
return { topics: [], uid: data.uid };
}
diff --git a/src/controllers/category.js b/src/controllers/category.js
index c1857c0..24b1133 100644
--- a/src/controllers/category.js
+++ b/src/controllers/category.js
@@ -38,7 +38,6 @@ function check3(req, utils, cid) {
}
categoryController.get = async function (req, res, next) {
- console.log('Justin Zou');
const cid = req.params.category_id;
let currentPage = parseInt(req.query.page, 10) || 1;
diff --git a/src/controllers/user.js b/src/controllers/user.js
index 6c924ac..c4bc6fe 100644
--- a/src/controllers/user.js
+++ b/src/controllers/user.js
@@ -12,7 +12,15 @@ userController.getCurrentUser = async function (req, res) {
}
const userslug = await user.getUserField(req.uid, 'userslug');
const userData = await accountHelpers.getUserDataByUserSlug(userslug, req.uid, req.query);
+ const isAdmin = await user.isAdministrator(req.uid);
+ let role = 'None';
+ if (isAdmin) {
+ role = 'Admin';
+ } else {
+ role = 'User';
+ }
res.json(userData);
+ userData.adminrole = role;
};
userController.getUserByUID = async function (req, res, next) {
diff --git a/src/messaging/data.js b/src/messaging/data.js
index dcb77bc..897d15d 100644
--- a/src/messaging/data.js
+++ b/src/messaging/data.js
@@ -59,17 +59,26 @@ module.exports = function (Messaging) {
messages = await user.blocks.filter(uid, 'fromuid', messages);
const users = await user.getUsersFields(
messages.map(msg => msg && msg.fromuid),
- ['uid', 'username', 'userslug', 'picture', 'status', 'banned', 'groupTitle']
+ ['uid', 'username', 'userslug', 'picture', 'status', 'banned', 'groupTitle', 'groupTitleArray']
);
messages.forEach((message, index) => {
message.fromUser = users[index];
message.fromUser.banned = !!message.fromUser.banned;
message.fromUser.deleted = message.fromuid !== message.fromUser.uid && message.fromUser.uid === 0;
+ message.groupTitle = '';
+ if (message.fromUser.groupTitle && message.fromUser.groupTitle.length > 0 &&
+ message.fromUser.groupTitleArray[0] !== undefined) {
+ const rawTitles = message.fromUser.groupTitleArray.slice(0, 3);
+ const cleanTitles = rawTitles.map((title) => {
+ const formattedTitle = title.replace(/"/g, '');
+ return formattedTitle.charAt(0).toUpperCase() + formattedTitle.slice(1);
+ });
+ message.groupTitle = cleanTitles.join(', ');
+ }
const self = message.fromuid === parseInt(uid, 10);
message.self = self ? 1 : 0;
-
message.newSet = false;
message.roomId = String(message.roomId || roomId);
});
diff --git a/src/posts/create.js b/src/posts/create.js
index 3305608..81675bc 100644
--- a/src/posts/create.js
+++ b/src/posts/create.js
@@ -18,6 +18,7 @@ module.exports = function (Posts) {
const { uid } = data;
const { tid } = data;
const content = data.content.toString();
+ const anonymous = data.anonymous ? 1 : 0;
const timestamp = data.timestamp || Date.now();
const isMain = data.isMain || false;
const [english, translatedTxt] = await translationApi.translate(data);
@@ -37,6 +38,7 @@ module.exports = function (Posts) {
tid: tid,
english: english,
translation: translatedTxt,
+ anonymous: anonymous,
content: content,
timestamp: timestamp,
};
diff --git a/src/posts/data.js b/src/posts/data.js
index 2ea2c39..bb7a287 100644
--- a/src/posts/data.js
+++ b/src/posts/data.js
@@ -5,7 +5,7 @@ const plugins = require('../plugins');
const utils = require('../utils');
const intFields = [
- 'uid', 'pid', 'tid', 'deleted', 'timestamp',
+ 'uid', 'pid', 'tid', 'anonymous', 'deleted', 'timestamp',
'upvotes', 'downvotes', 'deleterUid', 'edited',
'replies', 'bookmarks',
];
diff --git a/src/posts/summary.js b/src/posts/summary.js
index 364baad..6c10ded 100644
--- a/src/posts/summary.js
+++ b/src/posts/summary.js
@@ -20,7 +20,7 @@ module.exports = function (Posts) {
options.parse = options.hasOwnProperty('parse') ? options.parse : true;
options.extraFields = options.hasOwnProperty('extraFields') ? options.extraFields : [];
- const fields = ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted', 'upvotes', 'downvotes', 'replies', 'handle'].concat(options.extraFields);
+ const fields = ['pid', 'tid', 'content', 'anonymous', 'uid', 'timestamp', 'deleted', 'upvotes', 'downvotes', 'replies', 'handle'].concat(options.extraFields);
let posts = await Posts.getPostsFields(pids, fields);
posts = posts.filter(Boolean);
diff --git a/src/topics/create.js b/src/topics/create.js
index 47aade7..5eb7734 100644
--- a/src/topics/create.js
+++ b/src/topics/create.js
@@ -183,9 +183,10 @@ module.exports = function (Topics) {
await guestHandleValid(data);
data.content = String(data.content || '').trimEnd();
-
data.content = utils.censorBannedMarkdown(data.content);
+ data.anonymous = data.anonymous ? 1 : 0;
+
if (!data.fromQueue && !isAdmin) {
await user.isReadyToPost(uid, data.cid);
Topics.checkContent(data.content);
diff --git a/src/topics/posts.js b/src/topics/posts.js
index 73eb29b..9215409 100644
--- a/src/topics/posts.js
+++ b/src/topics/posts.js
@@ -1,4 +1,3 @@
-
'use strict';
const _ = require('lodash');
@@ -108,10 +107,11 @@ module.exports = function (Topics) {
return [];
}
const pids = postData.map(post => post && post.pid);
-
+ let outsideUids = null;
async function getPostUserData(field, method) {
const uids = _.uniq(postData.filter(p => p && parseInt(p[field], 10) >= 0).map(p => p[field]));
const userData = await method(uids);
+ outsideUids = uids;
return _.zipObject(uids, userData);
}
const [
@@ -124,7 +124,7 @@ module.exports = function (Topics) {
posts.hasBookmarked(pids, uid),
posts.getVoteStatusByPostIDs(pids, uid),
getPostUserData('uid', async uids => await posts.getUserInfoForPosts(uids, uid)),
- getPostUserData('editor', async uids => await user.getUsersFields(uids, ['uid', 'username', 'userslug'])),
+ getPostUserData('editor', async uids => await user.getUsersFields(uids, ['uid', 'username', 'userslug', 'isAdmin'])),
getPostReplies(postData, uid),
Topics.addParentPosts(postData),
]);
@@ -139,8 +139,9 @@ module.exports = function (Topics) {
postObj.votes = postObj.votes || 0;
postObj.replies = replies[i];
postObj.selfPost = parseInt(uid, 10) > 0 && parseInt(uid, 10) === postObj.uid;
-
- // Username override for guests, if enabled
+ outsideUids.forEach((i) => {
+ userData[String(i)].adminrole = userData[String(i)].groupTitle !== null;
+ });
if (meta.config.allowGuestHandles && postObj.uid === 0 && postObj.handle) {
postObj.user.username = validator.escape(String(postObj.handle));
postObj.user.displayname = postObj.user.username;
diff --git a/src/user/posts.js b/src/user/posts.js
index c33ebd2..1fbbb12 100644
--- a/src/user/posts.js
+++ b/src/user/posts.js
@@ -93,7 +93,6 @@ module.exports = function (User) {
User.setUserField(postData.uid, 'lastposttime', lastposttime),
User.updateLastOnlineTime(postData.uid),
]);
- console.log('jzou was here');
};
diff --git a/src/utils.js b/src/utils.js
index 2e62507..fcd5f1b 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -116,9 +116,9 @@ utils.censorBannedMarkdown = function (content) {
return content.replace(bannedWordsRegex, (match) => {
if (match.length <= 2) {
// Replace single-character words with "*"
- return '**';
+ return '\\*\\*';
}
- return match[0] + '*'.repeat(match.length - 2) + match.slice(-1);
+ return match[0] + '\\*'.repeat(match.length - 2) + match.slice(-1);
});
};
diff --git a/src/views/partials/chats/message.tpl b/src/views/partials/chats/message.tpl
index 3f80116..257318f 100644
--- a/src/views/partials/chats/message.tpl
+++ b/src/views/partials/chats/message.tpl
@@ -7,8 +7,8 @@