nodebb-plugin-moving-topics 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/languages/en-GB/moving-topics.json +6 -0
- package/languages/he/moving-topics.json +6 -0
- package/library.js +26 -2
- package/package.json +1 -1
- package/plugin.json +6 -1
- package/static/lib/admin.js +50 -0
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Allow topic owners to move their own topics between categories, without granting
|
|
|
9
9
|
- Moves are blocked for **locked** or **deleted** topics.
|
|
10
10
|
- Target categories are filtered by `topics:create` + `topics:read`.
|
|
11
11
|
- Admins/moderators retain existing move permissions.
|
|
12
|
+
- Optional limit by number of posts in the topic (default: 5).
|
|
12
13
|
|
|
13
14
|
## Requirements
|
|
14
15
|
|
|
@@ -39,7 +40,11 @@ Then rebuild and restart:
|
|
|
39
40
|
|
|
40
41
|
## Configuration
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
Admin control panel: `/admin/settings/post`
|
|
44
|
+
|
|
45
|
+
- **Maximum posts to allow owner moves** (`movingTopicsMaxPosts`)
|
|
46
|
+
- Default: `5`
|
|
47
|
+
- Set to `0` for no limit
|
|
43
48
|
|
|
44
49
|
## Usage
|
|
45
50
|
|
package/library.js
CHANGED
|
@@ -9,6 +9,14 @@ function getCore(path) {
|
|
|
9
9
|
return require.main.require(path);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function getMaxMovablePosts(meta) {
|
|
13
|
+
const value = parseInt(meta.config.movingTopicsMaxPosts, 10);
|
|
14
|
+
if (Number.isNaN(value)) {
|
|
15
|
+
return 5;
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
plugin.init = async function () {
|
|
13
21
|
if (patchedMove) {
|
|
14
22
|
return;
|
|
@@ -25,6 +33,7 @@ plugin.init = async function () {
|
|
|
25
33
|
const activitypubApi = getCore('./src/api/activitypub');
|
|
26
34
|
const activitypub = getCore('./src/activitypub');
|
|
27
35
|
const user = getCore('./src/user');
|
|
36
|
+
const meta = getCore('./src/meta');
|
|
28
37
|
|
|
29
38
|
originalMove = topicsApi.move;
|
|
30
39
|
|
|
@@ -48,6 +57,7 @@ plugin.init = async function () {
|
|
|
48
57
|
|
|
49
58
|
const uids = await user.getUidsFromSet('users:online', 0, -1);
|
|
50
59
|
const cids = [targetCid];
|
|
60
|
+
const maxPosts = getMaxMovablePosts(meta);
|
|
51
61
|
|
|
52
62
|
await batch.processArray(tids, async (batchTids) => {
|
|
53
63
|
await Promise.all(batchTids.map(async (tid) => {
|
|
@@ -59,6 +69,7 @@ plugin.init = async function () {
|
|
|
59
69
|
'slug',
|
|
60
70
|
'deleted',
|
|
61
71
|
'locked',
|
|
72
|
+
'postcount',
|
|
62
73
|
]);
|
|
63
74
|
|
|
64
75
|
if (!topicData) {
|
|
@@ -66,6 +77,10 @@ plugin.init = async function () {
|
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
const isOwner = parseInt(topicData.uid, 10) === parseInt(caller.uid, 10);
|
|
80
|
+
const exceedsMax = maxPosts > 0 && topicData.postcount > maxPosts;
|
|
81
|
+
if (exceedsMax) {
|
|
82
|
+
throw new Error(`[[moving-topics:error.max-posts, ${maxPosts}]]`);
|
|
83
|
+
}
|
|
69
84
|
if (!isOwner || topicData.locked || topicData.deleted) {
|
|
70
85
|
throw new Error('[[error:no-privileges]]');
|
|
71
86
|
}
|
|
@@ -106,13 +121,22 @@ plugin.init = async function () {
|
|
|
106
121
|
|
|
107
122
|
plugin.filterTopicPrivileges = async function (data) {
|
|
108
123
|
const topics = getCore('./src/topics');
|
|
109
|
-
const
|
|
124
|
+
const meta = getCore('./src/meta');
|
|
125
|
+
const topicData = await topics.getTopicFields(data.tid, ['uid', 'locked', 'deleted', 'postcount']);
|
|
110
126
|
if (!topicData) {
|
|
111
127
|
return data;
|
|
112
128
|
}
|
|
113
129
|
|
|
130
|
+
const maxPosts = getMaxMovablePosts(meta);
|
|
131
|
+
const exceedsMax = maxPosts > 0 && topicData.postcount > maxPosts;
|
|
114
132
|
const isOwner = parseInt(topicData.uid, 10) === parseInt(data.uid, 10);
|
|
115
|
-
data.canMoveOwnTopic = !!(
|
|
133
|
+
data.canMoveOwnTopic = !!(
|
|
134
|
+
isOwner &&
|
|
135
|
+
!data.isAdminOrMod &&
|
|
136
|
+
!topicData.locked &&
|
|
137
|
+
!topicData.deleted &&
|
|
138
|
+
!exceedsMax
|
|
139
|
+
);
|
|
116
140
|
|
|
117
141
|
if (data.canMoveOwnTopic && !data.view_thread_tools) {
|
|
118
142
|
data.view_thread_tools = true;
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
{ "hook": "static:app.load", "method": "init" },
|
|
9
9
|
{ "hook": "filter:privileges.topics.get", "method": "filterTopicPrivileges" }
|
|
10
10
|
],
|
|
11
|
+
"acpScripts": [
|
|
12
|
+
"static/lib/admin.js"
|
|
13
|
+
],
|
|
11
14
|
"scripts": [
|
|
12
15
|
"static/lib/client.js"
|
|
13
|
-
]
|
|
16
|
+
],
|
|
17
|
+
"languages": "languages",
|
|
18
|
+
"defaultLang": "en-GB"
|
|
14
19
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* global ajaxify, app */
|
|
4
|
+
|
|
5
|
+
let inserted = false;
|
|
6
|
+
|
|
7
|
+
$(window).on('action:app.load', function () {
|
|
8
|
+
require(['hooks', 'translator', 'admin/settings'], function (hooks, translator, Settings) {
|
|
9
|
+
hooks.on('action:ajaxify.end', function () {
|
|
10
|
+
if (!ajaxify.data || !ajaxify.data.template || !ajaxify.data.template['admin/settings/post']) {
|
|
11
|
+
inserted = false;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const container = $('#spy-container');
|
|
16
|
+
if (!container.length) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (inserted) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sectionHtml = [
|
|
25
|
+
'<hr/>',
|
|
26
|
+
'<div id="moving-topics-settings" class="mb-4">',
|
|
27
|
+
'<h5 class="fw-bold tracking-tight settings-header">[[moving-topics:admin.settings.title]]</h5>',
|
|
28
|
+
'<div class="mb-3">',
|
|
29
|
+
'<label class="form-label" for="movingTopicsMaxPosts">[[moving-topics:admin.settings.max-posts]]</label>',
|
|
30
|
+
'<input id="movingTopicsMaxPosts" type="number" min="0" class="form-control" data-field="movingTopicsMaxPosts" placeholder="5">',
|
|
31
|
+
'<p class="form-text">[[moving-topics:admin.settings.max-posts-help]]</p>',
|
|
32
|
+
'</div>',
|
|
33
|
+
'</div>',
|
|
34
|
+
].join('');
|
|
35
|
+
|
|
36
|
+
translator.translate(sectionHtml, function (translated) {
|
|
37
|
+
container.append(translated);
|
|
38
|
+
inserted = true;
|
|
39
|
+
|
|
40
|
+
if (!app.config.hasOwnProperty('movingTopicsMaxPosts')) {
|
|
41
|
+
$('#movingTopicsMaxPosts').val(5);
|
|
42
|
+
} else {
|
|
43
|
+
$('#movingTopicsMaxPosts').val(app.config.movingTopicsMaxPosts);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Settings.prepare();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|