Fossil SCM
Minor refactoring of forum post 'closed' tag lookup internals, moving towards extending it to support other tags, e.g. 'resolved'.
Commit
2d7e2cb24e2ebd7efb39d0e74e1595a4baa5f2d1d90a8a9f1dbeb0c2a7455d1a
Parent
ea99abc540d9c26…
2 files changed
+18
-18
+2
-2
+18
-18
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -47,11 +47,11 @@ | ||
| 47 | 47 | ForumPost *pNext; /* Next in chronological order */ |
| 48 | 48 | ForumPost *pPrev; /* Previous in chronological order */ |
| 49 | 49 | ForumPost *pDisplay; /* Next in display order */ |
| 50 | 50 | int nEdit; /* Number of edits to this post */ |
| 51 | 51 | 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") */ | |
| 53 | 53 | }; |
| 54 | 54 | |
| 55 | 55 | /* |
| 56 | 56 | ** A single instance of the following tracks all entries for a thread. |
| 57 | 57 | */ |
| @@ -126,39 +126,39 @@ | ||
| 126 | 126 | return 0; |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | /* |
| 130 | 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 | |
| 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 | 133 | ** (recursively), else they are not. When checking in-response-to |
| 134 | 134 | ** posts, the first one which is closed ends the search. |
| 135 | 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. | |
| 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 | 142 | ** |
| 143 | 143 | ** The return value is one of: |
| 144 | 144 | ** |
| 145 | -** - 0 if no "closed" tag is found. | |
| 145 | +** - 0 if no matching tag is found. | |
| 146 | 146 | ** |
| 147 | 147 | ** - The tagxref.rowid of the tagxref entry for the closure if rid is |
| 148 | 148 | ** the forum post to which the closure applies. |
| 149 | 149 | ** |
| 150 | 150 | ** - (-tagxref.rowid) if the given rid inherits a "closed" tag from an |
| 151 | 151 | ** IRT forum post. |
| 152 | 152 | */ |
| 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){ | |
| 154 | 154 | static Stmt qIrt = empty_Stmt_m; |
| 155 | 155 | int rc = 0, i = 0; |
| 156 | 156 | /* TODO: this can probably be turned into a CTE by someone with |
| 157 | 157 | ** superior SQL-fu. */ |
| 158 | 158 | for( ; rid; i++ ){ |
| 159 | - rc = rid_has_active_tag_name(rid, "closed"); | |
| 159 | + rc = rid_has_active_tag_name(rid, zTagName); | |
| 160 | 160 | if( rc || !bCheckIrt ) break; |
| 161 | 161 | else if( !qIrt.pStmt ) { |
| 162 | 162 | db_static_prepare(&qIrt, |
| 163 | 163 | "SELECT firt FROM forumpost " |
| 164 | 164 | "WHERE fpid=$fpid ORDER BY fmtime DESC" |
| @@ -183,11 +183,11 @@ | ||
| 183 | 183 | ** as noted below, with the given optional zReason string as the tag's |
| 184 | 184 | ** value. If doClose is false then any active "closed" tag on frid is |
| 185 | 185 | ** cancelled, except as noted below. zReason is ignored if doClose is |
| 186 | 186 | ** false or if zReason is NULL or starts with a NUL byte. |
| 187 | 187 | ** |
| 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() | |
| 189 | 189 | ** indicates that frid's head is not closed. If a parent post is |
| 190 | 190 | ** already closed, no tag is added. Similarly, it will only remove a |
| 191 | 191 | ** "closed" tag from a post which has its own "closed" tag, and will |
| 192 | 192 | ** not remove an inherited one from a parent post. |
| 193 | 193 | ** |
| @@ -224,11 +224,11 @@ | ||
| 224 | 224 | int trid; /* RID of new control artifact */ |
| 225 | 225 | char *zUuid; /* UUID of head version of post */ |
| 226 | 226 | |
| 227 | 227 | db_begin_transaction(); |
| 228 | 228 | frid = forumpost_head_rid(frid); |
| 229 | - iClosed = forum_rid_is_closed(frid, 1); | |
| 229 | + iClosed = forum_rid_is_tagged(frid, "closed", 1); | |
| 230 | 230 | if( (iClosed && doClose |
| 231 | 231 | /* Already closed, noting that in the case of (iClosed<0), it's |
| 232 | 232 | ** actually a parent which is closed. */) |
| 233 | 233 | || (iClosed<=0 && !doClose |
| 234 | 234 | /* This entry is not closed, but a parent post may be. */) ){ |
| @@ -443,13 +443,13 @@ | ||
| 443 | 443 | for(; p; p=p->pEditPrev ){ |
| 444 | 444 | p->nEdit = pPost->nEdit; |
| 445 | 445 | p->pEditTail = pPost; |
| 446 | 446 | } |
| 447 | 447 | } |
| 448 | - pPost->iClosed = forum_rid_is_closed(pPost->pEditHead | |
| 448 | + pPost->iClosed = forum_rid_is_tagged(pPost->pEditHead | |
| 449 | 449 | ? pPost->pEditHead->fpid |
| 450 | - : pPost->fpid, 1); | |
| 450 | + : pPost->fpid, "closed", 1); | |
| 451 | 451 | } |
| 452 | 452 | db_finalize(&q); |
| 453 | 453 | |
| 454 | 454 | if( computeHierarchy ){ |
| 455 | 455 | /* Compute the hierarchical display order */ |
| @@ -1332,11 +1332,11 @@ | ||
| 1332 | 1332 | Manifest *pPost; |
| 1333 | 1333 | int nContent = zContent ? (int)strlen(zContent) : 0; |
| 1334 | 1334 | |
| 1335 | 1335 | schema_forum(); |
| 1336 | 1336 | 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) ){ | |
| 1338 | 1338 | forumpost_error_closed(); |
| 1339 | 1339 | return 0; |
| 1340 | 1340 | } |
| 1341 | 1341 | if( iEdit==0 && whitespace_only(zContent) ){ |
| 1342 | 1342 | return 0; |
| @@ -1650,11 +1650,11 @@ | ||
| 1650 | 1650 | cgi_redirectf("%R/forumpost/%S",zFpid); |
| 1651 | 1651 | return; |
| 1652 | 1652 | } |
| 1653 | 1653 | bPreview = P("preview")!=0; |
| 1654 | 1654 | bReply = P("reply")!=0; |
| 1655 | - iClosed = forum_rid_is_closed(fpid, 1); | |
| 1655 | + iClosed = forum_rid_is_tagged(fpid, "closed", 1); | |
| 1656 | 1656 | isCsrfSafe = cgi_csrf_safe(2); |
| 1657 | 1657 | bPrivate = content_is_private(fpid); |
| 1658 | 1658 | bSameUser = login_is_individual() |
| 1659 | 1659 | && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 1660 | 1660 | if( isCsrfSafe && (g.perm.ModForum || (bPrivate && bSameUser)) ){ |
| 1661 | 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; /* 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 @@ | ||
| 962 | 962 | |
| 963 | 963 | |
| 964 | 964 | /* |
| 965 | 965 | ** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry |
| 966 | 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. | |
| 967 | +** name string, else returns 0. This function does not distinguish | |
| 968 | +** between a non-existent tag and a cancelled tag. | |
| 969 | 969 | ** |
| 970 | 970 | ** Design note: the return value is the tagxref.rowid because that |
| 971 | 971 | ** gives us an easy way to fetch the value of the tag later on, if |
| 972 | 972 | ** needed. |
| 973 | 973 | */ |
| 974 | 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. 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 |