Skip to content

Commit

Permalink
Merge pull request #47 from CMU-313/amanda/sprint2changes
Browse files Browse the repository at this point in the history
US9 - Fully worked backend functionality for the "Resolved" feature
  • Loading branch information
ilong4rennes authored Oct 9, 2024
2 parents 75a4d19 + aca215b commit a4b0c50
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 10 deletions.
Binary file added dump.rdb
Binary file not shown.
2 changes: 1 addition & 1 deletion install/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"nodebb-plugin-ntfy": "1.7.4",
"nodebb-plugin-spam-be-gone": "2.2.2",
"nodebb-rewards-essentials": "1.0.0",
"nodebb-theme-harmony": "1.2.63",
"nodebb-theme-harmony": "file:../nodebb-frontend-f24-the-turtles",
"nodebb-theme-lavender": "7.1.8",
"nodebb-theme-peace": "2.2.6",
"nodebb-theme-persona": "13.3.25",
Expand Down
7 changes: 2 additions & 5 deletions public/language/en-GB/topic.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
"thread-tools.change-owner": "Change Owner",
"thread-tools.select-category": "Select Category",
"thread-tools.fork": "Fork Topic",
"thread-tools.tag": "Tag Topic AAA",
"thread-tools.tag": "Tag Topic",
"thread-tools.delete": "Delete Topic",
"thread-tools.delete-posts": "Delete Posts",
"thread-tools.delete-confirm": "Are you sure you want to delete this topic?",
Expand All @@ -128,10 +128,7 @@
"thread-tools.purge-confirm" : "Are you sure you want to purge this topic?",
"thread-tools.merge-topics": "Merge Topics",
"thread-tools.merge": "Merge Topic",
"thread-tools.resolve": "Resolve Topic",
"thread-tools.resolve-confirm": "Are you sure you want to resolve this topic?",
"thread-tools.resolve-success": "The topic has been successfully resolved.",

"thread-tools.resolve": "Are you sure you want to resolve this topic?",

