Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Coding style tweaks. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | forumpost-locking |
| Files: | files | file ages | folders |
| SHA3-256: |
9fc70f6f63ff5eaddbc0b5e515d07782 |
| User & Date: | stephan 2023-02-21 08:47:16.977 |
Context
|
2023-02-21
| ||
| 09:52 | Add db_add_unsent() and replace numerous "INSERT OR IGNORE INTO unset" statements with that. ... (check-in: 98d4ee73d7 user: stephan tags: forumpost-locking) | |
| 08:47 | Coding style tweaks. ... (check-in: 9fc70f6f63 user: stephan tags: forumpost-locking) | |
| 03:49 | Closed forum threads can no longer be edited by non-admins. Fix broken ability of non-builtin users to delete their own pending-moderation post. UI controls for closing/reing-open threads are still TODO. ... (check-in: 8f02c1d4a8 user: stephan tags: forumpost-locking) | |
Changes
Changes to src/default.css.
| ︙ | ︙ | |||
898 899 900 901 902 903 904 |
padding-left: 1ex;
padding-right: 1ex;
margin-top: 1ex;
display: flex;
flex-direction: column;
}
div.forumClosed {
| < | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
padding-left: 1ex;
padding-right: 1ex;
margin-top: 1ex;
display: flex;
flex-direction: column;
}
div.forumClosed {
opacity: 0.7;
}
div.forumClosed > *:first-child::before {
content: "[CLOSED] ";
color: red;
opacity: 0.7;
}
|
| ︙ | ︙ |
Changes to src/forum.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 | ForumPost *pEditNext; /* This post is edited by pEditNext */ ForumPost *pEditPrev; /* This post is an edit of pEditPrev */ ForumPost *pNext; /* Next in chronological order */ ForumPost *pPrev; /* Previous in chronological order */ ForumPost *pDisplay; /* Next in display order */ int nEdit; /* Number of edits to this post */ int nIndent; /* Number of levels of indentation for this post */ | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
ForumPost *pEditNext; /* This post is edited by pEditNext */
ForumPost *pEditPrev; /* This post is an edit of pEditPrev */
ForumPost *pNext; /* Next in chronological order */
ForumPost *pPrev; /* Previous in chronological order */
ForumPost *pDisplay; /* Next in display order */
int nEdit; /* Number of edits to this post */
int nIndent; /* Number of levels of indentation for this post */
int iClosed; /* See forum_rid_is_closed() */
};
/*
** A single instance of the following tracks all entries for a thread.
*/
struct ForumThread {
ForumPost *pFirst; /* First post in chronological order */
|
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
**
** If bCheckParents is true then p's thread parents are checked
** (recursively) for closure, else only p is checked.
*/
int forum_post_is_closed(ForumPost *p, int bCheckParents){
if( !p ) return 0;
if( p->pEditTail ) p = p->pEditTail;
| | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
**
** If bCheckParents is true then p's thread parents are checked
** (recursively) for closure, else only p is checked.
*/
int forum_post_is_closed(ForumPost *p, int bCheckParents){
if( !p ) return 0;
if( p->pEditTail ) p = p->pEditTail;
if( p->iClosed || !bCheckParents ) return p->iClosed;
else if( p->pIrt ){
return forum_post_is_closed(p->pIrt->pEditTail
? p->pIrt->pEditTail : p->pIrt,
bCheckParents);
}
return 0;
}
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 |
if( rid ){
rc = forum_rid_is_closed(rid, 1);
}
return rc>0 ? -rc : rc;
}
/*
| | | | | | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
if( rid ){
rc = forum_rid_is_closed(rid, 1);
}
return rc>0 ? -rc : rc;
}
/*
** If iClosed is true and the current user has admin privileges, this
** renders either a checkbox to unlock forum post fpid (if iClosed>0)
** or a SPAN.warning element that the given post inherits the CLOSED
** status from a parent post (if iClosed<0). If neither of the initial
** conditions is true, this is a no-op.
*/
static void forumpost_emit_unlock_checkbox(int iClosed, int fpid){
if( iClosed && g.perm.Admin ){
if( iClosed>0 ){
/* Only show the "unlock" checkbox on a post which is actually
** closed, not on a post which inherits that state. */
@ <label class='warning'><input type="checkbox" name="reopen" value="1">
@ Re-open this CLOSED post? (NOT YET IMPLEMENTED)</label>
}else{
@ <span class='warning'>This post is CLOSED via a parent post</span>
}
|
| ︙ | ︙ | |||
306 307 308 309 310 311 312 |
pPost->pEditPrev = p;
pPost->pEditHead = p->pEditHead ? p->pEditHead : p;
for(; p; p=p->pEditPrev ){
p->nEdit = pPost->nEdit;
p->pEditTail = pPost;
}
}
| | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
pPost->pEditPrev = p;
pPost->pEditHead = p->pEditHead ? p->pEditHead : p;
for(; p; p=p->pEditPrev ){
p->nEdit = pPost->nEdit;
p->pEditTail = pPost;
}
}
pPost->iClosed = forum_rid_is_closed(pPost->fpid, 1);
}
db_finalize(&q);
if( computeHierarchy ){
/* Compute the hierarchical display order */
pPost = pThread->pFirst;
pPost->nIndent = 1;
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 |
fossil_print(
/* 0 1 2 3 4 5 6 7 */
/* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
" sid rev closed fpid pIrt pEditPrev pEditTail hash\n");
for(p=pThread->pFirst; p; p=p->pNext){
fossil_print("%4d %4d %7d %9d %9d %9d %9d %8.8s\n",
p->sid, p->rev,
| | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
fossil_print(
/* 0 1 2 3 4 5 6 7 */
/* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
" sid rev closed fpid pIrt pEditPrev pEditTail hash\n");
for(p=pThread->pFirst; p; p=p->pNext){
fossil_print("%4d %4d %7d %9d %9d %9d %9d %8.8s\n",
p->sid, p->rev,
p->iClosed,
p->fpid, p->pIrt ? p->pIrt->fpid : 0,
p->pEditPrev ? p->pEditPrev->fpid : 0,
p->pEditTail ? p->pEditTail->fpid : 0, p->zUuid);
}
fossil_print("\nDisplay\n");
for(p=pThread->pDisplay; p; p=p->pDisplay){
fossil_print("%*s", (p->nIndent-1)*3, "");
|
| ︙ | ︙ | |||
552 553 554 555 556 557 558 | char *zEditorName; /* Name of user who provided the current edit */ char *zDate; /* The time/date string */ char *zHist; /* History query string */ Manifest *pManifest; /* Manifest comprising the current post */ int bPrivate; /* True for posts awaiting moderation */ int bSameUser; /* True if author is also the reader */ int iIndent; /* Indent level */ | | | | | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 |
char *zEditorName; /* Name of user who provided the current edit */
char *zDate; /* The time/date string */
char *zHist; /* History query string */
Manifest *pManifest; /* Manifest comprising the current post */
int bPrivate; /* True for posts awaiting moderation */
int bSameUser; /* True if author is also the reader */
int iIndent; /* Indent level */
int iClosed; /* True if (sub)thread is closed */
const char *zMimetype;/* Formatting MIME type */
/* Get the manifest for the post. Abort if not found (e.g. shunned). */
pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
if( !pManifest ) return;
iClosed = forum_post_is_closed(p, 1);
/* When not in raw mode, create the border around the post. */
if( !bRaw ){
/* Open the <div> enclosing the post. Set the class string to mark the post
** as selected and/or obsolete. */
iIndent = (p->pEditHead ? p->pEditHead->nIndent : p->nIndent)-1;
@ <div id='forum%d(p->fpid)' class='forumTime\
@ %s(bSelect ? " forumSel" : "")\
@ %s(iClosed ? " forumClosed" : "")\
@ %s(p->pEditTail ? " forumObs" : "")' \
if( iIndent && iIndentScale ){
@ style='margin-left:%d(iIndent*iIndentScale)ex;'>
}else{
@ >
}
|
| ︙ | ︙ | |||
681 682 683 684 685 686 687 |
@ <div><form action="%R/forumedit" method="POST">
@ <input type="hidden" name="fpid" value="%s(p->zUuid)">
if( !bPrivate ){
/* Reply and Edit are only available if the post has been
** approved. Closed threads can only be edited or replied to
** by an admin but a user may delete their own posts even if
** they are closed. */
| | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 |
@ <div><form action="%R/forumedit" method="POST">
@ <input type="hidden" name="fpid" value="%s(p->zUuid)">
if( !bPrivate ){
/* Reply and Edit are only available if the post has been
** approved. Closed threads can only be edited or replied to
** by an admin but a user may delete their own posts even if
** they are closed. */
if( g.perm.Admin || !iClosed ){
@ <input type="submit" name="reply" value="Reply">
if( g.perm.Admin || (bSameUser && !iClosed) ){
@ <input type="submit" name="edit" value="Edit">
}
if( g.perm.Admin || bSameUser ){
@ <input type="submit" name="nullout" value="Delete">
}
}
}else if( g.perm.ModForum ){
|
| ︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 |
const char *zMimetype = 0;
const char *zContent = 0;
const char *zTitle = 0;
char *zDate = 0;
const char *zFpid = PD("fpid","");
int isCsrfSafe;
int isDelete = 0;
| | | 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 |
const char *zMimetype = 0;
const char *zContent = 0;
const char *zTitle = 0;
char *zDate = 0;
const char *zFpid = PD("fpid","");
int isCsrfSafe;
int isDelete = 0;
int iClosed = 0;
int bSameUser; /* True if author is also the reader */
int bPreview; /* True in preview mode. */
int bPrivate; /* True if post is private (not yet moderated) */
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
|
| ︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 |
webpage_error("fpid does not appear to be a forum post: \"%d\"", fpid);
}
if( P("cancel") ){
cgi_redirectf("%R/forumpost/%S",P("fpid"));
return;
}
bPreview = P("preview")!=0;
| | | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 |
webpage_error("fpid does not appear to be a forum post: \"%d\"", fpid);
}
if( P("cancel") ){
cgi_redirectf("%R/forumpost/%S",P("fpid"));
return;
}
bPreview = P("preview")!=0;
iClosed = forum_rid_is_closed(fpid, froot!=fpid);
isCsrfSafe = cgi_csrf_safe(1);
bPrivate = content_is_private(fpid);
bSameUser = login_is_individual()
&& fossil_strcmp(pPost->zUser, g.zLogin)==0;
if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
if( g.perm.ModForum && P("approve") ){
const char *zUserToTrust;
|
| ︙ | ︙ | |||
1434 1435 1436 1437 1438 1439 1440 |
@ <h2>Preview of Edited Post:</h2>
forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
}
@ <h2>Revised Message:</h2>
@ <form action="%R/forume2" method="POST">
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="edit" value="1">
| | | 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 |
@ <h2>Preview of Edited Post:</h2>
forum_render(zTitle, zMimetype, zContent,"forumEdit", 1);
}
@ <h2>Revised Message:</h2>
@ <form action="%R/forume2" method="POST">
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="edit" value="1">
if( iClosed ) forumpost_error_closed();
forum_from_line();
forum_post_widget(zTitle, zMimetype, zContent);
}else{
/* Reply */
char *zDisplayName;
zMimetype = PD("mimetype",DEFAULT_FORUM_MIMETYPE);
zContent = PDT("content","");
|
| ︙ | ︙ | |||
1464 1465 1466 1467 1468 1469 1470 |
@ <h2>Preview:</h2>
forum_render(0, zMimetype,zContent, "forumEdit", 1);
}
@ <h2>Enter Reply:</h2>
@ <form action="%R/forume2" method="POST">
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="reply" value="1">
| | | | | | 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 |
@ <h2>Preview:</h2>
forum_render(0, zMimetype,zContent, "forumEdit", 1);
}
@ <h2>Enter Reply:</h2>
@ <form action="%R/forume2" method="POST">
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
@ <input type="hidden" name="reply" value="1">
if( iClosed ) forumpost_error_closed();
forum_from_line();
forum_post_widget(0, zMimetype, zContent);
}
if( !isDelete ){
@ <input type="submit" name="preview" value="Preview">
}
@ <input type="submit" name="cancel" value="Cancel">
if( (bPreview && !whitespace_only(zContent)) || isDelete ){
if( !iClosed || g.perm.Admin ) {
@ <input type="submit" name="submit" value="Submit">
}
forumpost_emit_unlock_checkbox(iClosed, fpid);
}else if( !bPreview && iClosed ){
@ <span class='warning'>This post is CLOSED</span>
}
if( g.perm.Debug ){
/* For the test-forumnew page add these extra debugging controls */
@ <div class="debug">
@ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
@ Dry run</label>
|
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
905 906 907 908 909 910 911 |
rid, tagId
);
}
/*
** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
| | | | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 |
rid, tagId
);
}
/*
** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
** of an active (non-cancelled) tag matching the given rid and tag
** name string, else returns 0. Note that this function does not
** distinguish between a non-existent tag and a cancelled tag.
*/
int rid_has_active_tag_name(int rid, const char *zTagName){
static Stmt q = empty_Stmt_m;
int rc;
assert( 0 != zTagName );
|
| ︙ | ︙ |