Fossil SCM

Add admin-only alert subscription for notification when a user's permissions are elevated.

stephan 2025-03-13 17:06 trunk merge
Commit d96055cc33aa98f04ee8c92b996d9f91a599e4efe7347312f77fd3763ef27e22
+24 -3
--- src/alerts.c
+++ src/alerts.c
@@ -51,10 +51,11 @@
5151
@ -- f - Forum posts
5252
@ -- k - ** Special: Unsubscribed using /oneclickunsub
5353
@ -- n - New forum threads
5454
@ -- r - Replies to my own forum posts
5555
@ -- t - Ticket changes
56
+@ -- u - Elevation of users' permissions (admins only)
5657
@ -- w - Wiki changes
5758
@ -- x - Edits to forum posts
5859
@ -- Probably different codes will be added in the future. In the future
5960
@ -- we might also add a separate table that allows subscribing to email
6061
@ -- notifications for specific branches or tags or tickets.
@@ -1563,10 +1564,11 @@
15631564
if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c';
15641565
if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
15651566
if( g.perm.RdForum && PB("sn") ) ssub[nsub++] = 'n';
15661567
if( g.perm.RdForum && PB("sr") ) ssub[nsub++] = 'r';
15671568
if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't';
1569
+ if( g.perm.Admin && PB("su") ) ssub[nsub++] = 'u';
15681570
if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w';
15691571
if( g.perm.RdForum && PB("sx") ) ssub[nsub++] = 'x';
15701572
ssub[nsub] = 0;
15711573
zCode = db_text(0,
15721574
"INSERT INTO subscriber(semail,suname,"
@@ -1627,10 +1629,11 @@
16271629
if( g.perm.Read ) cgi_set_parameter_nocopy("sc","1",1);
16281630
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sf","1",1);
16291631
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sn","1",1);
16301632
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sr","1",1);
16311633
if( g.perm.RdTkt ) cgi_set_parameter_nocopy("st","1",1);
1634
+ if( g.perm.Admin ) cgi_set_parameter_nocopy("su","1",1);
16321635
if( g.perm.RdWiki ) cgi_set_parameter_nocopy("sw","1",1);
16331636
}
16341637
@ <p>To receive email notifications for changes to this
16351638
@ repository, fill out the form below and press the "Submit" button.</p>
16361639
form_begin(0, "%R/subscribe");
@@ -1699,10 +1702,14 @@
16991702
}
17001703
if( g.perm.RdWiki ){
17011704
@ <label><input type="checkbox" name="sw" %s(PCK("sw"))> \
17021705
@ Wiki</label><br>
17031706
}
1707
+ if( g.perm.Admin ){
1708
+ @ <label><input type="checkbox" name="su" %s(PCK("su"))> \
1709
+ @ User permission elevation</label>
1710
+ }
17041711
di = PB("di");
17051712
@ </td></tr>
17061713
@ <tr>
17071714
@ <td class="form_label">Delivery:</td>
17081715
@ <td><select size="1" name="di">
@@ -1820,11 +1827,11 @@
18201827
** verifying the email address.
18211828
*/
18221829
void alert_page(void){
18231830
const char *zName = 0; /* Value of the name= query parameter */
18241831
Stmt q; /* For querying the database */
1825
- int sa, sc, sf, st, sw, sx; /* Types of notifications requested */
1832
+ int sa, sc, sf, st, su, sw, sx; /* Types of notifications requested */
18261833
int sn, sr;
18271834
int sdigest = 0, sdonotcall = 0, sverified = 0; /* Other fields */
18281835
int isLogin; /* True if logged in as an individual */
18291836
const char *ssub = 0; /* Subscription flags */
18301837
const char *semail = 0; /* Email address */
@@ -1881,10 +1888,11 @@
18811888
if( g.perm.Read && PB("sc") ) newSsub[nsub++] = 'c';
18821889
if( g.perm.RdForum && PB("sf") ) newSsub[nsub++] = 'f';
18831890
if( g.perm.RdForum && PB("sn") ) newSsub[nsub++] = 'n';
18841891
if( g.perm.RdForum && PB("sr") ) newSsub[nsub++] = 'r';
18851892
if( g.perm.RdTkt && PB("st") ) newSsub[nsub++] = 't';
1893
+ if( g.perm.Admin && PB("su") ) newSsub[nsub++] = 'u';
18861894
if( g.perm.RdWiki && PB("sw") ) newSsub[nsub++] = 'w';
18871895
if( g.perm.RdForum && PB("sx") ) newSsub[nsub++] = 'x';
18881896
newSsub[nsub] = 0;
18891897
ssub = newSsub;
18901898
blob_init(&update, "UPDATE subscriber SET", -1);
@@ -1979,10 +1987,11 @@
19791987
sc = strchr(ssub,'c')!=0;
19801988
sf = strchr(ssub,'f')!=0;
19811989
sn = strchr(ssub,'n')!=0;
19821990
sr = strchr(ssub,'r')!=0;
19831991
st = strchr(ssub,'t')!=0;
1992
+ su = strchr(ssub,'u')!=0;
19841993
sw = strchr(ssub,'w')!=0;
19851994
sx = strchr(ssub,'x')!=0;
19861995
smip = db_column_text(&q, 5);
19871996
mtime = db_column_text(&q, 7);
19881997
sctime = db_column_text(&q, 8);
@@ -2097,11 +2106,19 @@
20972106
@ <label><input type="checkbox" name="st" %s(st?"checked":"")>\
20982107
@ Ticket changes</label><br>
20992108
}
21002109
if( g.perm.RdWiki ){
21012110
@ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
2102
- @ Wiki</label>
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>
21032120
}
21042121
@ </td></tr>
21052122
if( strchr(ssub,'k')!=0 ){
21062123
@ <tr><td></td><td>&nbsp;&uarr;&nbsp;
21072124
@ Note: User did a one-click unsubscribe</td></tr>
@@ -2529,15 +2546,16 @@
25292546
** f An original forum post
25302547
** n New forum threads
25312548
** r Replies to my forum posts
25322549
** x An edit to a prior forum post
25332550
** t A new ticket or a change to an existing ticket
2551
+** u A user was added or received new permissions
25342552
** w A change to a wiki page
25352553
** x Edits to forum posts
25362554
*/
25372555
struct EmailEvent {
2538
- int type; /* 'c', 'f', 'n', 'r', 't', 'w', 'x' */
2556
+ int type; /* 'c', 'f', 'n', 'r', 't', 'u', 'w', 'x' */
25392557
int needMod; /* Pending moderator approval */
25402558
Blob hdr; /* Header content, for forum entries */
25412559
Blob txt; /* Text description to appear in an alert */
25422560
char *zFromName; /* Human name of the sender */
25432561
char *zPriors; /* Upthread sender IDs for forum posts */
@@ -2932,10 +2950,11 @@
29322950
);
29332951
if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
29342952
if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
29352953
if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
29362954
if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
2955
+ if( strchr(zSub, 'u') ) blob_appendf(pBody, " * User permission elevation\n");
29372956
if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
29382957
blob_appendf(pBody, "\n"
29392958
"If you take no action, your subscription will expire and you will be\n"
29402959
"unsubscribed in about %d days. To make other changes or to unsubscribe\n"
29412960
"immediately, visit the following webpage:\n\n"
@@ -3144,10 +3163,11 @@
31443163
switch( p->type ){
31453164
case 'x': case 'f':
31463165
case 'n': case 'r': xType = '5'; break;
31473166
case 't': xType = 'q'; break;
31483167
case 'w': xType = 'l'; break;
3168
+ /* Note: case 'u' is not handled here */
31493169
}
31503170
if( strchr(zCap,xType)==0 ) continue;
31513171
}
31523172
}else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
31533173
/* Setup and admin users can get any notification that does not
@@ -3160,10 +3180,11 @@
31603180
case 'c': xType = 'o'; break;
31613181
case 'x': case 'f':
31623182
case 'n': case 'r': xType = '2'; break;
31633183
case 't': xType = 'r'; break;
31643184
case 'w': xType = 'j'; break;
3185
+ /* Note: case 'u' is not handled here */
31653186
}
31663187
if( strchr(zCap,xType)==0 ) continue;
31673188
}
31683189
if( blob_size(&p->hdr)>0 ){
31693190
/* This alert should be sent as a separate email */
31703191
--- src/alerts.c
+++ src/alerts.c
@@ -51,10 +51,11 @@
51 @ -- f - Forum posts
52 @ -- k - ** Special: Unsubscribed using /oneclickunsub
53 @ -- n - New forum threads
54 @ -- r - Replies to my own forum posts
55 @ -- t - Ticket changes
 
56 @ -- w - Wiki changes
57 @ -- x - Edits to forum posts
58 @ -- Probably different codes will be added in the future. In the future
59 @ -- we might also add a separate table that allows subscribing to email
60 @ -- notifications for specific branches or tags or tickets.
@@ -1563,10 +1564,11 @@
1563 if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c';
1564 if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
1565 if( g.perm.RdForum && PB("sn") ) ssub[nsub++] = 'n';
1566 if( g.perm.RdForum && PB("sr") ) ssub[nsub++] = 'r';
1567 if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't';
 
1568 if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w';
1569 if( g.perm.RdForum && PB("sx") ) ssub[nsub++] = 'x';
1570 ssub[nsub] = 0;
1571 zCode = db_text(0,
1572 "INSERT INTO subscriber(semail,suname,"
@@ -1627,10 +1629,11 @@
1627 if( g.perm.Read ) cgi_set_parameter_nocopy("sc","1",1);
1628 if( g.perm.RdForum ) cgi_set_parameter_nocopy("sf","1",1);
1629 if( g.perm.RdForum ) cgi_set_parameter_nocopy("sn","1",1);
1630 if( g.perm.RdForum ) cgi_set_parameter_nocopy("sr","1",1);
1631 if( g.perm.RdTkt ) cgi_set_parameter_nocopy("st","1",1);
 
1632 if( g.perm.RdWiki ) cgi_set_parameter_nocopy("sw","1",1);
1633 }
1634 @ <p>To receive email notifications for changes to this
1635 @ repository, fill out the form below and press the "Submit" button.</p>
1636 form_begin(0, "%R/subscribe");
@@ -1699,10 +1702,14 @@
1699 }
1700 if( g.perm.RdWiki ){
1701 @ <label><input type="checkbox" name="sw" %s(PCK("sw"))> \
1702 @ Wiki</label><br>
1703 }
 
 
 
 
1704 di = PB("di");
1705 @ </td></tr>
1706 @ <tr>
1707 @ <td class="form_label">Delivery:</td>
1708 @ <td><select size="1" name="di">
@@ -1820,11 +1827,11 @@
1820 ** verifying the email address.
1821 */
1822 void alert_page(void){
1823 const char *zName = 0; /* Value of the name= query parameter */
1824 Stmt q; /* For querying the database */
1825 int sa, sc, sf, st, sw, sx; /* Types of notifications requested */
1826 int sn, sr;
1827 int sdigest = 0, sdonotcall = 0, sverified = 0; /* Other fields */
1828 int isLogin; /* True if logged in as an individual */
1829 const char *ssub = 0; /* Subscription flags */
1830 const char *semail = 0; /* Email address */
@@ -1881,10 +1888,11 @@
1881 if( g.perm.Read && PB("sc") ) newSsub[nsub++] = 'c';
1882 if( g.perm.RdForum && PB("sf") ) newSsub[nsub++] = 'f';
1883 if( g.perm.RdForum && PB("sn") ) newSsub[nsub++] = 'n';
1884 if( g.perm.RdForum && PB("sr") ) newSsub[nsub++] = 'r';
1885 if( g.perm.RdTkt && PB("st") ) newSsub[nsub++] = 't';
 
1886 if( g.perm.RdWiki && PB("sw") ) newSsub[nsub++] = 'w';
1887 if( g.perm.RdForum && PB("sx") ) newSsub[nsub++] = 'x';
1888 newSsub[nsub] = 0;
1889 ssub = newSsub;
1890 blob_init(&update, "UPDATE subscriber SET", -1);
@@ -1979,10 +1987,11 @@
1979 sc = strchr(ssub,'c')!=0;
1980 sf = strchr(ssub,'f')!=0;
1981 sn = strchr(ssub,'n')!=0;
1982 sr = strchr(ssub,'r')!=0;
1983 st = strchr(ssub,'t')!=0;
 
1984 sw = strchr(ssub,'w')!=0;
1985 sx = strchr(ssub,'x')!=0;
1986 smip = db_column_text(&q, 5);
1987 mtime = db_column_text(&q, 7);
1988 sctime = db_column_text(&q, 8);
@@ -2097,11 +2106,19 @@
2097 @ <label><input type="checkbox" name="st" %s(st?"checked":"")>\
2098 @ Ticket changes</label><br>
2099 }
2100 if( g.perm.RdWiki ){
2101 @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
2102 @ Wiki</label>
 
 
 
 
 
 
 
 
2103 }
2104 @ </td></tr>
2105 if( strchr(ssub,'k')!=0 ){
2106 @ <tr><td></td><td>&nbsp;&uarr;&nbsp;
2107 @ Note: User did a one-click unsubscribe</td></tr>
@@ -2529,15 +2546,16 @@
2529 ** f An original forum post
2530 ** n New forum threads
2531 ** r Replies to my forum posts
2532 ** x An edit to a prior forum post
2533 ** t A new ticket or a change to an existing ticket
 
2534 ** w A change to a wiki page
2535 ** x Edits to forum posts
2536 */
2537 struct EmailEvent {
2538 int type; /* 'c', 'f', 'n', 'r', 't', 'w', 'x' */
2539 int needMod; /* Pending moderator approval */
2540 Blob hdr; /* Header content, for forum entries */
2541 Blob txt; /* Text description to appear in an alert */
2542 char *zFromName; /* Human name of the sender */
2543 char *zPriors; /* Upthread sender IDs for forum posts */
@@ -2932,10 +2950,11 @@
2932 );
2933 if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
2934 if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
2935 if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
2936 if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
 
2937 if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
2938 blob_appendf(pBody, "\n"
2939 "If you take no action, your subscription will expire and you will be\n"
2940 "unsubscribed in about %d days. To make other changes or to unsubscribe\n"
2941 "immediately, visit the following webpage:\n\n"
@@ -3144,10 +3163,11 @@
3144 switch( p->type ){
3145 case 'x': case 'f':
3146 case 'n': case 'r': xType = '5'; break;
3147 case 't': xType = 'q'; break;
3148 case 'w': xType = 'l'; break;
 
3149 }
3150 if( strchr(zCap,xType)==0 ) continue;
3151 }
3152 }else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
3153 /* Setup and admin users can get any notification that does not
@@ -3160,10 +3180,11 @@
3160 case 'c': xType = 'o'; break;
3161 case 'x': case 'f':
3162 case 'n': case 'r': xType = '2'; break;
3163 case 't': xType = 'r'; break;
3164 case 'w': xType = 'j'; break;
 
3165 }
3166 if( strchr(zCap,xType)==0 ) continue;
3167 }
3168 if( blob_size(&p->hdr)>0 ){
3169 /* This alert should be sent as a separate email */
3170
--- src/alerts.c
+++ src/alerts.c
@@ -51,10 +51,11 @@
51 @ -- f - Forum posts
52 @ -- k - ** Special: Unsubscribed using /oneclickunsub
53 @ -- n - New forum threads
54 @ -- r - Replies to my own forum posts
55 @ -- t - Ticket changes
56 @ -- u - Elevation of users' permissions (admins only)
57 @ -- w - Wiki changes
58 @ -- x - Edits to forum posts
59 @ -- Probably different codes will be added in the future. In the future
60 @ -- we might also add a separate table that allows subscribing to email
61 @ -- notifications for specific branches or tags or tickets.
@@ -1563,10 +1564,11 @@
1564 if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c';
1565 if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
1566 if( g.perm.RdForum && PB("sn") ) ssub[nsub++] = 'n';
1567 if( g.perm.RdForum && PB("sr") ) ssub[nsub++] = 'r';
1568 if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't';
1569 if( g.perm.Admin && PB("su") ) ssub[nsub++] = 'u';
1570 if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w';
1571 if( g.perm.RdForum && PB("sx") ) ssub[nsub++] = 'x';
1572 ssub[nsub] = 0;
1573 zCode = db_text(0,
1574 "INSERT INTO subscriber(semail,suname,"
@@ -1627,10 +1629,11 @@
1629 if( g.perm.Read ) cgi_set_parameter_nocopy("sc","1",1);
1630 if( g.perm.RdForum ) cgi_set_parameter_nocopy("sf","1",1);
1631 if( g.perm.RdForum ) cgi_set_parameter_nocopy("sn","1",1);
1632 if( g.perm.RdForum ) cgi_set_parameter_nocopy("sr","1",1);
1633 if( g.perm.RdTkt ) cgi_set_parameter_nocopy("st","1",1);
1634 if( g.perm.Admin ) cgi_set_parameter_nocopy("su","1",1);
1635 if( g.perm.RdWiki ) cgi_set_parameter_nocopy("sw","1",1);
1636 }
1637 @ <p>To receive email notifications for changes to this
1638 @ repository, fill out the form below and press the "Submit" button.</p>
1639 form_begin(0, "%R/subscribe");
@@ -1699,10 +1702,14 @@
1702 }
1703 if( g.perm.RdWiki ){
1704 @ <label><input type="checkbox" name="sw" %s(PCK("sw"))> \
1705 @ Wiki</label><br>
1706 }
1707 if( g.perm.Admin ){
1708 @ <label><input type="checkbox" name="su" %s(PCK("su"))> \
1709 @ User permission elevation</label>
1710 }
1711 di = PB("di");
1712 @ </td></tr>
1713 @ <tr>
1714 @ <td class="form_label">Delivery:</td>
1715 @ <td><select size="1" name="di">
@@ -1820,11 +1827,11 @@
1827 ** verifying the email address.
1828 */
1829 void alert_page(void){
1830 const char *zName = 0; /* Value of the name= query parameter */
1831 Stmt q; /* For querying the database */
1832 int sa, sc, sf, st, su, sw, sx; /* Types of notifications requested */
1833 int sn, sr;
1834 int sdigest = 0, sdonotcall = 0, sverified = 0; /* Other fields */
1835 int isLogin; /* True if logged in as an individual */
1836 const char *ssub = 0; /* Subscription flags */
1837 const char *semail = 0; /* Email address */
@@ -1881,10 +1888,11 @@
1888 if( g.perm.Read && PB("sc") ) newSsub[nsub++] = 'c';
1889 if( g.perm.RdForum && PB("sf") ) newSsub[nsub++] = 'f';
1890 if( g.perm.RdForum && PB("sn") ) newSsub[nsub++] = 'n';
1891 if( g.perm.RdForum && PB("sr") ) newSsub[nsub++] = 'r';
1892 if( g.perm.RdTkt && PB("st") ) newSsub[nsub++] = 't';
1893 if( g.perm.Admin && PB("su") ) newSsub[nsub++] = 'u';
1894 if( g.perm.RdWiki && PB("sw") ) newSsub[nsub++] = 'w';
1895 if( g.perm.RdForum && PB("sx") ) newSsub[nsub++] = 'x';
1896 newSsub[nsub] = 0;
1897 ssub = newSsub;
1898 blob_init(&update, "UPDATE subscriber SET", -1);
@@ -1979,10 +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);
@@ -2097,11 +2106,19 @@
2106 @ <label><input type="checkbox" name="st" %s(st?"checked":"")>\
2107 @ Ticket changes</label><br>
2108 }
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 ){
2123 @ <tr><td></td><td>&nbsp;&uarr;&nbsp;
2124 @ Note: User did a one-click unsubscribe</td></tr>
@@ -2529,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 */
@@ -2932,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"
@@ -3144,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
@@ -3160,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
+116 -12
--- src/setupuser.c
+++ src/setupuser.c
@@ -302,10 +302,101 @@
302302
if( zPw==0 ) return 0;
303303
if( zPw[0]==0 ) return 1;
304304
while( zPw[0]=='*' ){ zPw++; }
305305
return zPw[0]!=0;
306306
}
307
+
308
+/*
309
+** Return true if user capability string zNew contains any capability
310
+** letter which is not in user capability string zOrig, else 0. This
311
+** does not take inherited permissions into account. Either argument
312
+** may be NULL.
313
+*/
314
+static int userHasNewCaps(const char *zOrig, const char *zNew){
315
+ for( ; zNew && *zNew; ++zNew ){
316
+ if( !zOrig || strchr(zOrig,*zNew)==0 ){
317
+ return *zNew;
318
+ }
319
+ }
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
+** - They currently lack an "unsubscribe" link.
331
+**
332
+** - Only an admin can assign this subscription, but if a non-admin
333
+** edits their subscriptions after an admin assigns them this one,
334
+** this particular one will be lost. "Feature or bug?" is unclear,
335
+** but it would be odd for a non-admin to be assigned this
336
+** capability.
337
+*/
338
+static void alert_user_elevation(const char *zLogin, /*Affected user*/
339
+ int uid, /*[user].uid*/
340
+ int bIsNew, /*true if new user*/
341
+ const char *zOrigCaps,/*Old caps*/
342
+ const char *zNewCaps /*New caps*/){
343
+ Blob hdr, body;
344
+ Stmt q;
345
+ int nBody;
346
+ AlertSender *pSender;
347
+ char *zSubname;
348
+ char *zURL;
349
+ char * zSubject;
350
+
351
+ if( !alert_enabled() ) return;
352
+ zSubject = bIsNew
353
+ ? mprintf("New user created: [%q]", zLogin)
354
+ : mprintf("User [%q] permissions elevated", zLogin);
355
+ zURL = db_get("email-url",0);
356
+ zSubname = db_get("email-subname", "[Fossil Repo]");
357
+ blob_init(&body, 0, 0);
358
+ blob_init(&hdr, 0, 0);
359
+ if( bIsNew ){
360
+ blob_appendf(&body, "User [%q] was created by with "
361
+ "permissions [%q] by user [%q].\n",
362
+ zLogin, zNewCaps, g.zLogin);
363
+ } else {
364
+ blob_appendf(&body, "Permissions for user [%q] where elevated "
365
+ "from [%q] to [%q] by user [%q].\n",
366
+ zLogin, zOrigCaps, zNewCaps, g.zLogin);
367
+ }
368
+ if( zURL ){
369
+ blob_appendf(&body, "\nUser editor: %s/setup_uedit?uid=%d\n", zURL, uid);
370
+ }
371
+ nBody = blob_size(&body);
372
+ pSender = alert_sender_new(0, 0);
373
+ db_prepare(&q,
374
+ "SELECT semail, hex(subscriberCode)"
375
+ " FROM subscriber, user "
376
+ " WHERE sverified AND NOT sdonotcall"
377
+ " AND suname=login"
378
+ " AND ssub GLOB '*u*'");
379
+ while( !pSender->zErr && db_step(&q)==SQLITE_ROW ){
380
+ const char *zTo = db_column_text(&q, 0);
381
+ blob_truncate(&hdr, 0);
382
+ blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n",
383
+ zTo, zSubname, zSubject);
384
+ if( zURL ){
385
+ const char *zCode = db_column_text(&q, 1);
386
+ blob_truncate(&body, nBody);
387
+ blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
388
+ zURL, zCode);
389
+ }
390
+ alert_send(pSender, &hdr, &body, 0);
391
+ }
392
+ db_finalize(&q);
393
+ alert_sender_free(pSender);
394
+ fossil_free(zURL);
395
+ fossil_free(zSubname);
396
+ fossil_free(zSubject);
397
+}
307398
308399
/*
309400
** WEBPAGE: setup_uedit
310401
**
311402
** Edit information about a user or create a new user.
@@ -314,10 +405,11 @@
314405
void user_edit(void){
315406
const char *zId, *zLogin, *zInfo, *zCap, *zPw;
316407
const char *zGroup;
317408
const char *zOldLogin;
318409
int uid, i;
410
+ char *zOldCaps = 0; /* Capabilities before edit */
319411
char *zDeleteVerify = 0; /* Delete user verification text */
320412
int higherUser = 0; /* True if user being edited is SETUP and the */
321413
/* user doing the editing is ADMIN. Disallow editing */
322414
const char *inherit[128];
323415
int a[128];
@@ -331,14 +423,15 @@
331423
/* Check to see if an ADMIN user is trying to edit a SETUP account.
332424
** Don't allow that.
333425
*/
334426
zId = PD("id", "0");
335427
uid = atoi(zId);
336
- if( zId && !g.perm.Setup && uid>0 ){
337
- char *zOldCaps;
338
- zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
339
- higherUser = zOldCaps && strchr(zOldCaps,'s');
428
+ if( uid>0 ){
429
+ zOldCaps = db_text("", "SELECT cap FROM user WHERE uid=%d",uid);
430
+ if( zId && !g.perm.Setup ){
431
+ higherUser = zOldCaps && strchr(zOldCaps,'s');
432
+ }
340433
}
341434
342435
if( P("can") ){
343436
/* User pressed the cancel button */
344437
cgi_redirect(cgi_referer("setup_ulist"));
@@ -393,10 +486,12 @@
393486
}else if( !cgi_csrf_safe(2) ){
394487
/* This might be a cross-site request forgery, so ignore it */
395488
}else{
396489
/* We have all the information we need to make the change to the user */
397490
char c;
491
+ int bHasNewCaps = 0 /* 1 if user's permissions are increased */;
492
+ const int bIsNew = uid<=0;
398493
char aCap[70], zNm[4];
399494
zNm[0] = 'a';
400495
zNm[2] = 0;
401496
for(i=0, c='a'; c<='z'; c++){
402497
zNm[1] = c;
@@ -413,10 +508,11 @@
413508
a[c&0x7f] = P(zNm)!=0;
414509
if( a[c&0x7f] ) aCap[i++] = c;
415510
}
416511
417512
aCap[i] = 0;
513
+ bHasNewCaps = bIsNew || userHasNewCaps(zOldCaps, &aCap[0]);
418514
zPw = P("pw");
419515
zLogin = P("login");
420516
if( strlen(zLogin)==0 ){
421517
const char *zRef = cgi_referer("setup_ulist");
422518
style_header("User Creation Error");
@@ -444,15 +540,16 @@
444540
style_finish_page();
445541
return;
446542
}
447543
cgi_csrf_verify();
448544
db_unprotect(PROTECT_USER);
449
- db_multi_exec(
450
- "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
451
- "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
452
- uid, zLogin, P("info"), zPw, &aCap[0]
453
- );
545
+ uid = db_int(0,
546
+ "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
547
+ "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now()) "
548
+ "RETURNING uid",
549
+ uid, zLogin, P("info"), zPw, &aCap[0]);
550
+ assert( uid>0 );
454551
if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
455552
if( alert_tables_exist() ){
456553
/* Rename matching subscriber entry, else the user cannot
457554
re-subscribe with their same email address. */
458555
db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
@@ -460,11 +557,12 @@
460557
}
461558
admin_log( "Renamed user [%q] to [%q].", zOldLogin, zLogin );
462559
}
463560
db_protect_pop();
464561
setup_incr_cfgcnt();
465
- admin_log( "Updated user [%q] with capabilities [%q].",
562
+ admin_log( "%s user [%q] with capabilities [%q].",
563
+ bIsNew ? "Added" : "Updated",
466564
zLogin, &aCap[0] );
467565
if( atoi(PD("all","0"))>0 ){
468566
Blob sql;
469567
char *zErr = 0;
470568
blob_zero(&sql);
@@ -515,30 +613,36 @@
515613
@ <span class="loginError">%h(zErr)</span>
516614
@
517615
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
518616
@ [Bummer]</a></p>
519617
style_finish_page();
618
+ if( bHasNewCaps ){
619
+ alert_user_elevation(zLogin, uid, bIsNew, zOldCaps, &aCap[0]);
620
+ }
520621
return;
521622
}
522623
}
624
+ if( bHasNewCaps ){
625
+ alert_user_elevation(zLogin, uid, bIsNew, zOldCaps, &aCap[0]);
626
+ }
523627
cgi_redirect(cgi_referer("setup_ulist"));
524628
return;
525629
}
526630
527631
/* Load the existing information about the user, if any
528632
*/
529633
zLogin = "";
530634
zInfo = "";
531
- zCap = "";
635
+ zCap = zOldCaps;
532636
zPw = "";
533637
for(i='a'; i<='z'; i++) oa[i] = "";
534638
for(i='0'; i<='9'; i++) oa[i] = "";
535639
for(i='A'; i<='Z'; i++) oa[i] = "";
536640
if( uid ){
641
+ assert( zCap );
537642
zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
538643
zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
539
- zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
540644
zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
541645
for(i=0; zCap[i]; i++){
542646
char c = zCap[i];
543647
if( (c>='a' && c<='z') || (c>='0' && c<='9') || (c>='A' && c<='Z') ){
544648
oa[c&0x7f] = " checked=\"checked\"";
545649
--- src/setupuser.c
+++ src/setupuser.c
@@ -302,10 +302,101 @@
302 if( zPw==0 ) return 0;
303 if( zPw[0]==0 ) return 1;
304 while( zPw[0]=='*' ){ zPw++; }
305 return zPw[0]!=0;
306 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
308 /*
309 ** WEBPAGE: setup_uedit
310 **
311 ** Edit information about a user or create a new user.
@@ -314,10 +405,11 @@
314 void user_edit(void){
315 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
316 const char *zGroup;
317 const char *zOldLogin;
318 int uid, i;
 
319 char *zDeleteVerify = 0; /* Delete user verification text */
320 int higherUser = 0; /* True if user being edited is SETUP and the */
321 /* user doing the editing is ADMIN. Disallow editing */
322 const char *inherit[128];
323 int a[128];
@@ -331,14 +423,15 @@
331 /* Check to see if an ADMIN user is trying to edit a SETUP account.
332 ** Don't allow that.
333 */
334 zId = PD("id", "0");
335 uid = atoi(zId);
336 if( zId && !g.perm.Setup && uid>0 ){
337 char *zOldCaps;
338 zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
339 higherUser = zOldCaps && strchr(zOldCaps,'s');
 
340 }
341
342 if( P("can") ){
343 /* User pressed the cancel button */
344 cgi_redirect(cgi_referer("setup_ulist"));
@@ -393,10 +486,12 @@
393 }else if( !cgi_csrf_safe(2) ){
394 /* This might be a cross-site request forgery, so ignore it */
395 }else{
396 /* We have all the information we need to make the change to the user */
397 char c;
 
 
398 char aCap[70], zNm[4];
399 zNm[0] = 'a';
400 zNm[2] = 0;
401 for(i=0, c='a'; c<='z'; c++){
402 zNm[1] = c;
@@ -413,10 +508,11 @@
413 a[c&0x7f] = P(zNm)!=0;
414 if( a[c&0x7f] ) aCap[i++] = c;
415 }
416
417 aCap[i] = 0;
 
418 zPw = P("pw");
419 zLogin = P("login");
420 if( strlen(zLogin)==0 ){
421 const char *zRef = cgi_referer("setup_ulist");
422 style_header("User Creation Error");
@@ -444,15 +540,16 @@
444 style_finish_page();
445 return;
446 }
447 cgi_csrf_verify();
448 db_unprotect(PROTECT_USER);
449 db_multi_exec(
450 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
451 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
452 uid, zLogin, P("info"), zPw, &aCap[0]
453 );
 
454 if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
455 if( alert_tables_exist() ){
456 /* Rename matching subscriber entry, else the user cannot
457 re-subscribe with their same email address. */
458 db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
@@ -460,11 +557,12 @@
460 }
461 admin_log( "Renamed user [%q] to [%q].", zOldLogin, zLogin );
462 }
463 db_protect_pop();
464 setup_incr_cfgcnt();
465 admin_log( "Updated user [%q] with capabilities [%q].",
 
466 zLogin, &aCap[0] );
467 if( atoi(PD("all","0"))>0 ){
468 Blob sql;
469 char *zErr = 0;
470 blob_zero(&sql);
@@ -515,30 +613,36 @@
515 @ <span class="loginError">%h(zErr)</span>
516 @
517 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
518 @ [Bummer]</a></p>
519 style_finish_page();
 
 
 
520 return;
521 }
522 }
 
 
 
523 cgi_redirect(cgi_referer("setup_ulist"));
524 return;
525 }
526
527 /* Load the existing information about the user, if any
528 */
529 zLogin = "";
530 zInfo = "";
531 zCap = "";
532 zPw = "";
533 for(i='a'; i<='z'; i++) oa[i] = "";
534 for(i='0'; i<='9'; i++) oa[i] = "";
535 for(i='A'; i<='Z'; i++) oa[i] = "";
536 if( uid ){
 
537 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
538 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
539 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
540 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
541 for(i=0; zCap[i]; i++){
542 char c = zCap[i];
543 if( (c>='a' && c<='z') || (c>='0' && c<='9') || (c>='A' && c<='Z') ){
544 oa[c&0x7f] = " checked=\"checked\"";
545
--- src/setupuser.c
+++ src/setupuser.c
@@ -302,10 +302,101 @@
302 if( zPw==0 ) return 0;
303 if( zPw[0]==0 ) return 1;
304 while( zPw[0]=='*' ){ zPw++; }
305 return zPw[0]!=0;
306 }
307
308 /*
309 ** Return true if user capability string zNew contains any capability
310 ** letter which is not in user capability string zOrig, else 0. This
311 ** does not take inherited permissions into account. Either argument
312 ** may be NULL.
313 */
314 static int userHasNewCaps(const char *zOrig, const char *zNew){
315 for( ; zNew && *zNew; ++zNew ){
316 if( !zOrig || strchr(zOrig,*zNew)==0 ){
317 return *zNew;
318 }
319 }
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 ** - They currently lack an "unsubscribe" link.
331 **
332 ** - Only an admin can assign this subscription, but if a non-admin
333 ** edits their subscriptions after an admin assigns them this one,
334 ** this particular one will be lost. "Feature or bug?" is unclear,
335 ** but it would be odd for a non-admin to be assigned this
336 ** capability.
337 */
338 static void alert_user_elevation(const char *zLogin, /*Affected user*/
339 int uid, /*[user].uid*/
340 int bIsNew, /*true if new user*/
341 const char *zOrigCaps,/*Old caps*/
342 const char *zNewCaps /*New caps*/){
343 Blob hdr, body;
344 Stmt q;
345 int nBody;
346 AlertSender *pSender;
347 char *zSubname;
348 char *zURL;
349 char * zSubject;
350
351 if( !alert_enabled() ) return;
352 zSubject = bIsNew
353 ? mprintf("New user created: [%q]", zLogin)
354 : mprintf("User [%q] permissions elevated", zLogin);
355 zURL = db_get("email-url",0);
356 zSubname = db_get("email-subname", "[Fossil Repo]");
357 blob_init(&body, 0, 0);
358 blob_init(&hdr, 0, 0);
359 if( bIsNew ){
360 blob_appendf(&body, "User [%q] was created by with "
361 "permissions [%q] by user [%q].\n",
362 zLogin, zNewCaps, g.zLogin);
363 } else {
364 blob_appendf(&body, "Permissions for user [%q] where elevated "
365 "from [%q] to [%q] by user [%q].\n",
366 zLogin, zOrigCaps, zNewCaps, g.zLogin);
367 }
368 if( zURL ){
369 blob_appendf(&body, "\nUser editor: %s/setup_uedit?uid=%d\n", zURL, uid);
370 }
371 nBody = blob_size(&body);
372 pSender = alert_sender_new(0, 0);
373 db_prepare(&q,
374 "SELECT semail, hex(subscriberCode)"
375 " FROM subscriber, user "
376 " WHERE sverified AND NOT sdonotcall"
377 " AND suname=login"
378 " AND ssub GLOB '*u*'");
379 while( !pSender->zErr && db_step(&q)==SQLITE_ROW ){
380 const char *zTo = db_column_text(&q, 0);
381 blob_truncate(&hdr, 0);
382 blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n",
383 zTo, zSubname, zSubject);
384 if( zURL ){
385 const char *zCode = db_column_text(&q, 1);
386 blob_truncate(&body, nBody);
387 blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
388 zURL, zCode);
389 }
390 alert_send(pSender, &hdr, &body, 0);
391 }
392 db_finalize(&q);
393 alert_sender_free(pSender);
394 fossil_free(zURL);
395 fossil_free(zSubname);
396 fossil_free(zSubject);
397 }
398
399 /*
400 ** WEBPAGE: setup_uedit
401 **
402 ** Edit information about a user or create a new user.
@@ -314,10 +405,11 @@
405 void user_edit(void){
406 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
407 const char *zGroup;
408 const char *zOldLogin;
409 int uid, i;
410 char *zOldCaps = 0; /* Capabilities before edit */
411 char *zDeleteVerify = 0; /* Delete user verification text */
412 int higherUser = 0; /* True if user being edited is SETUP and the */
413 /* user doing the editing is ADMIN. Disallow editing */
414 const char *inherit[128];
415 int a[128];
@@ -331,14 +423,15 @@
423 /* Check to see if an ADMIN user is trying to edit a SETUP account.
424 ** Don't allow that.
425 */
426 zId = PD("id", "0");
427 uid = atoi(zId);
428 if( uid>0 ){
429 zOldCaps = db_text("", "SELECT cap FROM user WHERE uid=%d",uid);
430 if( zId && !g.perm.Setup ){
431 higherUser = zOldCaps && strchr(zOldCaps,'s');
432 }
433 }
434
435 if( P("can") ){
436 /* User pressed the cancel button */
437 cgi_redirect(cgi_referer("setup_ulist"));
@@ -393,10 +486,12 @@
486 }else if( !cgi_csrf_safe(2) ){
487 /* This might be a cross-site request forgery, so ignore it */
488 }else{
489 /* We have all the information we need to make the change to the user */
490 char c;
491 int bHasNewCaps = 0 /* 1 if user's permissions are increased */;
492 const int bIsNew = uid<=0;
493 char aCap[70], zNm[4];
494 zNm[0] = 'a';
495 zNm[2] = 0;
496 for(i=0, c='a'; c<='z'; c++){
497 zNm[1] = c;
@@ -413,10 +508,11 @@
508 a[c&0x7f] = P(zNm)!=0;
509 if( a[c&0x7f] ) aCap[i++] = c;
510 }
511
512 aCap[i] = 0;
513 bHasNewCaps = bIsNew || userHasNewCaps(zOldCaps, &aCap[0]);
514 zPw = P("pw");
515 zLogin = P("login");
516 if( strlen(zLogin)==0 ){
517 const char *zRef = cgi_referer("setup_ulist");
518 style_header("User Creation Error");
@@ -444,15 +540,16 @@
540 style_finish_page();
541 return;
542 }
543 cgi_csrf_verify();
544 db_unprotect(PROTECT_USER);
545 uid = db_int(0,
546 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
547 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now()) "
548 "RETURNING uid",
549 uid, zLogin, P("info"), zPw, &aCap[0]);
550 assert( uid>0 );
551 if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
552 if( alert_tables_exist() ){
553 /* Rename matching subscriber entry, else the user cannot
554 re-subscribe with their same email address. */
555 db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
@@ -460,11 +557,12 @@
557 }
558 admin_log( "Renamed user [%q] to [%q].", zOldLogin, zLogin );
559 }
560 db_protect_pop();
561 setup_incr_cfgcnt();
562 admin_log( "%s user [%q] with capabilities [%q].",
563 bIsNew ? "Added" : "Updated",
564 zLogin, &aCap[0] );
565 if( atoi(PD("all","0"))>0 ){
566 Blob sql;
567 char *zErr = 0;
568 blob_zero(&sql);
@@ -515,30 +613,36 @@
613 @ <span class="loginError">%h(zErr)</span>
614 @
615 @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
616 @ [Bummer]</a></p>
617 style_finish_page();
618 if( bHasNewCaps ){
619 alert_user_elevation(zLogin, uid, bIsNew, zOldCaps, &aCap[0]);
620 }
621 return;
622 }
623 }
624 if( bHasNewCaps ){
625 alert_user_elevation(zLogin, uid, bIsNew, zOldCaps, &aCap[0]);
626 }
627 cgi_redirect(cgi_referer("setup_ulist"));
628 return;
629 }
630
631 /* Load the existing information about the user, if any
632 */
633 zLogin = "";
634 zInfo = "";
635 zCap = zOldCaps;
636 zPw = "";
637 for(i='a'; i<='z'; i++) oa[i] = "";
638 for(i='0'; i<='9'; i++) oa[i] = "";
639 for(i='A'; i<='Z'; i++) oa[i] = "";
640 if( uid ){
641 assert( zCap );
642 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
643 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
 
644 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
645 for(i=0; zCap[i]; i++){
646 char c = zCap[i];
647 if( (c>='a' && c<='z') || (c>='0' && c<='9') || (c>='A' && c<='Z') ){
648 oa[c&0x7f] = " checked=\"checked\"";
649
--- www/alerts.md
+++ www/alerts.md
@@ -7,10 +7,11 @@
77
88
* New [checkins](/help?cmd=ci)
99
* [Ticket](./tickets.wiki) changes
1010
* [Wiki](./wikitheory.wiki) page changes
1111
* New and edited [forum](./forum.wiki) posts
12
+ * Users receiving [new permissions](./caps/index.md) (admins only)
1213
* Announcements
1314
1415
Subscribers can elect to receive emails as soon as these events happen,
1516
or they can receive a daily digest of the events instead.
1617
@@ -515,10 +516,14 @@
515516
email addresses until the user clicks the link in the verification
516517
email. This checkbox lets the Fossil Admin user manually verify the
517518
user, such as in the case where the verification email message got
518519
lost. Unchecking this box does not cause another verification email
519520
to be sent.
521
+
522
+* Admin users (only) may activate the "user elevation" subscription,
523
+ which sends a notification when a user is created or is explicitly
524
+ assigned permission they did not formerly have.
520525
521526
This screen also allows a Fossil Admin user to perform other activities
522527
on behalf of a subscriber which they could do themselves, such as to
523528
[unsubscribe](#unsub) them.
524529
525530
--- www/alerts.md
+++ www/alerts.md
@@ -7,10 +7,11 @@
7
8 * New [checkins](/help?cmd=ci)
9 * [Ticket](./tickets.wiki) changes
10 * [Wiki](./wikitheory.wiki) page changes
11 * New and edited [forum](./forum.wiki) posts
 
12 * Announcements
13
14 Subscribers can elect to receive emails as soon as these events happen,
15 or they can receive a daily digest of the events instead.
16
@@ -515,10 +516,14 @@
515 email addresses until the user clicks the link in the verification
516 email. This checkbox lets the Fossil Admin user manually verify the
517 user, such as in the case where the verification email message got
518 lost. Unchecking this box does not cause another verification email
519 to be sent.
 
 
 
 
520
521 This screen also allows a Fossil Admin user to perform other activities
522 on behalf of a subscriber which they could do themselves, such as to
523 [unsubscribe](#unsub) them.
524
525
--- www/alerts.md
+++ www/alerts.md
@@ -7,10 +7,11 @@
7
8 * New [checkins](/help?cmd=ci)
9 * [Ticket](./tickets.wiki) changes
10 * [Wiki](./wikitheory.wiki) page changes
11 * New and edited [forum](./forum.wiki) posts
12 * Users receiving [new permissions](./caps/index.md) (admins only)
13 * Announcements
14
15 Subscribers can elect to receive emails as soon as these events happen,
16 or they can receive a daily digest of the events instead.
17
@@ -515,10 +516,14 @@
516 email addresses until the user clicks the link in the verification
517 email. This checkbox lets the Fossil Admin user manually verify the
518 user, such as in the case where the verification email message got
519 lost. Unchecking this box does not cause another verification email
520 to be sent.
521
522 * Admin users (only) may activate the "user elevation" subscription,
523 which sends a notification when a user is created or is explicitly
524 assigned permission they did not formerly have.
525
526 This screen also allows a Fossil Admin user to perform other activities
527 on behalf of a subscriber which they could do themselves, such as to
528 [unsubscribe](#unsub) them.
529
530
--- www/changes.wiki
+++ www/changes.wiki
@@ -85,10 +85,15 @@
8585
<li> The -u (--usage) option shows only the command-line syntax
8686
<li> The -o (--options) option shows only the command-line options
8787
</ol>
8888
* Added the ability to attach wiki pages to a ticket for extended
8989
descriptions.
90
+ * Add a "user elevation" [/doc/trunk/www/alerts.md|subscription]
91
+ which alerts subscribers when an admin creates a new user or
92
+ adds new permissions to one.
93
+ * Diverse minor fixes and additions.
94
+
9095
9196
<h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
9297
9398
* The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
9499
that have non-ASCII filenames
95100
--- www/changes.wiki
+++ www/changes.wiki
@@ -85,10 +85,15 @@
85 <li> The -u (--usage) option shows only the command-line syntax
86 <li> The -o (--options) option shows only the command-line options
87 </ol>
88 * Added the ability to attach wiki pages to a ticket for extended
89 descriptions.
 
 
 
 
 
90
91 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
92
93 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
94 that have non-ASCII filenames
95
--- www/changes.wiki
+++ www/changes.wiki
@@ -85,10 +85,15 @@
85 <li> The -u (--usage) option shows only the command-line syntax
86 <li> The -o (--options) option shows only the command-line options
87 </ol>
88 * Added the ability to attach wiki pages to a ticket for extended
89 descriptions.
90 * Add a "user elevation" [/doc/trunk/www/alerts.md|subscription]
91 which alerts subscribers when an admin creates a new user or
92 adds new permissions to one.
93 * Diverse minor fixes and additions.
94
95
96 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
97
98 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
99 that have non-ASCII filenames
100
--- www/changes.wiki
+++ www/changes.wiki
@@ -85,10 +85,15 @@
8585
<li> The -u (--usage) option shows only the command-line syntax
8686
<li> The -o (--options) option shows only the command-line options
8787
</ol>
8888
* Added the ability to attach wiki pages to a ticket for extended
8989
descriptions.
90
+ * Add a "user elevation" [/doc/trunk/www/alerts.md|subscription]
91
+ which alerts subscribers when an admin creates a new user or
92
+ adds new permissions to one.
93
+ * Diverse minor fixes and additions.
94
+
9095
9196
<h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
9297
9398
* The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
9499
that have non-ASCII filenames
95100
--- www/changes.wiki
+++ www/changes.wiki
@@ -85,10 +85,15 @@
85 <li> The -u (--usage) option shows only the command-line syntax
86 <li> The -o (--options) option shows only the command-line options
87 </ol>
88 * Added the ability to attach wiki pages to a ticket for extended
89 descriptions.
 
 
 
 
 
90
91 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
92
93 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
94 that have non-ASCII filenames
95
--- www/changes.wiki
+++ www/changes.wiki
@@ -85,10 +85,15 @@
85 <li> The -u (--usage) option shows only the command-line syntax
86 <li> The -o (--options) option shows only the command-line options
87 </ol>
88 * Added the ability to attach wiki pages to a ticket for extended
89 descriptions.
90 * Add a "user elevation" [/doc/trunk/www/alerts.md|subscription]
91 which alerts subscribers when an admin creates a new user or
92 adds new permissions to one.
93 * Diverse minor fixes and additions.
94
95
96 <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
97
98 * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
99 that have non-ASCII filenames
100

Keyboard Shortcuts

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