Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add capability to determine whether a given sub-thread inherits a lock from a parent. Re-label "locked" to "closed" per /chat feedback. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | forumpost-locking |
| Files: | files | file ages | folders |
| SHA3-256: |
464f4d175f503806837051c4bc6b404a |
| User & Date: | stephan 2023-02-21 01:58:29.078 |
Context
|
2023-02-21
| ||
| 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) | |
| 01:58 | Add capability to determine whether a given sub-thread inherits a lock from a parent. Re-label "locked" to "closed" per /chat feedback. ... (check-in: 464f4d175f user: stephan tags: forumpost-locking) | |
| 00:52 | Initial bits for "locking" forum (sub)threads using a "closed" tag. This currently affects the display but does not hinder edits made via malicious misuse because the pieces needed for such validation do not yet have access to the relevant ForumPost objects. ... (check-in: 4d664bfe55 user: stephan tags: forumpost-locking) | |
Changes
Changes to src/default.css.
| ︙ | ︙ | |||
902 903 904 905 906 907 908 |
flex-direction: column;
}
div.forumClosed {
border-style: dotted;
opacity: 0.7;
}
div.forumClosed > *:first-child::before {
| | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 |
flex-direction: column;
}
div.forumClosed {
border-style: dotted;
opacity: 0.7;
}
div.forumClosed > *:first-child::before {
content: "[CLOSED] ";
color: red;
opacity: 0.7;
}
.forum div > form {
margin: 0.5em 0;
}
.forum-post-collapser {
|
| ︙ | ︙ |
Changes to src/forum.c.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
if( p->fClosed ) return p->fClosed;
else if( p->pIrt ){
return forum_post_is_closed(p->pIrt->pEditTail
? p->pIrt->pEditTail : p->pIrt);
}
return 0;
}
/*
** Delete a complete ForumThread and all its entries.
*/
static void forumthread_delete(ForumThread *pThread){
ForumPost *pPost, *pNext;
for(pPost=pThread->pFirst; pPost; pPost = pNext){
| > > > > > > > > > > > > > > > > > > > > > > > > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
if( p->fClosed ) return p->fClosed;
else if( p->pIrt ){
return forum_post_is_closed(p->pIrt->pEditTail
? p->pIrt->pEditTail : p->pIrt);
}
return 0;
}
/*
** Given a forum post RID, this function returns true if that post or
** the latest version of any parent post in its hierarchy have an
** active "closed" tag.
*/
int forum_rid_is_closed(int rid){
static Stmt qIrt = empty_Stmt_m;
int rc;
/* TODO: this can probably be turned into a CTE, rather than a
** recursive call into this function, by someone with superior
** SQL-fu. */
rc = rid_has_active_tag_name(rid, "closed");
if( rc ) return rc;
else if( !qIrt.pStmt ) {
db_static_prepare(&qIrt,
"SELECT firt FROM forumpost "
"WHERE fpid=$fpid ORDER BY fmtime DESC"
);
}
db_bind_int(&qIrt, "$fpid", rid);
rc = SQLITE_ROW==db_step(&qIrt) ? db_column_int(&qIrt, 0) : 0;
db_reset(&qIrt);
return rc>0 ? forum_rid_is_closed(rc) : 0;
}
/*
** Delete a complete ForumThread and all its entries.
*/
static void forumthread_delete(ForumThread *pThread){
ForumPost *pPost, *pNext;
for(pPost=pThread->pFirst; pPost; pPost = pNext){
|
| ︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 |
**
** Start a new thread on the forum or reply to an existing thread.
** But first prompt to see if the user would like to log in.
*/
void forum_page_init(void){
int isEdit;
char *zGoto;
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
if( sqlite3_strglob("*edit*", g.zPath)==0 ){
zGoto = mprintf("forume2?fpid=%S",PD("fpid",""));
| > | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 |
**
** Start a new thread on the forum or reply to an existing thread.
** But first prompt to see if the user would like to log in.
*/
void forum_page_init(void){
int isEdit;
char *zGoto;
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
if( sqlite3_strglob("*edit*", g.zPath)==0 ){
zGoto = mprintf("forume2?fpid=%S",PD("fpid",""));
|
| ︙ | ︙ | |||
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 |
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;
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
fpid = symbolic_name_to_rid(zFpid, "f");
if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
webpage_error("Missing or invalid fpid query parameter");
}
froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
webpage_error("fpid does not appear to be a forum post: \"%d\"", fpid);
}
if( P("cancel") ){
cgi_redirectf("%R/forumpost/%S",P("fpid"));
return;
}
isCsrfSafe = cgi_csrf_safe(1);
if( g.perm.ModForum && isCsrfSafe ){
if( P("approve") ){
const char *zUserToTrust;
moderation_approve('f', fpid);
if( g.perm.AdminForum
&& PB("trust")
| > > | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 |
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 fClosed = 0;
login_check_credentials();
if( !g.perm.WrForum ){
login_needed(g.anon.WrForum);
return;
}
fpid = symbolic_name_to_rid(zFpid, "f");
if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
webpage_error("Missing or invalid fpid query parameter");
}
froot = db_int(0, "SELECT froot FROM forumpost WHERE fpid=%d", fpid);
if( froot==0 || (pRootPost = manifest_get(froot, CFTYPE_FORUM, 0))==0 ){
webpage_error("fpid does not appear to be a forum post: \"%d\"", fpid);
}
if( P("cancel") ){
cgi_redirectf("%R/forumpost/%S",P("fpid"));
return;
}
fClosed = forum_rid_is_closed(fpid);
isCsrfSafe = cgi_csrf_safe(1);
if( g.perm.ModForum && isCsrfSafe ){
if( P("approve") ){
const char *zUserToTrust;
moderation_approve('f', fpid);
if( g.perm.AdminForum
&& PB("trust")
|
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
904 905 906 907 908 909 910 |
" AND tagxref.tagid=tag.tagid",
rid, tagId
);
}
/*
| | | | | > | | | | | | > | | | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
" AND tagxref.tagid=tag.tagid",
rid, tagId
);
}
/*
** Returns tagxref.rowid if the given blob.rid has a tagxref.rid entry
** 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 = 0;
assert( 0 != zTagName );
if( !q.pStmt ){
db_static_prepare(&q,
"SELECT tagxref.rowid FROM tagxref, tag"
" WHERE tagxref.rid=$rid AND tagtype>0 "
" AND tag.tagname=$tagname"
" AND tagxref.tagid=tag.tagid"
);
}
db_bind_int(&q, "$rid", rid);
db_bind_text(&q, "$tagname", zTagName);
if( SQLITE_ROW==db_step(&q) ){
rc = db_column_int(&q, 0);
}
db_reset(&q);
return rc;
}
|