"topic-move-success": "This topic will be moved to \"%1\" shortly. Click here to undo.",
"topic-move-multiple-success": "These topics will be moved to \"%1\" shortly. Click here to undo.",
Expand Down
21 changes: 21 additions & 0 deletions public/openapi/write/topics/tid/resolve.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
paths:
/topics/{tid}/resolve:
put:
summary: Resolve a topic
description: Marks a topic as resolved.
parameters:
- name: tid
in: path
required: true
description: Topic ID
schema:
type: integer
responses:
'200':
description: Topic marked as resolved successfully
'400':
description: Invalid request
'403':
description: Not authorized
'404':
description: Topic not found
18 changes: 16 additions & 2 deletions public/src/client/category/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ define('forum/category/tools', [
socket.on('event:topic_unlocked', setLockedState);
socket.on('event:topic_pinned', setPinnedState);
socket.on('event:topic_unpinned', setPinnedState);
socket.on('event:topic_resolved', setResolvedState);
socket.on('event:topic_unresolved', setResolvedState);
socket.on('event:topic_moved', onTopicMoved);
};

Expand Down Expand Up @@ -173,8 +175,8 @@ define('forum/category/tools', [
threadTools.requestPinExpiry(body, execute.bind(null, true));
break;

case 'resolve': // Add a confirmation for resolving
bootbox.confirm('[[topic:thread-tools.resolve-confirm]]', execute);
case 'resolve':
threadTools.requestResolveExpiry(body, execute.bind(null, true));
break;

default:
Expand All @@ -191,6 +193,8 @@ define('forum/category/tools', [
socket.removeListener('event:topic_unlocked', setLockedState);
socket.removeListener('event:topic_pinned', setPinnedState);
socket.removeListener('event:topic_unpinned', setPinnedState);
socket.removeListener('event:topic_resolved', setResolvedState);
socket.removeListener('event:topic_unresolved', setResolvedState);
socket.removeListener('event:topic_moved', onTopicMoved);
};

Expand Down Expand Up @@ -233,6 +237,9 @@ define('forum/category/tools', [
components.get('topic/pin').toggleClass('hidden', areAllScheduled || isAnyPinned);
components.get('topic/unpin').toggleClass('hidden', areAllScheduled || !isAnyPinned);

components.get('topic/mark-resolve').toggleClass('hidden', areAllScheduled || isAnyPinned);
// components.get('topic/mark-unread-for-all').toggleClass('hidden', areAllScheduled || !isAnyPinned);

components.get('topic/merge').toggleClass('hidden', isAnyScheduled);
}

Expand Down Expand Up @@ -287,6 +294,13 @@ define('forum/category/tools', [
ajaxify.refresh();
}

function setResolvedState(data) {
const topic = getTopicEl(data.tid);
topic.toggleClass('resolved', data.isResolved);
topic.find('[component="topic/resolved"]').toggleClass('hidden', !data.isResolved);
ajaxify.refresh();
}

function setLockedState(data) {
const topic = getTopicEl(data.tid);
topic.toggleClass('locked', data.isLocked);
Expand Down
2 changes: 2 additions & 0 deletions public/src/client/topic/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ define('forum/topic/events', [
'event:topic_pinned': threadTools.setPinnedState,
'event:topic_unpinned': threadTools.setPinnedState,

'event:topic_resolved': threadTools.setResolvedState,

'event:topic_moved': onTopicMoved,

'event:post_edited': onPostEdited,
Expand Down
55 changes: 54 additions & 1 deletion public/src/client/topic/threadTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@ define('forum/topic/threadTools', [
return false;
});

topicContainer.on('click', '[component="topic/mark-resolve"]', function () {
topicCommand('put', '/resolve', 'resolve');
return false;
});

topicContainer.on('click', '[component="topic/mark-unread"]', function () {
console.log('mark-unreadAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
topicCommand('del', '/read', undefined, () => {
if (app.previousUrl && !app.previousUrl.match('^/topic')) {
ajaxify.go(app.previousUrl, function () {
Expand Down Expand Up @@ -248,6 +252,10 @@ define('forum/topic/threadTools', [
ThreadTools.requestPinExpiry(body, execute.bind(null, true));
break;

case 'resolve':
ThreadTools.requestResolveExpiry(body, execute.bind(null, true));
break;

default:
execute(true);
break;
Expand Down Expand Up @@ -293,6 +301,39 @@ define('forum/topic/threadTools', [
});
};

ThreadTools.requestResolveExpiry = function (body, onSuccess) {
// Modify to set expiry as 'forever' (no expiry)
app.parseAndTranslate('modals/set-pin-expiry', {}, function (html) {
const modal = bootbox.dialog({
title: '[[topic:thread-tools.resolve]]',
message: html,
onEscape: true,
onShown: function () {
// Leave the expiry date and time empty to default to 'forever'
const expiryDateEl = modal.get(0).querySelector('#expiry-date');
const expiryTimeEl = modal.get(0).querySelector('#expiry-time');
if (expiryDateEl) expiryDateEl.value = ''; // No expiry date
if (expiryTimeEl) expiryTimeEl.value = ''; // No expiry time
},
buttons: {
cancel: {
label: '[[modules:bootbox.cancel]]',
className: 'btn-link',
},
save: {
label: 'Yes, Mark As Resolved',
className: 'btn-primary',
callback: function () {
// Automatically set expiry to 'forever' by skipping any expiry date/time
body.expiry = null; // No expiry, set as forever
onSuccess(); // Proceed with resolving without expiry
},
},
},
});
});
};

ThreadTools.setLockedState = function (data) {
const threadEl = components.get('topic');
if (parseInt(data.tid, 10) !== parseInt(threadEl.attr('data-tid'), 10)) {
Expand Down Expand Up @@ -377,6 +418,18 @@ define('forum/topic/threadTools', [
posts.addTopicEvents(data.events);
};

ThreadTools.setResolvedState = function (data) {
const threadEl = components.get('topic');
if (parseInt(data.tid, 10) !== parseInt(threadEl.attr('data-tid'), 10)) {
return;
}

components.get('topic/resolve').toggleClass('hidden', data.resolved).parent().attr('hidden', data.resolved ? '' : null);
ajaxify.data.resolved = data.resolved;

posts.addTopicEvents(data.events);
};

function setFollowState(state) {
const titles = {
follow: '[[topic:watching]]',
Expand Down
23 changes: 23 additions & 0 deletions src/api/topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ topicsAPI.create = async function (caller, data) {

const payload = { ...data };
payload.tags = payload.tags || [];
// payload.resolve = 0;
apiHelpers.setDefaultPostData(caller, payload);
const isScheduling = parseInt(data.timestamp, 10) > payload.timestamp;
if (isScheduling) {
Expand Down Expand Up @@ -149,6 +150,14 @@ topicsAPI.unpin = async function (caller, data) {
});
};

topicsAPI.resolve = async function (caller, { tids, expiry }) {
await doTopicAction('resolve', 'event:topic_resolved', caller, { tids });

if (expiry) {
await Promise.all(tids.map(async tid => topics.tools.setPinExpiry(tid, expiry, caller.uid)));
}
};

topicsAPI.lock = async function (caller, data) {
await doTopicAction('lock', 'event:topic_locked', caller, {
tids: data.tids,
Expand All @@ -161,6 +170,20 @@ topicsAPI.unlock = async function (caller, data) {
});
};

// topics.resolve = async function (req, { tids }) {
// await Promise.all(tids.map(async (tid) => {
// await topics.setTopicField(tid, 'resolved', 1); // Set resolved to 1
// await events.log({ type: 'topic_resolved', uid: req.uid, tid });
// }));
// };

// topics.unresolve = async function (req, { tids }) {
// await Promise.all(tids.map(async (tid) => {
// await topics.setTopicField(tid, 'resolved', 0); // Set resolved to 0
// await events.log({ type: 'topic_unresolved', uid: req.uid, tid });
// }));
// };

topicsAPI.follow = async function (caller, data) {
await topics.follow(data.tid, caller.uid);
};
Expand Down
5 changes: 5 additions & 0 deletions src/controllers/write/topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ Topics.unpin = async (req, res) => {
helpers.formatApiResponse(200, res);
};

Topics.resolve = async (req, res) => {
await api.topics.resolve(req, { tids: [req.params.tid] });
helpers.formatApiResponse(200, res);
};

Topics.lock = async (req, res) => {
await api.topics.lock(req, { tids: [req.params.tid] });
helpers.formatApiResponse(200, res);
Expand Down
2 changes: 2 additions & 0 deletions src/routes/write/topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ module.exports = function () {
setupApiRoute(router, 'put', '/:tid/pin', [...middlewares, middleware.assert.topic], controllers.write.topics.pin);
setupApiRoute(router, 'delete', '/:tid/pin', [...middlewares], controllers.write.topics.unpin);

setupApiRoute(router, 'put', '/:tid/resolve', [...middlewares, middleware.assert.topic], controllers.write.topics.resolve);

setupApiRoute(router, 'put', '/:tid/lock', [...middlewares], controllers.write.topics.lock);
setupApiRoute(router, 'delete', '/:tid/lock', [...middlewares], controllers.write.topics.unlock);

Expand Down
43 changes: 43 additions & 0 deletions src/topics/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ module.exports = function (Topics) {
return topicData;
}

topicTools.resolve = async function (tid, uid) {
return await toggleResolve(tid, uid, true, true);
};

topicTools.pin = async function (tid, uid) {
return await togglePin(tid, uid, true);
};
Expand Down Expand Up @@ -149,6 +153,45 @@ module.exports = function (Topics) {
return tids.filter(Boolean);
};

async function toggleResolve(tid, uid, resolve, pin) {
const topicData = await Topics.getTopicData(tid);
if (!topicData) {
throw new Error('[[error:no-topic]]');
}

Topics.setTopicField(tid, 'resolved', resolve ? 1 : 0);
const promises = [
Topics.setTopicField(tid, 'pinned', pin ? 1 : 0),
Topics.setTopicField(tid, 'resolved', resolve ? 1 : 0),
// Topics.events.log(tid, { type: pin ? 'pin' : 'unpin', uid }),
// Topics.events.log(tid, { type: resolve ? 'resolve' : 'unresolve', uid }),
];
if (resolve) {
// promises.push(db.sortedSetAdd(`cid:${topicData.cid}:tids:pinned`, Date.now(), tid));
promises.push(db.sortedSetAdd(`cid:${topicData.cid}:tids:resolved`, Date.now(), tid));
promises.push(db.sortedSetsRemove([
`cid:${topicData.cid}:tids`,
`cid:${topicData.cid}:tids:create`,
`cid:${topicData.cid}:tids:posts`,
`cid:${topicData.cid}:tids:votes`,
`cid:${topicData.cid}:tids:views`,
], tid));
}

const results = await Promise.all(promises);

topicData.isPinned = pin; // deprecate in v2.0
topicData.isResolved = resolve;
topicData.pinned = pin;
topicData.resolved = resolve;
topicData.events = results[1];

const updatedTopicData = await Topics.getTopicData(tid);
console.log('Updated topic data:', updatedTopicData);

return topicData;
}

async function togglePin(tid, uid, pin) {
const topicData = await Topics.getTopicData(tid);
if (!topicData) {
Expand Down
5 changes: 4 additions & 1 deletion test/socket.io.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
// see https://gist.github.com/jfromaniello/4087861#gistcomment-1447029


process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
if (process.env.NODE_ENV === 'development') {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // Only for local development
}

const util = require('util');

Expand Down
Loading

0 comments on commit a4b0c50

Please sign in to comment.