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

[WIP]: Feature - Tagging a question as "Resolved" #5 #15

Closed
wants to merge 8 commits into from
Binary file modified dump.rdb
Binary file not shown.
4 changes: 4 additions & 0 deletions public/src/client/topic.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ define('forum/topic', [

handleTopicSearch();

if (ajaxify.data.resolved) {
$('.topic-title').append(' <span class="badge badge-success">Resolved</span>');
}

hooks.fire('action:topic.loaded', ajaxify.data);
};

Expand Down
18 changes: 9 additions & 9 deletions src/controllers/topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,29 +411,29 @@ const db = require('../database');
topicsController.setResolved = async function (req, res) {
try {
const { tid } = req.params;
const { resolved } = req.body; // Expected payload: { "resolved": true } or { "resolved": false }
let { resolved } = req.body;

if (typeof resolved !== 'boolean') {
return res.status(400).json({ error: "Invalid request. 'resolved' must be a boolean." });
}

// Fetch the topic to ensure it exists
const topic = await topics.getTopicData(tid);
if (!topic) {
return res.status(404).json({ error: 'Topic not found' });
// Fetch topic tags
const topicTags = await topics.getTopicTags(tid);
if (topicTags.includes('resolved')) {
resolved = true; // Auto-set resolved if tag is present
}

// Ensure the user has permission to edit the topic
// Check user permissions
const canEdit = await privileges.topics.canEdit(tid, req.uid);
if (!canEdit) {
return res.status(403).json({ error: '[[error:no-privileges]]' });
}

// Update the `resolved` field in Redis as a boolean
await db.setObjectField(`topic:${tid}`, 'resolved', resolved);
// Update the resolved status in the database
await db.setObjectField(`topic:${tid}`, 'resolved', resolved.toString());

res.json({ message: 'Topic resolved status updated', tid, resolved });
} catch (error) {
res.status(500).json({ error: error.message });
}
};

9 changes: 9 additions & 0 deletions src/topics/tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,15 @@ module.exports = function (Topics) {

tags = await Topics.filterTags(tags, cid);
await Topics.addTags(tags, [tid]);

// Auto-update resolved status if the "resolved" tag is present
if (tags.includes('resolved')) {
await db.setObjectField(`topic:${tid}`, 'resolved', 'true');
}
if (!tags.includes('resolved')) {
await db.setObjectField(`topic:${tid}`, 'resolved', 'false');
}

plugins.hooks.fire('action:topic.updateTags', { tags, tid });
};

Expand Down
3 changes: 2 additions & 1 deletion test/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ describe('Plugins', () => {

it('should install a plugin', function (done) {
this.timeout(0);
plugins.toggleInstall(pluginName, '1.0.16', (err, pluginData) => {
// Before it was 1.0.16
plugins.toggleInstall(pluginName, '4.1.0', (err, pluginData) => {
assert.ifError(err);
latest = pluginData.latest;

Expand Down
48 changes: 38 additions & 10 deletions test/topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -2522,8 +2522,6 @@ describe('Topics\'', async () => {
});




// Unit Tests Marking Question Resolved/Unresolved
const topicsController = require('../src/controllers/topics');

Expand All @@ -2541,6 +2539,7 @@ describe('topicsController.setResolved - Unit Test', () => {
const adminLogin = await helpers.loginUser('admin', '123456');
adminJar = adminLogin.jar;
csrf_token = adminLogin.csrf_token;

// Create a test topic in the database using the actual API function
const categoryObj = await categories.create({
name: 'Resolved Topics Test',
Expand All @@ -2550,15 +2549,26 @@ describe('topicsController.setResolved - Unit Test', () => {
uid: adminUid,
title: 'Test Topic',
content: 'This is a test topic.',
cid: categoryObj.cid, // Assuming category ID 1 exists in test DB
cid: categoryObj.cid,
});
testTid = topic.topicData.tid; // Get the actual created topic ID
testTid = topic.topicData.tid;

req = { params: { tid: testTid }, body: {}, uid: 1 };
res = {
data: null,
statusCode: null,
json: function (data) { this.data = data; return this; },
status: function (code) { this.statusCode = code; return this; },
statusHistory: [],
jsonHistory: [],
json: function (data) {
this.data = data;
this.jsonHistory.push(data);
return this;
},
status: function (code) {
this.statusCode = code;
this.statusHistory.push(code);
return this;
},
};
});

Expand Down Expand Up @@ -2592,21 +2602,39 @@ describe('topicsController.setResolved - Unit Test', () => {
it('should return 400 if "resolved" field is missing', async () => {
await topicsController.setResolved(req, res);

assert.strictEqual(res.statusCode, 400);
assert.deepStrictEqual(res.data, { error: "Invalid request. 'resolved' must be a boolean." });
assert.strictEqual(res.statusHistory[0], 400);
assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." });
});

it('should return 400 if "resolved" field is not a boolean', async () => {
req.body.resolved = 'invalid'; // Invalid type
await topicsController.setResolved(req, res);

assert.strictEqual(res.statusCode, 400);
assert.deepStrictEqual(res.data, { error: "Invalid request. 'resolved' must be a boolean." });
assert.strictEqual(res.statusHistory[0], 400);
assert.deepStrictEqual(res.jsonHistory[0], { error: "Invalid request. 'resolved' must be a boolean." });
});

it('should update the database with the correct resolved status', async () => {
req.body.resolved = true;
await topicsController.setResolved(req, res);

const resolvedStatus = await topics.getTopicField(req.params.tid, 'resolved');
assert.strictEqual(resolvedStatus, true); // Ensure value is stored as string
});

it('should not update the resolved status if the topic does not exist', async () => {
req.params.tid = 999999; // Non-existent topic
req.body.resolved = true;
await topicsController.setResolved(req, res);

assert.strictEqual(res.statusHistory[0], 404);
assert.deepStrictEqual(res.jsonHistory[0], { error: 'Topic not found' });
});
});




// Integration Tests Marking Question Resolved/Unresolved
describe('Marking Topics as Resolved', () => {
let testTid;
Expand Down
Loading