Fossil SCM

Minor refactoring of forum post 'closed' tag lookup internals, moving towards extending it to support other tags, e.g. 'resolved'.

stephan 2026-05-22 12:35 UTC trunk
Commit 2d7e2cb24e2ebd7efb39d0e74e1595a4baa5f2d1d90a8a9f1dbeb0c2a7455d1a
2 files changed +18 -18 +2 -2
+18 -18
--- src/forum.c
+++ src/forum.c
@@ -47,11 +47,11 @@
4747
ForumPost *pNext; /* Next in chronological order */
4848
ForumPost *pPrev; /* Previous in chronological order */
4949
ForumPost *pDisplay; /* Next in display order */
5050
int nEdit; /* Number of edits to this post */
5151
int nIndent; /* Number of levels of indentation for this post */
52
- int iClosed; /* See forum_rid_is_closed() */
52
+ int iClosed; /* True if forum_rid_is_tagged("closed") */
5353
};
5454
5555
/*
5656
** A single instance of the following tracks all entries for a thread.
5757
*/
@@ -126,39 +126,39 @@
126126
return 0;
127127
}
128128
129129
/*
130130
** Given a forum post RID, this function returns true if that post has
131
-** (or inherits) an active "closed" tag. If bCheckIrt is true then
132
-** the post to which the given post responds is also checked
131
+** (or inherits) an active tag named zTagName. If bCheckIrt is true
132
+** then the post to which the given post responds is also checked
133133
** (recursively), else they are not. When checking in-response-to
134134
** posts, the first one which is closed ends the search.
135135
**
136
-** Note that this function checks _exactly_ the given rid, whereas
137
-** forum post closure/re-opening is always applied to the head of an
138
-** edit chain so that we get consistent implied locking behavior for
139
-** later versions and responses to arbitrary versions in the
140
-** chain. Even so, the "closed" tag is applied as a propagating tag
141
-** so will apply to all edits in a given chain.
136
+** This function checks _exactly_ the given rid, whereas forum post
137
+** closure/re-opening is always applied to the head of an edit chain
138
+** so that we get consistent implied locking behavior for later
139
+** versions and responses to arbitrary versions in the chain. Even so,
140
+** the "closed" tag is applied as a propagating tag so will apply to
141
+** all edits in a given chain.
142142
**
143143
** The return value is one of:
144144
**
145
-** - 0 if no "closed" tag is found.
145
+** - 0 if no matching tag is found.
146146
**
147147
** - The tagxref.rowid of the tagxref entry for the closure if rid is
148148
** the forum post to which the closure applies.
149149
**
150150
** - (-tagxref.rowid) if the given rid inherits a "closed" tag from an
151151
** IRT forum post.
152152
*/
153
-static int forum_rid_is_closed(int rid, int bCheckIrt){
153
+static int forum_rid_is_tagged(int rid, const char *zTagName, int bCheckIrt){
154154
static Stmt qIrt = empty_Stmt_m;
155155
int rc = 0, i = 0;
156156
/* TODO: this can probably be turned into a CTE by someone with
157157
** superior SQL-fu. */
158158
for( ; rid; i++ ){
159
- rc = rid_has_active_tag_name(rid, "closed");
159
+ rc = rid_has_active_tag_name(rid, zTagName);
160160
if( rc || !bCheckIrt ) break;
161161
else if( !qIrt.pStmt ) {
162162
db_static_prepare(&qIrt,
163163
"SELECT firt FROM forumpost "
164164
"WHERE fpid=$fpid ORDER BY fmtime DESC"
@@ -183,11 +183,11 @@
183183
** as noted below, with the given optional zReason string as the tag's
184184
** value. If doClose is false then any active "closed" tag on frid is
185185
** cancelled, except as noted below. zReason is ignored if doClose is
186186
** false or if zReason is NULL or starts with a NUL byte.
187187
**
188
-** This function only adds a "closed" tag if forum_rid_is_closed()
188
+** This function only adds a "closed" tag if forum_rid_is_tagged()
189189
** indicates that frid's head is not closed. If a parent post is
190190
** already closed, no tag is added. Similarly, it will only remove a
191191
** "closed" tag from a post which has its own "closed" tag, and will
192192
** not remove an inherited one from a parent post.
193193
**
@@ -224,11 +224,11 @@
224224
int trid; /* RID of new control artifact */
225225
char *zUuid; /* UUID of head version of post */
226226
227227
db_begin_transaction();
228228
frid = forumpost_head_rid(frid);
229
- iClosed = forum_rid_is_closed(frid, 1);
229
+ iClosed = forum_rid_is_tagged(frid, "closed", 1);
230230
if( (iClosed && doClose
231231
/* Already closed, noting that in the case of (iClosed<0), it's
232232
** actually a parent which is closed. */)
233233
|| (iClosed<=0 && !doClose
234234
/* This entry is not closed, but a parent post may be. */) ){
@@ -443,13 +443,13 @@
443443
for(; p; p=p->pEditPrev ){
444444
p->nEdit = pPost->nEdit;
445445
p->pEditTail = pPost;
446446
}
447447
}
448
- pPost->iClosed = forum_rid_is_closed(pPost->pEditHead
448
+ pPost->iClosed = forum_rid_is_tagged(pPost->pEditHead
449449
? pPost->pEditHead->fpid
450
- : pPost->fpid, 1);
450
+ : pPost->fpid, "closed", 1);
451451
}
452452
db_finalize(&q);
453453
454454
if( computeHierarchy ){
455455
/* Compute the hierarchical display order */
@@ -1332,11 +1332,11 @@
13321332
Manifest *pPost;
13331333
int nContent = zContent ? (int)strlen(zContent) : 0;
13341334
13351335
schema_forum();
13361336
if( !g.perm.Admin && (iEdit || iInReplyTo)
1337
- && forum_rid_is_closed(iEdit ? iEdit : iInReplyTo, 1) ){
1337
+ && forum_rid_is_tagged(iEdit ? iEdit : iInReplyTo, "closed", 1) ){
13381338
forumpost_error_closed();
13391339
return 0;
13401340
}
13411341
if( iEdit==0 && whitespace_only(zContent) ){
13421342
return 0;
@@ -1650,11 +1650,11 @@
16501650
cgi_redirectf("%R/forumpost/%S",zFpid);
16511651
return;
16521652
}
16531653
bPreview = P("preview")!=0;
16541654
bReply = P("reply")!=0;
1655
- iClosed = forum_rid_is_closed(fpid, 1);
1655
+ iClosed = forum_rid_is_tagged(fpid, "closed", 1);
16561656
isCsrfSafe = cgi_csrf_safe(2);
16571657
bPrivate = content_is_private(fpid);
16581658
bSameUser = login_is_individual()
16591659
&& fossil_strcmp(pPost->zUser, g.zLogin)==0;
16601660
if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
16611661
--- src/forum.c
+++ src/forum.c
@@ -47,11 +47,11 @@
47 ForumPost *pNext; /* Next in chronological order */
48 ForumPost *pPrev; /* Previous in chronological order */
49 ForumPost *pDisplay; /* Next in display order */
50 int nEdit; /* Number of edits to this post */
51 int nIndent; /* Number of levels of indentation for this post */
52 int iClosed; /* See forum_rid_is_closed() */
53 };
54
55 /*
56 ** A single instance of the following tracks all entries for a thread.
57 */
@@ -126,39 +126,39 @@
126 return 0;
127 }
128
129 /*
130 ** Given a forum post RID, this function returns true if that post has
131 ** (or inherits) an active "closed" tag. If bCheckIrt is true then
132 ** the post to which the given post responds is also checked
133 ** (recursively), else they are not. When checking in-response-to
134 ** posts, the first one which is closed ends the search.
135 **
136 ** Note that this function checks _exactly_ the given rid, whereas
137 ** forum post closure/re-opening is always applied to the head of an
138 ** edit chain so that we get consistent implied locking behavior for
139 ** later versions and responses to arbitrary versions in the
140 ** chain. Even so, the "closed" tag is applied as a propagating tag
141 ** so will apply to all edits in a given chain.
142 **
143 ** The return value is one of:
144 **
145 ** - 0 if no "closed" tag is found.
146 **
147 ** - The tagxref.rowid of the tagxref entry for the closure if rid is
148 ** the forum post to which the closure applies.
149 **
150 ** - (-tagxref.rowid) if the given rid inherits a "closed" tag from an
151 ** IRT forum post.
152 */
153 static int forum_rid_is_closed(int rid, int bCheckIrt){
154 static Stmt qIrt = empty_Stmt_m;
155 int rc = 0, i = 0;
156 /* TODO: this can probably be turned into a CTE by someone with
157 ** superior SQL-fu. */
158 for( ; rid; i++ ){
159 rc = rid_has_active_tag_name(rid, "closed");
160 if( rc || !bCheckIrt ) break;
161 else if( !qIrt.pStmt ) {
162 db_static_prepare(&qIrt,
163 "SELECT firt FROM forumpost "
164 "WHERE fpid=$fpid ORDER BY fmtime DESC"
@@ -183,11 +183,11 @@
183 ** as noted below, with the given optional zReason string as the tag's
184 ** value. If doClose is false then any active "closed" tag on frid is
185 ** cancelled, except as noted below. zReason is ignored if doClose is
186 ** false or if zReason is NULL or starts with a NUL byte.
187 **
188 ** This function only adds a "closed" tag if forum_rid_is_closed()
189 ** indicates that frid's head is not closed. If a parent post is
190 ** already closed, no tag is added. Similarly, it will only remove a
191 ** "closed" tag from a post which has its own "closed" tag, and will
192 ** not remove an inherited one from a parent post.
193 **
@@ -224,11 +224,11 @@
224 int trid; /* RID of new control artifact */
225 char *zUuid; /* UUID of head version of post */
226
227 db_begin_transaction();
228 frid = forumpost_head_rid(frid);
229 iClosed = forum_rid_is_closed(frid, 1);
230 if( (iClosed && doClose
231 /* Already closed, noting that in the case of (iClosed<0), it's
232 ** actually a parent which is closed. */)
233 || (iClosed<=0 && !doClose
234 /* This entry is not closed, but a parent post may be. */) ){
@@ -443,13 +443,13 @@
443 for(; p; p=p->pEditPrev ){
444 p->nEdit = pPost->nEdit;
445 p->pEditTail = pPost;
446 }
447 }
448 pPost->iClosed = forum_rid_is_closed(pPost->pEditHead
449 ? pPost->pEditHead->fpid
450 : pPost->fpid, 1);
451 }
452 db_finalize(&q);
453
454 if( computeHierarchy ){
455 /* Compute the hierarchical display order */
@@ -1332,11 +1332,11 @@
1332 Manifest *pPost;
1333 int nContent = zContent ? (int)strlen(zContent) : 0;
1334
1335 schema_forum();
1336 if( !g.perm.Admin && (iEdit || iInReplyTo)
1337 && forum_rid_is_closed(iEdit ? iEdit : iInReplyTo, 1) ){
1338 forumpost_error_closed();
1339 return 0;
1340 }
1341 if( iEdit==0 && whitespace_only(zContent) ){
1342 return 0;
@@ -1650,11 +1650,11 @@
1650 cgi_redirectf("%R/forumpost/%S",zFpid);
1651 return;
1652 }
1653 bPreview = P("preview")!=0;
1654 bReply = P("reply")!=0;
1655 iClosed = forum_rid_is_closed(fpid, 1);
1656 isCsrfSafe = cgi_csrf_safe(2);
1657 bPrivate = content_is_private(fpid);
1658 bSameUser = login_is_individual()
1659 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
1660 if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
1661
--- src/forum.c
+++ src/forum.c
@@ -47,11 +47,11 @@
47 ForumPost *pNext; /* Next in chronological order */
48 ForumPost *pPrev; /* Previous in chronological order */
49 ForumPost *pDisplay; /* Next in display order */
50 int nEdit; /* Number of edits to this post */
51 int nIndent; /* Number of levels of indentation for this post */
52 int iClosed; /* True if forum_rid_is_tagged("closed") */
53 };
54
55 /*
56 ** A single instance of the following tracks all entries for a thread.
57 */
@@ -126,39 +126,39 @@
126 return 0;
127 }
128
129 /*
130 ** Given a forum post RID, this function returns true if that post has
131 ** (or inherits) an active tag named zTagName. If bCheckIrt is true
132 ** then the post to which the given post responds is also checked
133 ** (recursively), else they are not. When checking in-response-to
134 ** posts, the first one which is closed ends the search.
135 **
136 ** This function checks _exactly_ the given rid, whereas forum post
137 ** closure/re-opening is always applied to the head of an edit chain
138 ** so that we get consistent implied locking behavior for later
139 ** versions and responses to arbitrary versions in the chain. Even so,
140 ** the "closed" tag is applied as a propagating tag so will apply to
141 ** all edits in a given chain.
142 **
143 ** The return value is one of:
144 **
145 ** - 0 if no matching tag is found.
146 **
147 ** - The tagxref.rowid of the tagxref entry for the closure if rid is
148 ** the forum post to which the closure applies.
149 **
150 ** - (-tagxref.rowid) if the given rid inherits a "closed" tag from an
151 ** IRT forum post.
152 */
153 static int forum_rid_is_tagged(int rid, const char *zTagName, int bCheckIrt){
154 static Stmt qIrt = empty_Stmt_m;
155 int rc = 0, i = 0;
156 /* TODO: this can probably be turned into a CTE by someone with
157 ** superior SQL-fu. */
158 for( ; rid; i++ ){
159 rc = rid_has_active_tag_name(rid, zTagName);
160 if( rc || !bCheckIrt ) break;
161 else if( !qIrt.pStmt ) {
162 db_static_prepare(&qIrt,
163 "SELECT firt FROM forumpost "
164 "WHERE fpid=$fpid ORDER BY fmtime DESC"
@@ -183,11 +183,11 @@
183 ** as noted below, with the given optional zReason string as the tag's
184 ** value. If doClose is false then any active "closed" tag on frid is
185 ** cancelled, except as noted below. zReason is ignored if doClose is
186 ** false or if zReason is NULL or starts with a NUL byte.
187 **
188 ** This function only adds a "closed" tag if forum_rid_is_tagged()
189 ** indicates that frid's head is not closed. If a parent post is
190 ** already closed, no tag is added. Similarly, it will only remove a
191 ** "closed" tag from a post which has its own "closed" tag, and will
192 ** not remove an inherited one from a parent post.
193 **
@@ -224,11 +224,11 @@
224 int trid; /* RID of new control artifact */
225 char *zUuid; /* UUID of head version of post */
226
227 db_begin_transaction();
228 frid = forumpost_head_rid(frid);
229 iClosed = forum_rid_is_tagged(frid, "closed", 1);
230 if( (iClosed && doClose
231 /* Already closed, noting that in the case of (iClosed<0), it's
232 ** actually a parent which is closed. */)
233 || (iClosed<=0 && !doClose
234 /* This entry is not closed, but a parent post may be. */) ){
@@ -443,13 +443,13 @@
443 for(; p; p=p->pEditPrev ){
444 p->nEdit = pPost->nEdit;
445 p->pEditTail = pPost;
446 }
447 }
448 pPost->iClosed = forum_rid_is_tagged(pPost->pEditHead
449 ? pPost->pEditHead->fpid
450 : pPost->fpid, "closed", 1);
451 }
452 db_finalize(&q);
453
454 if( computeHierarchy ){
455 /* Compute the hierarchical display order */
@@ -1332,11 +1332,11 @@
1332 Manifest *pPost;
1333 int nContent = zContent ? (int)strlen(zContent) : 0;
1334
1335 schema_forum();
1336 if( !g.perm.Admin && (iEdit || iInReplyTo)
1337 && forum_rid_is_tagged(iEdit ? iEdit : iInReplyTo, "closed", 1) ){
1338 forumpost_error_closed();
1339 return 0;
1340 }
1341 if( iEdit==0 && whitespace_only(zContent) ){
1342 return 0;
@@ -1650,11 +1650,11 @@
1650 cgi_redirectf("%R/forumpost/%S",zFpid);
1651 return;
1652 }
1653 bPreview = P("preview")!=0;
1654 bReply = P("reply")!=0;
1655 iClosed = forum_rid_is_tagged(fpid, "closed", 1);
1656 isCsrfSafe = cgi_csrf_safe(2);
1657 bPrivate = content_is_private(fpid);
1658 bSameUser = login_is_individual()
1659 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
1660 if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){
1661
+2 -2
--- src/tag.c
+++ src/tag.c
@@ -962,12 +962,12 @@
962962
963963
964964
/*
965965
** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
966966
** of an active (non-cancelled) tag matching the given rid and tag
967
-** name string, else returns 0. Note that this function does not
968
-** distinguish between a non-existent tag and a cancelled tag.
967
+** name string, else returns 0. This function does not distinguish
968
+** between a non-existent tag and a cancelled tag.
969969
**
970970
** Design note: the return value is the tagxref.rowid because that
971971
** gives us an easy way to fetch the value of the tag later on, if
972972
** needed.
973973
*/
974974
--- src/tag.c
+++ src/tag.c
@@ -962,12 +962,12 @@
962
963
964 /*
965 ** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
966 ** of an active (non-cancelled) tag matching the given rid and tag
967 ** name string, else returns 0. Note that this function does not
968 ** distinguish between a non-existent tag and a cancelled tag.
969 **
970 ** Design note: the return value is the tagxref.rowid because that
971 ** gives us an easy way to fetch the value of the tag later on, if
972 ** needed.
973 */
974
--- src/tag.c
+++ src/tag.c
@@ -962,12 +962,12 @@
962
963
964 /*
965 ** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
966 ** of an active (non-cancelled) tag matching the given rid and tag
967 ** name string, else returns 0. This function does not distinguish
968 ** between a non-existent tag and a cancelled tag.
969 **
970 ** Design note: the return value is the tagxref.rowid because that
971 ** gives us an easy way to fetch the value of the tag later on, if
972 ** needed.
973 */
974

Keyboard Shortcuts

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