Fossil SCM

Cleanups, mostly docs, in the user elevation alerts. Document the currently-known ways which this particular alert differs from others. This needs more sanding-down but am checking this in to go work on the broken user deletion (which pre-dates this branch but was first discovered here).

stephan 2025-03-09 07:12 useredit-note-elevation
Commit d6c5c7f639bceeef2e8c60de96731d2138094fcf2f3f8aa7bec971937a9ba4a8
2 files changed +10 -2 +28 -16
+10 -2
--- src/alerts.c
+++ src/alerts.c
@@ -1987,11 +1987,11 @@
19871987
sc = strchr(ssub,'c')!=0;
19881988
sf = strchr(ssub,'f')!=0;
19891989
sn = strchr(ssub,'n')!=0;
19901990
sr = strchr(ssub,'r')!=0;
19911991
st = strchr(ssub,'t')!=0;
1992
- su = g.perm.Admin && strchr(ssub,'u')!=0;
1992
+ su = strchr(ssub,'u')!=0;
19931993
sw = strchr(ssub,'w')!=0;
19941994
sx = strchr(ssub,'x')!=0;
19951995
smip = db_column_text(&q, 5);
19961996
mtime = db_column_text(&q, 7);
19971997
sctime = db_column_text(&q, 8);
@@ -2109,10 +2109,14 @@
21092109
if( g.perm.RdWiki ){
21102110
@ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
21112111
@ Wiki</label><br>
21122112
}
21132113
if( g.perm.Admin ){
2114
+ /* Corner-case bug: if an admin assigns 'u' to a non-admin, that
2115
+ ** subscription will get removed if the user later edits their
2116
+ ** subscriptions, as non-admins are not permitted to add that
2117
+ ** subscription. */
21142118
@ <label><input type="checkbox" name="su" %s(su?"checked":"")>\
21152119
@ User permission elevation</label>
21162120
}
21172121
@ </td></tr>
21182122
if( strchr(ssub,'k')!=0 ){
@@ -2542,15 +2546,16 @@
25422546
** f An original forum post
25432547
** n New forum threads
25442548
** r Replies to my forum posts
25452549
** x An edit to a prior forum post
25462550
** t A new ticket or a change to an existing ticket
2551
+** u A user was added or received new permissions
25472552
** w A change to a wiki page
25482553
** x Edits to forum posts
25492554
*/
25502555
struct EmailEvent {
2551
- int type; /* 'c', 'f', 'n', 'r', 't', 'w', 'x' */
2556
+ int type; /* 'c', 'f', 'n', 'r', 't', 'u', 'w', 'x' */
25522557
int needMod; /* Pending moderator approval */
25532558
Blob hdr; /* Header content, for forum entries */
25542559
Blob txt; /* Text description to appear in an alert */
25552560
char *zFromName; /* Human name of the sender */
25562561
char *zPriors; /* Upthread sender IDs for forum posts */
@@ -2945,10 +2950,11 @@
29452950
);
29462951
if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
29472952
if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
29482953
if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
29492954
if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
2955
+ if( strchr(zSub, 'u') ) blob_appendf(pBody, " * User permission elevation\n");
29502956
if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
29512957
blob_appendf(pBody, "\n"
29522958
"If you take no action, your subscription will expire and you will be\n"
29532959
"unsubscribed in about %d days. To make other changes or to unsubscribe\n"
29542960
"immediately, visit the following webpage:\n\n"
@@ -3157,10 +3163,11 @@
31573163
switch( p->type ){
31583164
case 'x': case 'f':
31593165
case 'n': case 'r': xType = '5'; break;
31603166
case 't': xType = 'q'; break;
31613167
case 'w': xType = 'l'; break;
3168
+ /* Note: case 'u' is not handled here */
31623169
}
31633170
if( strchr(zCap,xType)==0 ) continue;
31643171
}
31653172
}else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
31663173
/* Setup and admin users can get any notification that does not
@@ -3173,10 +3180,11 @@
31733180
case 'c': xType = 'o'; break;
31743181
case 'x': case 'f':
31753182
case 'n': case 'r': xType = '2'; break;
31763183
case 't': xType = 'r'; break;
31773184
case 'w': xType = 'j'; break;
3185
+ /* Note: case 'u' is not handled here */
31783186
}
31793187
if( strchr(zCap,xType)==0 ) continue;
31803188
}
31813189
if( blob_size(&p->hdr)>0 ){
31823190
/* This alert should be sent as a separate email */
31833191
--- src/alerts.c
+++ src/alerts.c
@@ -1987,11 +1987,11 @@
1987 sc = strchr(ssub,'c')!=0;
1988 sf = strchr(ssub,'f')!=0;
1989 sn = strchr(ssub,'n')!=0;
1990 sr = strchr(ssub,'r')!=0;
1991 st = strchr(ssub,'t')!=0;
1992 su = g.perm.Admin && strchr(ssub,'u')!=0;
1993 sw = strchr(ssub,'w')!=0;
1994 sx = strchr(ssub,'x')!=0;
1995 smip = db_column_text(&q, 5);
1996 mtime = db_column_text(&q, 7);
1997 sctime = db_column_text(&q, 8);
@@ -2109,10 +2109,14 @@
2109 if( g.perm.RdWiki ){
2110 @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
2111 @ Wiki</label><br>
2112 }
2113 if( g.perm.Admin ){
 
 
 
 
2114 @ <label><input type="checkbox" name="su" %s(su?"checked":"")>\
2115 @ User permission elevation</label>
2116 }
2117 @ </td></tr>
2118 if( strchr(ssub,'k')!=0 ){
@@ -2542,15 +2546,16 @@
2542 ** f An original forum post
2543 ** n New forum threads
2544 ** r Replies to my forum posts
2545 ** x An edit to a prior forum post
2546 ** t A new ticket or a change to an existing ticket
 
2547 ** w A change to a wiki page
2548 ** x Edits to forum posts
2549 */
2550 struct EmailEvent {
2551 int type; /* 'c', 'f', 'n', 'r', 't', 'w', 'x' */
2552 int needMod; /* Pending moderator approval */
2553 Blob hdr; /* Header content, for forum entries */
2554 Blob txt; /* Text description to appear in an alert */
2555 char *zFromName; /* Human name of the sender */
2556 char *zPriors; /* Upthread sender IDs for forum posts */
@@ -2945,10 +2950,11 @@
2945 );
2946 if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
2947 if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
2948 if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
2949 if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
 
2950 if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
2951 blob_appendf(pBody, "\n"
2952 "If you take no action, your subscription will expire and you will be\n"
2953 "unsubscribed in about %d days. To make other changes or to unsubscribe\n"
2954 "immediately, visit the following webpage:\n\n"
@@ -3157,10 +3163,11 @@
3157 switch( p->type ){
3158 case 'x': case 'f':
3159 case 'n': case 'r': xType = '5'; break;
3160 case 't': xType = 'q'; break;
3161 case 'w': xType = 'l'; break;
 
3162 }
3163 if( strchr(zCap,xType)==0 ) continue;
3164 }
3165 }else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
3166 /* Setup and admin users can get any notification that does not
@@ -3173,10 +3180,11 @@
3173 case 'c': xType = 'o'; break;
3174 case 'x': case 'f':
3175 case 'n': case 'r': xType = '2'; break;
3176 case 't': xType = 'r'; break;
3177 case 'w': xType = 'j'; break;
 
3178 }
3179 if( strchr(zCap,xType)==0 ) continue;
3180 }
3181 if( blob_size(&p->hdr)>0 ){
3182 /* This alert should be sent as a separate email */
3183
--- src/alerts.c
+++ src/alerts.c
@@ -1987,11 +1987,11 @@
1987 sc = strchr(ssub,'c')!=0;
1988 sf = strchr(ssub,'f')!=0;
1989 sn = strchr(ssub,'n')!=0;
1990 sr = strchr(ssub,'r')!=0;
1991 st = strchr(ssub,'t')!=0;
1992 su = strchr(ssub,'u')!=0;
1993 sw = strchr(ssub,'w')!=0;
1994 sx = strchr(ssub,'x')!=0;
1995 smip = db_column_text(&q, 5);
1996 mtime = db_column_text(&q, 7);
1997 sctime = db_column_text(&q, 8);
@@ -2109,10 +2109,14 @@
2109 if( g.perm.RdWiki ){
2110 @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
2111 @ Wiki</label><br>
2112 }
2113 if( g.perm.Admin ){
2114 /* Corner-case bug: if an admin assigns 'u' to a non-admin, that
2115 ** subscription will get removed if the user later edits their
2116 ** subscriptions, as non-admins are not permitted to add that
2117 ** subscription. */
2118 @ <label><input type="checkbox" name="su" %s(su?"checked":"")>\
2119 @ User permission elevation</label>
2120 }
2121 @ </td></tr>
2122 if( strchr(ssub,'k')!=0 ){
@@ -2542,15 +2546,16 @@
2546 ** f An original forum post
2547 ** n New forum threads
2548 ** r Replies to my forum posts
2549 ** x An edit to a prior forum post
2550 ** t A new ticket or a change to an existing ticket
2551 ** u A user was added or received new permissions
2552 ** w A change to a wiki page
2553 ** x Edits to forum posts
2554 */
2555 struct EmailEvent {
2556 int type; /* 'c', 'f', 'n', 'r', 't', 'u', 'w', 'x' */
2557 int needMod; /* Pending moderator approval */
2558 Blob hdr; /* Header content, for forum entries */
2559 Blob txt; /* Text description to appear in an alert */
2560 char *zFromName; /* Human name of the sender */
2561 char *zPriors; /* Upthread sender IDs for forum posts */
@@ -2945,10 +2950,11 @@
2950 );
2951 if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
2952 if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
2953 if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
2954 if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
2955 if( strchr(zSub, 'u') ) blob_appendf(pBody, " * User permission elevation\n");
2956 if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
2957 blob_appendf(pBody, "\n"
2958 "If you take no action, your subscription will expire and you will be\n"
2959 "unsubscribed in about %d days. To make other changes or to unsubscribe\n"
2960 "immediately, visit the following webpage:\n\n"
@@ -3157,10 +3163,11 @@
3163 switch( p->type ){
3164 case 'x': case 'f':
3165 case 'n': case 'r': xType = '5'; break;
3166 case 't': xType = 'q'; break;
3167 case 'w': xType = 'l'; break;
3168 /* Note: case 'u' is not handled here */
3169 }
3170 if( strchr(zCap,xType)==0 ) continue;
3171 }
3172 }else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
3173 /* Setup and admin users can get any notification that does not
@@ -3173,10 +3180,11 @@
3180 case 'c': xType = 'o'; break;
3181 case 'x': case 'f':
3182 case 'n': case 'r': xType = '2'; break;
3183 case 't': xType = 'r'; break;
3184 case 'w': xType = 'j'; break;
3185 /* Note: case 'u' is not handled here */
3186 }
3187 if( strchr(zCap,xType)==0 ) continue;
3188 }
3189 if( blob_size(&p->hdr)>0 ){
3190 /* This alert should be sent as a separate email */
3191
+28 -16
--- src/setupuser.c
+++ src/setupuser.c
@@ -320,11 +320,27 @@
320320
return 0;
321321
}
322322
323323
/*
324324
** Sends notification of user permission elevation changes to all
325
-** subscribers with a "u" subscription.
325
+** subscribers with a "u" subscription. This is a no-op if alerts are
326
+** not enabled.
327
+**
328
+** These subscriptions differ from most, in that:
329
+**
330
+** - The attempt is made to send them immediately, as opposed to
331
+** handling them en masse via alert_send_alerts().
332
+**
333
+** - They do not honor digest mode.
334
+**
335
+** - They currently lack an "unsubscribe" link.
336
+**
337
+** - Only an admin can assign this subscription, but if a non-admin
338
+** edits their subscriptions after an admin assigns them this one,
339
+** this particular one will be lost. "Feature or bug?" is unclear,
340
+** but it would be odd for a non-admin to be assigned this
341
+** capability.
326342
*/
327343
static void alert_user_elevation(const char *zLogin, /*Affected user*/
328344
int uid, /*[user].uid*/
329345
int bIsNew, /*true if new user*/
330346
const char *zOrigCaps,/*Old caps*/
@@ -331,15 +347,20 @@
331347
const char *zNewCaps /*New caps*/){
332348
Blob hdr, body;
333349
Stmt q;
334350
int nBody;
335351
AlertSender *pSender;
336
- char *zSubname = db_get("email-subname", "[Fossil Repo]");
337
- char *zURL = db_get("email-url",0);
338
- char * zSubject = bIsNew
352
+ char *zSubname;
353
+ char *zURL;
354
+ char * zSubject;
355
+
356
+ if( !alert_enabled() ) return;
357
+ zSubject = bIsNew
339358
? mprintf("New user created: [%q]", zLogin)
340359
: mprintf("User [%q] permissions elevated", zLogin);
360
+ zURL = db_get("email-url",0);
361
+ zSubname = db_get("email-subname", "[Fossil Repo]");
341362
blob_init(&body, 0, 0);
342363
blob_init(&hdr, 0, 0);
343364
if( bIsNew ){
344365
blob_appendf(&body, "User [%q] was created by with "
345366
"permissions [%q] by user [%q].\n",
@@ -357,13 +378,12 @@
357378
db_prepare(&q,
358379
"SELECT semail, hex(subscriberCode)"
359380
" FROM subscriber, user "
360381
" WHERE sverified AND NOT sdonotcall"
361382
" AND suname=login"
362
- " AND fullcap(cap) GLOB '*a*'"
363383
" AND ssub GLOB '*u*'");
364
- while( db_step(&q)==SQLITE_ROW ){
384
+ while( !pSender->zErr && db_step(&q)==SQLITE_ROW ){
365385
const char *zTo = db_column_text(&q, 0);
366386
blob_truncate(&hdr, 0);
367387
blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n",
368388
zTo, zSubname, zSubject);
369389
if( zURL ){
@@ -525,24 +545,16 @@
525545
style_finish_page();
526546
return;
527547
}
528548
cgi_csrf_verify();
529549
db_unprotect(PROTECT_USER);
530
- {
531
- Stmt q;
532
- db_prepare(&q,
550
+ uid = db_int(0,
533551
"REPLACE INTO user(uid,login,info,pw,cap,mtime) "
534552
"VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now()) "
535553
"RETURNING uid",
536554
uid, zLogin, P("info"), zPw, &aCap[0]);
537
- if( SQLITE_ROW==db_step(&q) ){
538
- uid = db_column_int(&q, 0);
539
- }else{
540
- fossil_fatal("Inserting new user failed");
541
- }
542
- db_finalize(&q);
543
- }
555
+ assert( uid>0 );
544556
if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
545557
if( alert_tables_exist() ){
546558
/* Rename matching subscriber entry, else the user cannot
547559
re-subscribe with their same email address. */
548560
db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
549561
--- src/setupuser.c
+++ src/setupuser.c
@@ -320,11 +320,27 @@
320 return 0;
321 }
322
323 /*
324 ** Sends notification of user permission elevation changes to all
325 ** subscribers with a "u" subscription.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326 */
327 static void alert_user_elevation(const char *zLogin, /*Affected user*/
328 int uid, /*[user].uid*/
329 int bIsNew, /*true if new user*/
330 const char *zOrigCaps,/*Old caps*/
@@ -331,15 +347,20 @@
331 const char *zNewCaps /*New caps*/){
332 Blob hdr, body;
333 Stmt q;
334 int nBody;
335 AlertSender *pSender;
336 char *zSubname = db_get("email-subname", "[Fossil Repo]");
337 char *zURL = db_get("email-url",0);
338 char * zSubject = bIsNew
 
 
 
339 ? mprintf("New user created: [%q]", zLogin)
340 : mprintf("User [%q] permissions elevated", zLogin);
 
 
341 blob_init(&body, 0, 0);
342 blob_init(&hdr, 0, 0);
343 if( bIsNew ){
344 blob_appendf(&body, "User [%q] was created by with "
345 "permissions [%q] by user [%q].\n",
@@ -357,13 +378,12 @@
357 db_prepare(&q,
358 "SELECT semail, hex(subscriberCode)"
359 " FROM subscriber, user "
360 " WHERE sverified AND NOT sdonotcall"
361 " AND suname=login"
362 " AND fullcap(cap) GLOB '*a*'"
363 " AND ssub GLOB '*u*'");
364 while( db_step(&q)==SQLITE_ROW ){
365 const char *zTo = db_column_text(&q, 0);
366 blob_truncate(&hdr, 0);
367 blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n",
368 zTo, zSubname, zSubject);
369 if( zURL ){
@@ -525,24 +545,16 @@
525 style_finish_page();
526 return;
527 }
528 cgi_csrf_verify();
529 db_unprotect(PROTECT_USER);
530 {
531 Stmt q;
532 db_prepare(&q,
533 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
534 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now()) "
535 "RETURNING uid",
536 uid, zLogin, P("info"), zPw, &aCap[0]);
537 if( SQLITE_ROW==db_step(&q) ){
538 uid = db_column_int(&q, 0);
539 }else{
540 fossil_fatal("Inserting new user failed");
541 }
542 db_finalize(&q);
543 }
544 if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
545 if( alert_tables_exist() ){
546 /* Rename matching subscriber entry, else the user cannot
547 re-subscribe with their same email address. */
548 db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
549
--- src/setupuser.c
+++ src/setupuser.c
@@ -320,11 +320,27 @@
320 return 0;
321 }
322
323 /*
324 ** Sends notification of user permission elevation changes to all
325 ** subscribers with a "u" subscription. This is a no-op if alerts are
326 ** not enabled.
327 **
328 ** These subscriptions differ from most, in that:
329 **
330 ** - The attempt is made to send them immediately, as opposed to
331 ** handling them en masse via alert_send_alerts().
332 **
333 ** - They do not honor digest mode.
334 **
335 ** - They currently lack an "unsubscribe" link.
336 **
337 ** - Only an admin can assign this subscription, but if a non-admin
338 ** edits their subscriptions after an admin assigns them this one,
339 ** this particular one will be lost. "Feature or bug?" is unclear,
340 ** but it would be odd for a non-admin to be assigned this
341 ** capability.
342 */
343 static void alert_user_elevation(const char *zLogin, /*Affected user*/
344 int uid, /*[user].uid*/
345 int bIsNew, /*true if new user*/
346 const char *zOrigCaps,/*Old caps*/
@@ -331,15 +347,20 @@
347 const char *zNewCaps /*New caps*/){
348 Blob hdr, body;
349 Stmt q;
350 int nBody;
351 AlertSender *pSender;
352 char *zSubname;
353 char *zURL;
354 char * zSubject;
355
356 if( !alert_enabled() ) return;
357 zSubject = bIsNew
358 ? mprintf("New user created: [%q]", zLogin)
359 : mprintf("User [%q] permissions elevated", zLogin);
360 zURL = db_get("email-url",0);
361 zSubname = db_get("email-subname", "[Fossil Repo]");
362 blob_init(&body, 0, 0);
363 blob_init(&hdr, 0, 0);
364 if( bIsNew ){
365 blob_appendf(&body, "User [%q] was created by with "
366 "permissions [%q] by user [%q].\n",
@@ -357,13 +378,12 @@
378 db_prepare(&q,
379 "SELECT semail, hex(subscriberCode)"
380 " FROM subscriber, user "
381 " WHERE sverified AND NOT sdonotcall"
382 " AND suname=login"
 
383 " AND ssub GLOB '*u*'");
384 while( !pSender->zErr && db_step(&q)==SQLITE_ROW ){
385 const char *zTo = db_column_text(&q, 0);
386 blob_truncate(&hdr, 0);
387 blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n",
388 zTo, zSubname, zSubject);
389 if( zURL ){
@@ -525,24 +545,16 @@
545 style_finish_page();
546 return;
547 }
548 cgi_csrf_verify();
549 db_unprotect(PROTECT_USER);
550 uid = db_int(0,
 
 
551 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
552 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now()) "
553 "RETURNING uid",
554 uid, zLogin, P("info"), zPw, &aCap[0]);
555 assert( uid>0 );
 
 
 
 
 
 
556 if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
557 if( alert_tables_exist() ){
558 /* Rename matching subscriber entry, else the user cannot
559 re-subscribe with their same email address. */
560 db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
561

Keyboard Shortcuts

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