From 78410f41b985beccda259bd9bb2cb47bc5eb2d25 Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:08:42 -0500
Subject: [PATCH 1/8] Added privilege for users who can resolve posts
---
src/privileges/topics.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/privileges/topics.js b/src/privileges/topics.js
index 2a96589..1a7ee80 100644
--- a/src/privileges/topics.js
+++ b/src/privileges/topics.js
@@ -48,7 +48,8 @@ privsTopics.get = async function (tid, uid) {
'posts:view_deleted': privData['posts:view_deleted'] || isAdministrator,
read: privData.read || isAdministrator,
purge: (privData.purge && (isOwner || isModerator)) || isAdministrator,
-
+ // add privilege for resolve topics, only topic owner, admin, or mod
+ can_resolve: isOwner || isAdminOrMod,
view_thread_tools: editable || deletable,
editable: editable,
deletable: deletable,
From cbf2fe25ed7a159907e283cf74b00fa1df7cae8e Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:13:13 -0500
Subject: [PATCH 2/8] Added resolve field as number for topics
---
public/openapi/components/schemas/TopicObject.yaml | 4 ++++
src/topics/create.js | 5 ++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/public/openapi/components/schemas/TopicObject.yaml b/public/openapi/components/schemas/TopicObject.yaml
index 64de19a..ee39002 100644
--- a/public/openapi/components/schemas/TopicObject.yaml
+++ b/public/openapi/components/schemas/TopicObject.yaml
@@ -213,6 +213,10 @@ TopicObjectSlim:
type: number
postercount:
type: number
+ # Instructed to make this addition by ChatGPT, code by copilot autocomplete
+ # Add resolve field to topic schema
+ resolve:
+ type: number
scheduled:
type: number
deleted:
diff --git a/src/topics/create.js b/src/topics/create.js
index 56a53e0..a414225 100644
--- a/src/topics/create.js
+++ b/src/topics/create.js
@@ -38,6 +38,7 @@ module.exports = function (Topics) {
postcount: 0,
viewcount: 0,
isAnonymous: isAnonymous, // store anonymous status
+ resolve: 0, // Add resolve field to topic's data, defaults to 0 for unresolved (1 for resolved)
};
if (Array.isArray(data.tags) && data.tags.length) {
@@ -226,7 +227,9 @@ module.exports = function (Topics) {
topicInfo,
] = await Promise.all([
posts.getUserInfoForPosts([postData.uid], uid),
- Topics.getTopicFields(tid, ['tid', 'uid', 'title', 'slug', 'cid', 'postcount', 'mainPid', 'scheduled']),
+ // Instructed to add resolve field by ChatGPT
+ // Add resolve field to topic's field getter
+ Topics.getTopicFields(tid, ['tid', 'uid', 'resolve', 'title', 'slug', 'cid', 'postcount', 'mainPid', 'scheduled']),
Topics.addParentPosts([postData]),
Topics.syncBacklinks(postData),
posts.parsePost(postData),
From 6b651685cf606ead4fa949fa0f233a5df8b5bc47 Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:14:01 -0500
Subject: [PATCH 3/8] Added button for resolve topic on front-end
---
.../templates/partials/post_bar.tpl | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/themes/nodebb-theme-persona/templates/partials/post_bar.tpl b/themes/nodebb-theme-persona/templates/partials/post_bar.tpl
index 1bb6c77..c4ab9eb 100644
--- a/themes/nodebb-theme-persona/templates/partials/post_bar.tpl
+++ b/themes/nodebb-theme-persona/templates/partials/post_bar.tpl
@@ -17,4 +17,26 @@
+
+
+
+
+
+
+
From 7018847b3649c1675fd43a5cc8c7db002783bc8d Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:14:59 -0500
Subject: [PATCH 4/8] Added display for a topic's resolve status on front-end
---
themes/nodebb-theme-persona/templates/topic.tpl | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/themes/nodebb-theme-persona/templates/topic.tpl b/themes/nodebb-theme-persona/templates/topic.tpl
index 44c66c2..ec26128 100644
--- a/themes/nodebb-theme-persona/templates/topic.tpl
+++ b/themes/nodebb-theme-persona/templates/topic.tpl
@@ -16,6 +16,11 @@
{{{each icons}}}{@value}{{{end}}}
{title}
+
+ Resolved
+
+ Unresolved
+
From 798f437eec82534f5edaa8a8216c7bcce80ff600 Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:16:02 -0500
Subject: [PATCH 5/8] Added attribution to ChatGPT for topic partial
---
themes/nodebb-theme-persona/templates/topic.tpl | 1 +
1 file changed, 1 insertion(+)
diff --git a/themes/nodebb-theme-persona/templates/topic.tpl b/themes/nodebb-theme-persona/templates/topic.tpl
index ec26128..ef3935a 100644
--- a/themes/nodebb-theme-persona/templates/topic.tpl
+++ b/themes/nodebb-theme-persona/templates/topic.tpl
@@ -16,6 +16,7 @@
{{{each icons}}}{@value}{{{end}}}
{title}
+
Resolved
From 64d5a607bcd6e4eaa12706b5ca62206817f2b89b Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:17:44 -0500
Subject: [PATCH 6/8] Set up api endpoint for resolve a topic
---
public/openapi/write.yaml | 4 ++
public/openapi/write/topics/tid/resolve.yaml | 46 ++++++++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 public/openapi/write/topics/tid/resolve.yaml
diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml
index 6f55dbc..7ff5987 100644
--- a/public/openapi/write.yaml
+++ b/public/openapi/write.yaml
@@ -128,6 +128,10 @@ paths:
$ref: 'write/topics/tid/thumbs/order.yaml'
/topics/{tid}/events:
$ref: 'write/topics/tid/events.yaml'
+ # Instructed to add by ChatGPT, code written by copilot autocomplete
+ # Set up path to resolve topic endpoint
+ /topics/{tid}/resolve:
+ $ref: 'write/topics/tid/resolve.yaml'
/topics/{tid}/events/{eventId}:
$ref: 'write/topics/tid/events/eventId.yaml'
/posts/{pid}:
diff --git a/public/openapi/write/topics/tid/resolve.yaml b/public/openapi/write/topics/tid/resolve.yaml
new file mode 100644
index 0000000..acac2fa
--- /dev/null
+++ b/public/openapi/write/topics/tid/resolve.yaml
@@ -0,0 +1,46 @@
+# File instructed to write by ChatGPT, code written by ChatGPT
+# defines an API endpoint for resolving a topic
+put:
+ tags:
+ - topics
+ summary: Resolve a topic
+ description: Marks a topic as resolved.
+ operationId: resolveTopic
+ parameters:
+ - in: path
+ name: tid
+ required: true
+ schema:
+ type: number
+ description: The topic identifier that is to be marked as resolved.
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ resolved:
+ type: boolean
+ description: A boolean flag to indicate the resolve status. True to mark the topic as resolved, false to mark it as unresolved.
+ required:
+ - resolved
+ responses:
+ '200':
+ description: Topic successfully resolved
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ success:
+ type: boolean
+ message:
+ type: string
+ '400':
+ description: Bad request. Possible reasons: missing parameters or incorrect values.
+ '404':
+ description: Topic not found.
+ '401':
+ description: Unauthorized. User is not logged in or lacks the necessary permissions to resolve the topic.
+ '500':
+ description: Internal server error. An error occurred while attempting to resolve the topic.
From 8d94e971b8754e6ba85f8964e85edb6032e4d5e3 Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:18:51 -0500
Subject: [PATCH 7/8] Added resolve as a field for topic data
---
src/topics/data.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/topics/data.js b/src/topics/data.js
index 3d3051d..b9c4387 100644
--- a/src/topics/data.js
+++ b/src/topics/data.js
@@ -8,11 +8,13 @@ const utils = require('../utils');
const translator = require('../translator');
const plugins = require('../plugins');
+// Instructed to add by ChatGPT
+// Add resolve field to int fields of topic
const intFields = [
'tid', 'cid', 'uid', 'mainPid', 'postcount',
'viewcount', 'postercount', 'deleted', 'locked', 'pinned',
'pinExpiry', 'timestamp', 'upvotes', 'downvotes', 'lastposttime',
- 'deleterUid',
+ 'deleterUid','resolve',
];
module.exports = function (Topics) {
From 9b7953843009ee31f20624c94891295f6e08c9cd Mon Sep 17 00:00:00 2001
From: cathyxfeiyang <157295142+cathyxfeiyang@users.noreply.github.com>
Date: Wed, 28 Feb 2024 03:24:24 -0500
Subject: [PATCH 8/8] Add handling upon click of resolve button to resolve
topic
---
public/src/client/topic.js | 26 ++++++++++++++++++++++++++
src/controllers/write/topics.js | 12 ++++++++++++
src/routes/write/topics.js | 2 +-
src/topics/tools.js | 22 ++++++++++++++++++++++
4 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/public/src/client/topic.js b/public/src/client/topic.js
index 969b3da..23e90c1 100644
--- a/public/src/client/topic.js
+++ b/public/src/client/topic.js
@@ -63,6 +63,10 @@ define('forum/topic', [
addRepliesHandler();
addPostsPreviewHandler();
+ // instructed to add by ChatGPT, written by ChatGPT
+ // call handling function to handle click of resolve button
+ handleResolveButton();
+
handleBookmark(tid);
$(window).on('scroll', utils.debounce(updateTopicTitle, 250));
@@ -72,6 +76,28 @@ define('forum/topic', [
hooks.fire('action:topic.loaded', ajaxify.data);
};
+ // instructed to add by ChatGPT, written by ChatGPT
+ // handle click events for resolving topics
+ function handleResolveButton() {
+ // attach event listener to the resolve button
+ $(document).on('click', '[component="topic/resolve"]', function() {
+ // Sends a PUT request to the server to mark a topic, identified by 'tid', as resolved.
+ // The resolve parameter is set to 1, indicating the action to resolve the topic.
+ api.put('/topics/' + tid + '/resolve', { resolve: 1 })
+ .then(function(response) {
+ // Upon successful resolution, refreshes the page to reflect changes.
+ location.reload();
+ })
+ .catch(function(error) {
+ // If the PUT request fails, displays an error message to the user.
+ // It uses a custom alert system to show the error message or a default message if none is provided.
+ alerts.error(error.message || 'Failed to update topic resolution status.');
+ });
+ });
+ }
+
+
+
function handleTopicSearch() {
require(['mousetrap'], (mousetrap) => {
if (config.topicSearchEnabled) {
diff --git a/src/controllers/write/topics.js b/src/controllers/write/topics.js
index 6fcb475..e6e8571 100644
--- a/src/controllers/write/topics.js
+++ b/src/controllers/write/topics.js
@@ -31,6 +31,18 @@ Topics.create = async (req, res) => {
}
};
+// Code instructed to write and written by ChatGPT
+// Function to resolve a topic
+Topics.resolve = async (req, res) => {
+ // Call resolve tool to mark topic as resolved
+ // It takes the topic ID (tid) from the request parameters and the user ID (uid) from the request object.
+ await topics.tools.resolve(req.params.tid, req.uid);
+ // Send a success response to the client.
+ // It formats the response as per the API's standard, with a 200 OK status code.
+ helpers.formatApiResponse(200, res);
+};
+
+
Topics.reply = async (req, res) => {
const id = await lockPosting(req, '[[error:already-posting]]');
try {
diff --git a/src/routes/write/topics.js b/src/routes/write/topics.js
index 55b9b5a..2ad3647 100644
--- a/src/routes/write/topics.js
+++ b/src/routes/write/topics.js
@@ -17,7 +17,7 @@ module.exports = function () {
setupApiRoute(router, 'get', '/:tid', [], controllers.write.topics.get);
setupApiRoute(router, 'post', '/:tid', [middleware.checkRequired.bind(null, ['content']), middleware.assert.topic], controllers.write.topics.reply);
setupApiRoute(router, 'delete', '/:tid', [...middlewares], controllers.write.topics.purge);
-
+ setupApiRoute(router, 'put', '/:tid/resolve', [...middlewares], controllers.write.topics.resolve);
setupApiRoute(router, 'put', '/:tid/state', [...middlewares], controllers.write.topics.restore);
setupApiRoute(router, 'delete', '/:tid/state', [...middlewares], controllers.write.topics.delete);
diff --git a/src/topics/tools.js b/src/topics/tools.js
index c2a254b..413bfc5 100644
--- a/src/topics/tools.js
+++ b/src/topics/tools.js
@@ -23,6 +23,28 @@ module.exports = function (Topics) {
return await toggleDelete(tid, uid, false);
};
+ // Code instructed and written by ChatGPT
+ // Resolves a topic after checking for topic existence and privileges
+ topicTools.resolve = async function (tid, uid) {
+ const topicData = await topics.getTopicFields(tid, ['uid']);
+ // check if topic exists
+ if (!topicData) {
+ throw new Error('[[error:no-topic]]');
+ }
+ const isOwner = parseInt(topicData.uid, 10) === parseInt(uid, 10);
+ const isAdmin = await user.isAdministrator(uid);
+ const isMod = await user.isModerator(uid, tid); // Assuming tid can be used to determine the forum/category for moderator check
+ // Check if the user has the 'topics:can_resolve' privilege on the topic, or if they are the owner, an admin, or a moderator
+ const canResolve = isOwner || isAdmin || isMod;
+ if (!canResolve) {
+ throw new Error('[[error:no-privileges]]');
+ }
+ // Proceed to mark the topic as resolved since the user has the required privilege or role
+ await topics.setTopicField(tid, 'resolve', 1);
+ topicData.resolve = 1;
+ return topicData;
+ };
+
async function toggleDelete(tid, uid, isDelete) {
const topicData = await Topics.getTopicData(tid);
if (!topicData) {