Fossil SCM

Add the forum-close-policy boolean config setting. If true, forum moderators may close/re-open forum posts, as well as reply to closed posts.

stephan 2023-06-06 19:38 forumpost-locking
Commit 162fc1e6aa1c6f3c54c5c39769b0af0d39f9cc617903f1169f9e42eaaad35dcf
2 files changed +7 +56 -16
+7
--- src/db.c
+++ src/db.c
@@ -4650,10 +4650,17 @@
46504650
** to obtain a check-in lock during auto-sync, the server will
46514651
** send the "pragma avoid-delta-manifests" statement in its reply,
46524652
** which will cause the client to avoid generating a delta
46534653
** manifest.
46544654
*/
4655
+/*
4656
+** SETTING: forum-close-policy boolean default=off
4657
+** If true, forum moderators may close forum posts, else only
4658
+** administrators may do so. Note that this only affects the forum web
4659
+** UI, not post-closing tags which arrive via the command-line or from
4660
+** synchronization with a remote.
4661
+*/
46554662
/*
46564663
** SETTING: gdiff-command width=40 default=gdiff sensitive
46574664
** The value is an external command to run when performing a graphical
46584665
** diff. If undefined, text diff will be used.
46594666
*/
46604667
--- src/db.c
+++ src/db.c
@@ -4650,10 +4650,17 @@
4650 ** to obtain a check-in lock during auto-sync, the server will
4651 ** send the "pragma avoid-delta-manifests" statement in its reply,
4652 ** which will cause the client to avoid generating a delta
4653 ** manifest.
4654 */
 
 
 
 
 
 
 
4655 /*
4656 ** SETTING: gdiff-command width=40 default=gdiff sensitive
4657 ** The value is an external command to run when performing a graphical
4658 ** diff. If undefined, text diff will be used.
4659 */
4660
--- src/db.c
+++ src/db.c
@@ -4650,10 +4650,17 @@
4650 ** to obtain a check-in lock during auto-sync, the server will
4651 ** send the "pragma avoid-delta-manifests" statement in its reply,
4652 ** which will cause the client to avoid generating a delta
4653 ** manifest.
4654 */
4655 /*
4656 ** SETTING: forum-close-policy boolean default=off
4657 ** If true, forum moderators may close forum posts, else only
4658 ** administrators may do so. Note that this only affects the forum web
4659 ** UI, not post-closing tags which arrive via the command-line or from
4660 ** synchronization with a remote.
4661 */
4662 /*
4663 ** SETTING: gdiff-command width=40 default=gdiff sensitive
4664 ** The value is an external command to run when performing a graphical
4665 ** diff. If undefined, text diff will be used.
4666 */
4667
+56 -16
--- src/forum.c
+++ src/forum.c
@@ -261,20 +261,56 @@
261261
db_end_transaction(0);
262262
return 1;
263263
}
264264
265265
/*
266
-** If iClosed is true and the current user has admin privileges, this
267
-** renders either a checkbox to unlock forum post fpid (if iClosed>0)
268
-** or a SPAN.warning element that the given post inherits the CLOSED
269
-** status from a parent post (if iClosed<0). If neither of the initial
270
-** conditions is true, this is a no-op.
266
+** Returns true if the forum-close-policy setting is true, else false,
267
+** caching the result for subsequent calls.
268
+*/
269
+static int forumpost_close_policy(void){
270
+ static int closePolicy = -99;
271
+
272
+ if( closePolicy==-99 ){
273
+ closePolicy = db_get_boolean("forum-close-policy",0)>0;
274
+ }
275
+ return closePolicy;
276
+}
277
+
278
+/*
279
+** Returns 1 if the current user is an admin, -1 if the current user
280
+** is a forum moderator and the forum-close-policy setting is true,
281
+** else returns 0. The value is cached for subsequent calls.
282
+*/
283
+static int forumpost_may_close(void){
284
+ static int permClose = -99;
285
+ if( permClose!=-99 ){
286
+ return permClose;
287
+ }else if( g.perm.Admin ){
288
+ return permClose = 1;
289
+ }else if( g.perm.ModForum ){
290
+ return permClose = forumpost_close_policy()>0 ? -1 : 0;
291
+ }else{
292
+ return permClose = 0;
293
+ }
294
+}
295
+
296
+/*
297
+** If iClosed is true and the current user forumpost-close privileges,
298
+** this renders either a checkbox to unlock forum post fpid (if
299
+** iClosed>0) or a SPAN.warning element that the given post inherits
300
+** the CLOSED status from a parent post (if iClosed<0). If neither of
301
+** the initial conditions is true, this is a no-op.
271302
*/
272303
static void forumpost_emit_closed_state(int fpid, int iClosed){
273
- const char *zCommon =
274
- "Only admins may edit or respond to closed posts.";
304
+ const char *zCommon;
275305
int iHead = forumpost_head_rid(fpid);
306
+ const int permClose = forumpost_may_close();
307
+
308
+ zCommon = forumpost_close_policy()==0
309
+ ? "Admins may close or re-open posts, or respond to closed posts."
310
+ : "Admins or moderators "
311
+ "may close or re-open posts, or respond to closed posts.";
276312
/*@ forumpost_emit_closed_state(%d(fpid), %d(iClosed))<br/>*/
277313
if( iHead != fpid ){
278314
iClosed = forum_rid_is_closed(iHead, 1);
279315
/*@ forumpost_emit_closed_state() %d(iHead), %d(iClosed)*/
280316
}
@@ -283,28 +319,32 @@
283319
@ This post is CLOSED via a parent post. %s(zCommon)\
284320
@ </div>
285321
return;
286322
}
287323
else if( iClosed==0 ){
288
- if( g.perm.Admin==0 ) return;
324
+ if( permClose==0 ) return;
289325
@ <div class="warning forumpost-closure-warning">
290326
@ <form method="post" action="%R/forumpost_close">
291327
@ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
292328
@ <input type="submit" value="CLOSE this post and its responses" />
293
- @ %s(zCommon)
329
+ @ <span>%s(zCommon)</span>
330
+ @ <span>This does NOT save any pending changes in
331
+ @ the editor!</span>
294332
@ </form></div>
295333
return;
296334
}
297335
assert( iClosed>0 );
298
- /* Only show the "unlock" checkbox on a post which is actually
336
+ /* Only show the "unlock" option on a post which is actually
299337
** closed, not on a post which inherits that state. */
300338
@ <div class="warning forumpost-closure-warning">\
301339
@ This post is CLOSED. %s(zCommon)
302
- if( g.perm.Admin ){
340
+ if( permClose ){
303341
@ <form method="post" action="%R/forumpost_reopen">
304342
@ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
305343
@ <input type="submit" value="Re-open this post and its responses" />
344
+ @ <span>This does NOT save any pending changes in
345
+ @ the editor!</span>
306346
@ </form>
307347
}
308348
@ </div>
309349
}
310350
@@ -884,13 +924,13 @@
884924
@ <form action="%R/forumedit" method="POST">
885925
@ <input type="hidden" name="fpid" value="%s(p->zUuid)">
886926
if( !bPrivate ){
887927
/* Reply and Edit are only available if the post has been
888928
** approved. Closed threads can only be edited or replied to
889
- ** by an admin but a user may delete their own posts even if
890
- ** they are closed. */
891
- if( g.perm.Admin || !iClosed ){
929
+ ** if forumpost_may_close() is true but a user may delete
930
+ ** their own posts even if they are closed. */
931
+ if( forumpost_may_close() || !iClosed ){
892932
@ <input type="submit" name="reply" value="Reply">
893933
if( g.perm.Admin || (bSameUser && !iClosed) ){
894934
@ <input type="submit" name="edit" value="Edit">
895935
}
896936
if( g.perm.Admin || bSameUser ){
@@ -913,11 +953,11 @@
913953
}else if( bSameUser ){
914954
/* Allow users to delete (reject) their own pending posts. */
915955
@ <input type="submit" name="reject" value="Delete">
916956
}
917957
@ </form>
918
- if( bSelect && g.perm.Admin && iClosed>=0 ){
958
+ if( bSelect && forumpost_may_close() && iClosed>=0 ){
919959
int iHead = forumpost_head_rid(p->fpid);
920960
@ <form method="post" \
921961
@ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
922962
@ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
923963
@ <input type="submit" value='%s(iClosed ? "Re-open" : "Close")' />
@@ -1430,11 +1470,11 @@
14301470
const char *zReason = 0;
14311471
int fClose;
14321472
int fpid;
14331473
14341474
login_check_credentials();
1435
- if( !g.perm.Admin ){
1475
+ if( forumpost_may_close()==0 ){
14361476
login_needed(g.anon.Admin);
14371477
return;
14381478
}
14391479
fpid = symbolic_name_to_rid(zFpid, "f");
14401480
if( fpid<=0 ){
14411481
--- src/forum.c
+++ src/forum.c
@@ -261,20 +261,56 @@
261 db_end_transaction(0);
262 return 1;
263 }
264
265 /*
266 ** If iClosed is true and the current user has admin privileges, this
267 ** renders either a checkbox to unlock forum post fpid (if iClosed>0)
268 ** or a SPAN.warning element that the given post inherits the CLOSED
269 ** status from a parent post (if iClosed<0). If neither of the initial
270 ** conditions is true, this is a no-op.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271 */
272 static void forumpost_emit_closed_state(int fpid, int iClosed){
273 const char *zCommon =
274 "Only admins may edit or respond to closed posts.";
275 int iHead = forumpost_head_rid(fpid);
 
 
 
 
 
 
276 /*@ forumpost_emit_closed_state(%d(fpid), %d(iClosed))<br/>*/
277 if( iHead != fpid ){
278 iClosed = forum_rid_is_closed(iHead, 1);
279 /*@ forumpost_emit_closed_state() %d(iHead), %d(iClosed)*/
280 }
@@ -283,28 +319,32 @@
283 @ This post is CLOSED via a parent post. %s(zCommon)\
284 @ </div>
285 return;
286 }
287 else if( iClosed==0 ){
288 if( g.perm.Admin==0 ) return;
289 @ <div class="warning forumpost-closure-warning">
290 @ <form method="post" action="%R/forumpost_close">
291 @ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
292 @ <input type="submit" value="CLOSE this post and its responses" />
293 @ %s(zCommon)
 
 
294 @ </form></div>
295 return;
296 }
297 assert( iClosed>0 );
298 /* Only show the "unlock" checkbox on a post which is actually
299 ** closed, not on a post which inherits that state. */
300 @ <div class="warning forumpost-closure-warning">\
301 @ This post is CLOSED. %s(zCommon)
302 if( g.perm.Admin ){
303 @ <form method="post" action="%R/forumpost_reopen">
304 @ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
305 @ <input type="submit" value="Re-open this post and its responses" />
 
 
306 @ </form>
307 }
308 @ </div>
309 }
310
@@ -884,13 +924,13 @@
884 @ <form action="%R/forumedit" method="POST">
885 @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
886 if( !bPrivate ){
887 /* Reply and Edit are only available if the post has been
888 ** approved. Closed threads can only be edited or replied to
889 ** by an admin but a user may delete their own posts even if
890 ** they are closed. */
891 if( g.perm.Admin || !iClosed ){
892 @ <input type="submit" name="reply" value="Reply">
893 if( g.perm.Admin || (bSameUser && !iClosed) ){
894 @ <input type="submit" name="edit" value="Edit">
895 }
896 if( g.perm.Admin || bSameUser ){
@@ -913,11 +953,11 @@
913 }else if( bSameUser ){
914 /* Allow users to delete (reject) their own pending posts. */
915 @ <input type="submit" name="reject" value="Delete">
916 }
917 @ </form>
918 if( bSelect && g.perm.Admin && iClosed>=0 ){
919 int iHead = forumpost_head_rid(p->fpid);
920 @ <form method="post" \
921 @ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
922 @ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
923 @ <input type="submit" value='%s(iClosed ? "Re-open" : "Close")' />
@@ -1430,11 +1470,11 @@
1430 const char *zReason = 0;
1431 int fClose;
1432 int fpid;
1433
1434 login_check_credentials();
1435 if( !g.perm.Admin ){
1436 login_needed(g.anon.Admin);
1437 return;
1438 }
1439 fpid = symbolic_name_to_rid(zFpid, "f");
1440 if( fpid<=0 ){
1441
--- src/forum.c
+++ src/forum.c
@@ -261,20 +261,56 @@
261 db_end_transaction(0);
262 return 1;
263 }
264
265 /*
266 ** Returns true if the forum-close-policy setting is true, else false,
267 ** caching the result for subsequent calls.
268 */
269 static int forumpost_close_policy(void){
270 static int closePolicy = -99;
271
272 if( closePolicy==-99 ){
273 closePolicy = db_get_boolean("forum-close-policy",0)>0;
274 }
275 return closePolicy;
276 }
277
278 /*
279 ** Returns 1 if the current user is an admin, -1 if the current user
280 ** is a forum moderator and the forum-close-policy setting is true,
281 ** else returns 0. The value is cached for subsequent calls.
282 */
283 static int forumpost_may_close(void){
284 static int permClose = -99;
285 if( permClose!=-99 ){
286 return permClose;
287 }else if( g.perm.Admin ){
288 return permClose = 1;
289 }else if( g.perm.ModForum ){
290 return permClose = forumpost_close_policy()>0 ? -1 : 0;
291 }else{
292 return permClose = 0;
293 }
294 }
295
296 /*
297 ** If iClosed is true and the current user forumpost-close privileges,
298 ** this renders either a checkbox to unlock forum post fpid (if
299 ** iClosed>0) or a SPAN.warning element that the given post inherits
300 ** the CLOSED status from a parent post (if iClosed<0). If neither of
301 ** the initial conditions is true, this is a no-op.
302 */
303 static void forumpost_emit_closed_state(int fpid, int iClosed){
304 const char *zCommon;
 
305 int iHead = forumpost_head_rid(fpid);
306 const int permClose = forumpost_may_close();
307
308 zCommon = forumpost_close_policy()==0
309 ? "Admins may close or re-open posts, or respond to closed posts."
310 : "Admins or moderators "
311 "may close or re-open posts, or respond to closed posts.";
312 /*@ forumpost_emit_closed_state(%d(fpid), %d(iClosed))<br/>*/
313 if( iHead != fpid ){
314 iClosed = forum_rid_is_closed(iHead, 1);
315 /*@ forumpost_emit_closed_state() %d(iHead), %d(iClosed)*/
316 }
@@ -283,28 +319,32 @@
319 @ This post is CLOSED via a parent post. %s(zCommon)\
320 @ </div>
321 return;
322 }
323 else if( iClosed==0 ){
324 if( permClose==0 ) return;
325 @ <div class="warning forumpost-closure-warning">
326 @ <form method="post" action="%R/forumpost_close">
327 @ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
328 @ <input type="submit" value="CLOSE this post and its responses" />
329 @ <span>%s(zCommon)</span>
330 @ <span>This does NOT save any pending changes in
331 @ the editor!</span>
332 @ </form></div>
333 return;
334 }
335 assert( iClosed>0 );
336 /* Only show the "unlock" option on a post which is actually
337 ** closed, not on a post which inherits that state. */
338 @ <div class="warning forumpost-closure-warning">\
339 @ This post is CLOSED. %s(zCommon)
340 if( permClose ){
341 @ <form method="post" action="%R/forumpost_reopen">
342 @ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
343 @ <input type="submit" value="Re-open this post and its responses" />
344 @ <span>This does NOT save any pending changes in
345 @ the editor!</span>
346 @ </form>
347 }
348 @ </div>
349 }
350
@@ -884,13 +924,13 @@
924 @ <form action="%R/forumedit" method="POST">
925 @ <input type="hidden" name="fpid" value="%s(p->zUuid)">
926 if( !bPrivate ){
927 /* Reply and Edit are only available if the post has been
928 ** approved. Closed threads can only be edited or replied to
929 ** if forumpost_may_close() is true but a user may delete
930 ** their own posts even if they are closed. */
931 if( forumpost_may_close() || !iClosed ){
932 @ <input type="submit" name="reply" value="Reply">
933 if( g.perm.Admin || (bSameUser && !iClosed) ){
934 @ <input type="submit" name="edit" value="Edit">
935 }
936 if( g.perm.Admin || bSameUser ){
@@ -913,11 +953,11 @@
953 }else if( bSameUser ){
954 /* Allow users to delete (reject) their own pending posts. */
955 @ <input type="submit" name="reject" value="Delete">
956 }
957 @ </form>
958 if( bSelect && forumpost_may_close() && iClosed>=0 ){
959 int iHead = forumpost_head_rid(p->fpid);
960 @ <form method="post" \
961 @ action='%R/forumpost_%s(iClosed > 0 ? "reopen" : "close")'>
962 @ <input type="hidden" name="fpid" value="%z(rid_to_uuid(iHead))" />
963 @ <input type="submit" value='%s(iClosed ? "Re-open" : "Close")' />
@@ -1430,11 +1470,11 @@
1470 const char *zReason = 0;
1471 int fClose;
1472 int fpid;
1473
1474 login_check_credentials();
1475 if( forumpost_may_close()==0 ){
1476 login_needed(g.anon.Admin);
1477 return;
1478 }
1479 fpid = symbolic_name_to_rid(zFpid, "f");
1480 if( fpid<=0 ){
1481

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button