Fossil SCM

Filter notifications to reduce multiple alerts if forum-posts are edited.

graham 2020-03-17 12:17 trunk
Commit 1c84fa5569640b937af9241d66e0953756d6a5e771d820af659c8c8bff4a1ffe
1 file changed +120 -11
+120 -11
--- src/alerts.c
+++ src/alerts.c
@@ -303,10 +303,36 @@
303303
"eadmin", "", 0);
304304
@ <p>This is the email for the human administrator for the system.
305305
@ Abuse and trouble reports are send here.
306306
@ (Property: "email-admin")</p>
307307
@ <hr>
308
+
309
+ onoff_attribute("Omit alerts for edited forum posts",
310
+ "alert-omit-edited", "alert-omit-edited", 1, 0 ) ;
311
+
312
+ @ <p>If enabled, notifications will only be sent for the latest
313
+ @ versions of edited forum posts. If disabled, notifications will
314
+ @ be sent for all versions. Applies to both individual and digest
315
+ @ notifications.</p>
316
+
317
+ entry_attribute("Grace period in minutes allowed for editing", 5,
318
+ "alert-edit-window", "alert-edit-window", "5", 0 ) ;
319
+
320
+ @ <p>Number of minutes grace allowed for just-posted forum topics
321
+ @ during which notifications will be sent. This is to reduce the
322
+ @ number of alerts if someone edits a post shortly after posting.
323
+ @ Set to zero to disable this feature.</p>
324
+
325
+ onoff_attribute("Notify immediately if replied-to",
326
+ "alert-notify-on-reply", "alert-notify-on-reply", 1, 0 ) ;
327
+
328
+ @ <p>If enabled, and a forum post has been replied-to, send
329
+ @ notifications immediately, even if the "grace period" has not
330
+ @ expired. If disabled, notifications for replied-to posts will
331
+ @ not be sent until the grace-period has expired. Does not affect
332
+ @ the handling of the reply itself.</p>
333
+ @ <hr>
308334
309335
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
310336
@ </div></form>
311337
db_end_transaction(0);
312338
style_footer();
@@ -1967,10 +1993,11 @@
19671993
int type; /* 'c', 'f', 'm', 't', 'w' */
19681994
int needMod; /* Pending moderator approval */
19691995
Blob hdr; /* Header content, for forum entries */
19701996
Blob txt; /* Text description to appear in an alert */
19711997
char *zFromName; /* Human name of the sender */
1998
+ int edited; /* Forum post has been edited */
19721999
EmailEvent *pNext; /* Next in chronological order */
19732000
};
19742001
#endif
19752002
19762003
/*
@@ -2000,10 +2027,11 @@
20002027
EmailEvent anchor;
20012028
EmailEvent *pLast;
20022029
const char *zUrl = db_get("email-url","http://localhost:8080");
20032030
const char *zFrom;
20042031
const char *zSub;
2032
+ const int alert_omit_edited = db_get_int("alert-omit-edited",0);
20052033
20062034
20072035
/* First do non-forum post events */
20082036
db_prepare(&q,
20092037
"SELECT"
@@ -2024,12 +2052,14 @@
20242052
" wantalert.needMod" /* 4 */
20252053
" FROM temp.wantalert, event, blob"
20262054
" WHERE blob.rid=event.objid"
20272055
" AND event.objid=substr(wantalert.eventId,2)+0"
20282056
" AND (%d OR eventId NOT GLOB 'f*')"
2057
+ " AND (%d OR wantalert.edited=false)"
20292058
" ORDER BY event.mtime",
2030
- doDigest
2059
+ doDigest,
2060
+ !alert_omit_edited
20312061
);
20322062
memset(&anchor, 0, sizeof(anchor));
20332063
pLast = &anchor;
20342064
*pnEvent = 0;
20352065
while( db_step(&q)==SQLITE_ROW ){
@@ -2037,10 +2067,15 @@
20372067
p = fossil_malloc( sizeof(EmailEvent) );
20382068
pLast->pNext = p;
20392069
pLast = p;
20402070
p->type = db_column_text(&q, 3)[0];
20412071
p->needMod = db_column_int(&q, 4);
2072
+ /* For forum posts in a digest, the "edited=false" above will have prevented
2073
+ ** them being included in the result-set. For non-forum posts, set p->edited
2074
+ ** to 0 so they are processed as normal.
2075
+ */
2076
+ p->edited = 0;
20422077
p->zFromName = 0;
20432078
p->pNext = 0;
20442079
switch( p->type ){
20452080
case 'c': zType = "Check-In"; break;
20462081
case 'f': zType = "Forum post"; break;
@@ -2086,11 +2121,12 @@
20862121
" (SELECT uuid FROM blob WHERE rid=forumpost.fpid)," /* 1 */
20872122
" datetime(event.mtime)," /* 2 */
20882123
" substr(comment,instr(comment,':')+2)," /* 3 */
20892124
" (SELECT uuid FROM blob WHERE rid=forumpost.firt)," /* 4 */
20902125
" wantalert.needMod," /* 5 */
2091
- " coalesce(trim(substr(info,1,instr(info,'<')-1)),euser,user)" /* 6 */
2126
+ " coalesce(trim(substr(info,1,instr(info,'<')-1)),euser,user)," /* 6 */
2127
+ " wantalert.edited" /* 7 */
20922128
" FROM temp.wantalert, event, forumpost"
20932129
" LEFT JOIN user ON (login=coalesce(euser,user))"
20942130
" WHERE event.objid=substr(wantalert.eventId,2)+0"
20952131
" AND eventId GLOB 'f*'"
20962132
" AND forumpost.fpid=event.objid"
@@ -2109,10 +2145,11 @@
21092145
pLast->pNext = p;
21102146
pLast = p;
21112147
p->type = 'f';
21122148
p->needMod = db_column_int(&q, 5);
21132149
z = db_column_text(&q,6);
2150
+ p->edited = db_column_int(&q, 7);
21142151
p->zFromName = z && z[0] ? fossil_strdup(z) : 0;
21152152
p->pNext = 0;
21162153
blob_init(&p->hdr, 0, 0);
21172154
zUuid = db_column_text(&q, 1);
21182155
zTitle = db_column_text(&q, 3);
@@ -2198,19 +2235,21 @@
21982235
needMod = find_option("needmod",0,0)!=0;
21992236
db_find_and_open_repository(0, 0);
22002237
verify_all_options();
22012238
db_begin_transaction();
22022239
alert_schema(0);
2203
- db_multi_exec("CREATE TEMP TABLE wantalert(eventid TEXT, needMod BOOLEAN)");
2240
+ db_multi_exec("CREATE TEMP TABLE wantalert(eventid TEXT, needMod BOOLEAN,"
2241
+ "edited BOOLEAN)");
22042242
if( g.argc==2 ){
22052243
db_multi_exec(
2206
- "INSERT INTO wantalert(eventId,needMod)"
2207
- " SELECT eventid, %d FROM pending_alert", needMod);
2244
+ "INSERT INTO wantalert(eventId,needMod,edited)"
2245
+ " SELECT eventid, %d, 0 FROM pending_alert", needMod);
22082246
}else{
22092247
int i;
22102248
for(i=2; i<g.argc; i++){
2211
- db_multi_exec("INSERT INTO wantalert(eventId,needMod) VALUES(%Q,%d)",
2249
+ db_multi_exec("INSERT INTO wantalert(eventId,needMod,edited)"
2250
+ " VALUES(%Q,%d,0)",
22122251
g.argv[i], needMod);
22132252
}
22142253
}
22152254
blob_init(&out, 0, 0);
22162255
email_header(&out);
@@ -2303,10 +2342,18 @@
23032342
** (1) Create a TEMP table wantalert(eventId,needMod) and fill it with
23042343
** all the events that we want to send alerts about. The needMod
23052344
** flags is set if and only if the event is still awaiting
23062345
** moderator approval. Events with the needMod flag are only
23072346
** shown to users that have moderator privileges.
2347
+**
2348
+** (1b) For forum posts, mark those that have been edited so we can
2349
+** avoid notifications for out-of-date posts, if so configured.
2350
+**
2351
+** (1c) Purge forum-post entries from wantalert if not enough time
2352
+** has passed since creation (and, optionally, if they have not
2353
+** been replied to). This gives an opportunity for "oops I made
2354
+** a typo" to be corrected before people are notified.
23082355
**
23092356
** (2) Call alert_compute_event_text() to compute a list of EmailEvent
23102357
** objects that describe all events about which we want to send
23112358
** alerts.
23122359
**
@@ -2335,10 +2382,13 @@
23352382
const char *zRepoName;
23362383
const char *zFrom;
23372384
const char *zDest = (flags & SENDALERT_STDOUT) ? "stdout" : 0;
23382385
AlertSender *pSender = 0;
23392386
u32 senderFlags = 0;
2387
+ const int alert_omit_edited = db_get_int("alert-omit-edited", 0);
2388
+ const int alert_edit_window = db_get_int("alert-edit-window", 0);
2389
+ const int alert_notify_on_reply = db_get_int("alert-notify-on-reply", 0);
23402390
23412391
if( g.fSqlTrace ) fossil_trace("-- BEGIN alert_send_alerts(%u)\n", flags);
23422392
alert_schema(0);
23432393
if( !alert_enabled() ) goto send_alert_done;
23442394
zUrl = db_get("email-url",0);
@@ -2354,35 +2404,88 @@
23542404
23552405
/* Step (1): Compute the alerts that need sending
23562406
*/
23572407
db_multi_exec(
23582408
"DROP TABLE IF EXISTS temp.wantalert;"
2359
- "CREATE TEMP TABLE wantalert(eventId TEXT, needMod BOOLEAN, sentMod);"
2409
+ "CREATE TEMP TABLE wantalert(eventId TEXT, needMod BOOLEAN, sentMod,"
2410
+ " edited BOOLEAN);"
23602411
);
23612412
if( flags & SENDALERT_DIGEST ){
23622413
/* Unmoderated changes are never sent as part of a digest */
23632414
db_multi_exec(
2364
- "INSERT INTO wantalert(eventId,needMod)"
2365
- " SELECT eventid, 0"
2415
+ "INSERT INTO wantalert(eventId,needMod,edited)"
2416
+ " SELECT eventid, 0, 0"
23662417
" FROM pending_alert"
23672418
" WHERE sentDigest IS FALSE"
23682419
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2));"
23692420
);
23702421
zDigest = "true";
23712422
}else{
23722423
/* Immediate alerts might include events that are subject to
23732424
** moderator approval */
23742425
db_multi_exec(
2375
- "INSERT INTO wantalert(eventId,needMod,sentMod)"
2426
+ "INSERT INTO wantalert(eventId,needMod,sentMod,edited)"
23762427
" SELECT eventid,"
23772428
" EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2)),"
2378
- " sentMod"
2429
+ " sentMod,0"
23792430
" FROM pending_alert"
23802431
" WHERE sentSep IS FALSE;"
23812432
"DELETE FROM wantalert WHERE needMod AND sentMod;"
23822433
);
23832434
}
2435
+
2436
+ /* Step 1b
2437
+ ** Mark all entries as "edited" if a forum-post ("f...") and the id (after
2438
+ ** the "f") appears in the 'fprev' field of a 'forumpost' record. If
2439
+ ** 'alert-omit-edited' is enabled, notifications for such entries will NOT be
2440
+ ** generated, but the entries WILL be marked as 'sentSep' or 'sepDigest'.
2441
+ **
2442
+ ** Step 1c
2443
+ ** Delete any entry that matchs all the following:
2444
+ ** a. Is a forum-post and the 'fmtime' entry from 'forumpost' is less than
2445
+ ** 'alert-edit-window' minutes in the past.
2446
+ ** b. Either 'alert-notift-on-reply' is turned off OR there is no reply to
2447
+ ** this post.
2448
+ ** c. Does not require approval.
2449
+ ** Entries matching all the above are removed from 'wantalert' so the original
2450
+ ** entries in 'pending_alert' will NOT be marked as sent/deleted.
2451
+ */
2452
+ db_multi_exec(
2453
+ "UPDATE wantalert SET edited=1"
2454
+ " WHERE EXISTS ("
2455
+ " SELECT 1"
2456
+ " FROM forumpost"
2457
+ " WHERE substr(eventid,1,1)='f' AND fprev=substr(eventid,2)"
2458
+ " );"
2459
+ "DELETE FROM wantalert"
2460
+ " WHERE ( SELECT fmtime > julianday('now', '-%d minutes')"
2461
+ " FROM forumpost"
2462
+ " WHERE substr(eventid,1,1)='f' AND fpid=substr(eventid,2)"
2463
+ " )"
2464
+ " AND ( %d OR NOT EXISTS ("
2465
+ " SELECT 1"
2466
+ " FROM forumpost"
2467
+ " WHERE substr(eventid,1,1)='f' AND firt=substr(eventid,2)"
2468
+ " )"
2469
+ " )"
2470
+ " AND NOT needMod;",
2471
+ alert_edit_window,
2472
+ 1-alert_notify_on_reply
2473
+ );
2474
+
2475
+ if( g.fSqlTrace ) {
2476
+ db_prepare(&q, "SELECT eventid, needMod, sentMod, edited FROM wantalert" ) ;
2477
+ fossil_trace( "%10s %10s %10s %10s\n", "EventID", "NeedMod", "SentMod", "Edited" );
2478
+ while( db_step(&q)==SQLITE_ROW ){
2479
+ const char* eventid = db_column_text( &q, 0 ) ;
2480
+ const char* needMod = db_column_text( &q, 1 ) ;
2481
+ const char* sentMod = db_column_text( &q, 2 ) ;
2482
+ const char* edited = db_column_text( &q, 3 ) ;
2483
+ fossil_trace( "%10s %10s %10s %10s\n", eventid, needMod, sentMod, edited );
2484
+ }
2485
+ db_finalize(&q);
2486
+ }
23842487
23852488
/* Step 2: compute EmailEvent objects for every notification that
23862489
** needs sending.
23872490
*/
23882491
pEvents = alert_compute_event_text(&nEvent, (flags & SENDALERT_DIGEST)!=0);
@@ -2459,10 +2562,16 @@
24592562
case 't': xType = 'r'; break;
24602563
case 'w': xType = 'j'; break;
24612564
}
24622565
if( strchr(zCap,xType)==0 ) continue;
24632566
}
2567
+ /* If 'alert-omit-edited' is enabled, and the current entry
2568
+ ** has been edited, skip it. This potentially could be made
2569
+ ** the subject of a user-specific setting.
2570
+ */
2571
+ if( alert_omit_edited && p->edited ) continue;
2572
+
24642573
if( blob_size(&p->hdr)>0 ){
24652574
/* This alert should be sent as a separate email */
24662575
Blob fhdr, fbody;
24672576
blob_init(&fhdr, 0, 0);
24682577
blob_appendf(&fhdr, "To: <%s>\r\n", zEmail);
24692578
--- src/alerts.c
+++ src/alerts.c
@@ -303,10 +303,36 @@
303 "eadmin", "", 0);
304 @ <p>This is the email for the human administrator for the system.
305 @ Abuse and trouble reports are send here.
306 @ (Property: "email-admin")</p>
307 @ <hr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
309 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
310 @ </div></form>
311 db_end_transaction(0);
312 style_footer();
@@ -1967,10 +1993,11 @@
1967 int type; /* 'c', 'f', 'm', 't', 'w' */
1968 int needMod; /* Pending moderator approval */
1969 Blob hdr; /* Header content, for forum entries */
1970 Blob txt; /* Text description to appear in an alert */
1971 char *zFromName; /* Human name of the sender */
 
1972 EmailEvent *pNext; /* Next in chronological order */
1973 };
1974 #endif
1975
1976 /*
@@ -2000,10 +2027,11 @@
2000 EmailEvent anchor;
2001 EmailEvent *pLast;
2002 const char *zUrl = db_get("email-url","http://localhost:8080");
2003 const char *zFrom;
2004 const char *zSub;
 
2005
2006
2007 /* First do non-forum post events */
2008 db_prepare(&q,
2009 "SELECT"
@@ -2024,12 +2052,14 @@
2024 " wantalert.needMod" /* 4 */
2025 " FROM temp.wantalert, event, blob"
2026 " WHERE blob.rid=event.objid"
2027 " AND event.objid=substr(wantalert.eventId,2)+0"
2028 " AND (%d OR eventId NOT GLOB 'f*')"
 
2029 " ORDER BY event.mtime",
2030 doDigest
 
2031 );
2032 memset(&anchor, 0, sizeof(anchor));
2033 pLast = &anchor;
2034 *pnEvent = 0;
2035 while( db_step(&q)==SQLITE_ROW ){
@@ -2037,10 +2067,15 @@
2037 p = fossil_malloc( sizeof(EmailEvent) );
2038 pLast->pNext = p;
2039 pLast = p;
2040 p->type = db_column_text(&q, 3)[0];
2041 p->needMod = db_column_int(&q, 4);
 
 
 
 
 
2042 p->zFromName = 0;
2043 p->pNext = 0;
2044 switch( p->type ){
2045 case 'c': zType = "Check-In"; break;
2046 case 'f': zType = "Forum post"; break;
@@ -2086,11 +2121,12 @@
2086 " (SELECT uuid FROM blob WHERE rid=forumpost.fpid)," /* 1 */
2087 " datetime(event.mtime)," /* 2 */
2088 " substr(comment,instr(comment,':')+2)," /* 3 */
2089 " (SELECT uuid FROM blob WHERE rid=forumpost.firt)," /* 4 */
2090 " wantalert.needMod," /* 5 */
2091 " coalesce(trim(substr(info,1,instr(info,'<')-1)),euser,user)" /* 6 */
 
2092 " FROM temp.wantalert, event, forumpost"
2093 " LEFT JOIN user ON (login=coalesce(euser,user))"
2094 " WHERE event.objid=substr(wantalert.eventId,2)+0"
2095 " AND eventId GLOB 'f*'"
2096 " AND forumpost.fpid=event.objid"
@@ -2109,10 +2145,11 @@
2109 pLast->pNext = p;
2110 pLast = p;
2111 p->type = 'f';
2112 p->needMod = db_column_int(&q, 5);
2113 z = db_column_text(&q,6);
 
2114 p->zFromName = z && z[0] ? fossil_strdup(z) : 0;
2115 p->pNext = 0;
2116 blob_init(&p->hdr, 0, 0);
2117 zUuid = db_column_text(&q, 1);
2118 zTitle = db_column_text(&q, 3);
@@ -2198,19 +2235,21 @@
2198 needMod = find_option("needmod",0,0)!=0;
2199 db_find_and_open_repository(0, 0);
2200 verify_all_options();
2201 db_begin_transaction();
2202 alert_schema(0);
2203 db_multi_exec("CREATE TEMP TABLE wantalert(eventid TEXT, needMod BOOLEAN)");
 
2204 if( g.argc==2 ){
2205 db_multi_exec(
2206 "INSERT INTO wantalert(eventId,needMod)"
2207 " SELECT eventid, %d FROM pending_alert", needMod);
2208 }else{
2209 int i;
2210 for(i=2; i<g.argc; i++){
2211 db_multi_exec("INSERT INTO wantalert(eventId,needMod) VALUES(%Q,%d)",
 
2212 g.argv[i], needMod);
2213 }
2214 }
2215 blob_init(&out, 0, 0);
2216 email_header(&out);
@@ -2303,10 +2342,18 @@
2303 ** (1) Create a TEMP table wantalert(eventId,needMod) and fill it with
2304 ** all the events that we want to send alerts about. The needMod
2305 ** flags is set if and only if the event is still awaiting
2306 ** moderator approval. Events with the needMod flag are only
2307 ** shown to users that have moderator privileges.
 
 
 
 
 
 
 
 
2308 **
2309 ** (2) Call alert_compute_event_text() to compute a list of EmailEvent
2310 ** objects that describe all events about which we want to send
2311 ** alerts.
2312 **
@@ -2335,10 +2382,13 @@
2335 const char *zRepoName;
2336 const char *zFrom;
2337 const char *zDest = (flags & SENDALERT_STDOUT) ? "stdout" : 0;
2338 AlertSender *pSender = 0;
2339 u32 senderFlags = 0;
 
 
 
2340
2341 if( g.fSqlTrace ) fossil_trace("-- BEGIN alert_send_alerts(%u)\n", flags);
2342 alert_schema(0);
2343 if( !alert_enabled() ) goto send_alert_done;
2344 zUrl = db_get("email-url",0);
@@ -2354,35 +2404,88 @@
2354
2355 /* Step (1): Compute the alerts that need sending
2356 */
2357 db_multi_exec(
2358 "DROP TABLE IF EXISTS temp.wantalert;"
2359 "CREATE TEMP TABLE wantalert(eventId TEXT, needMod BOOLEAN, sentMod);"
 
2360 );
2361 if( flags & SENDALERT_DIGEST ){
2362 /* Unmoderated changes are never sent as part of a digest */
2363 db_multi_exec(
2364 "INSERT INTO wantalert(eventId,needMod)"
2365 " SELECT eventid, 0"
2366 " FROM pending_alert"
2367 " WHERE sentDigest IS FALSE"
2368 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2));"
2369 );
2370 zDigest = "true";
2371 }else{
2372 /* Immediate alerts might include events that are subject to
2373 ** moderator approval */
2374 db_multi_exec(
2375 "INSERT INTO wantalert(eventId,needMod,sentMod)"
2376 " SELECT eventid,"
2377 " EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2)),"
2378 " sentMod"
2379 " FROM pending_alert"
2380 " WHERE sentSep IS FALSE;"
2381 "DELETE FROM wantalert WHERE needMod AND sentMod;"
2382 );
2383 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2384
2385 /* Step 2: compute EmailEvent objects for every notification that
2386 ** needs sending.
2387 */
2388 pEvents = alert_compute_event_text(&nEvent, (flags & SENDALERT_DIGEST)!=0);
@@ -2459,10 +2562,16 @@
2459 case 't': xType = 'r'; break;
2460 case 'w': xType = 'j'; break;
2461 }
2462 if( strchr(zCap,xType)==0 ) continue;
2463 }
 
 
 
 
 
 
2464 if( blob_size(&p->hdr)>0 ){
2465 /* This alert should be sent as a separate email */
2466 Blob fhdr, fbody;
2467 blob_init(&fhdr, 0, 0);
2468 blob_appendf(&fhdr, "To: <%s>\r\n", zEmail);
2469
--- src/alerts.c
+++ src/alerts.c
@@ -303,10 +303,36 @@
303 "eadmin", "", 0);
304 @ <p>This is the email for the human administrator for the system.
305 @ Abuse and trouble reports are send here.
306 @ (Property: "email-admin")</p>
307 @ <hr>
308
309 onoff_attribute("Omit alerts for edited forum posts",
310 "alert-omit-edited", "alert-omit-edited", 1, 0 ) ;
311
312 @ <p>If enabled, notifications will only be sent for the latest
313 @ versions of edited forum posts. If disabled, notifications will
314 @ be sent for all versions. Applies to both individual and digest
315 @ notifications.</p>
316
317 entry_attribute("Grace period in minutes allowed for editing", 5,
318 "alert-edit-window", "alert-edit-window", "5", 0 ) ;
319
320 @ <p>Number of minutes grace allowed for just-posted forum topics
321 @ during which notifications will be sent. This is to reduce the
322 @ number of alerts if someone edits a post shortly after posting.
323 @ Set to zero to disable this feature.</p>
324
325 onoff_attribute("Notify immediately if replied-to",
326 "alert-notify-on-reply", "alert-notify-on-reply", 1, 0 ) ;
327
328 @ <p>If enabled, and a forum post has been replied-to, send
329 @ notifications immediately, even if the "grace period" has not
330 @ expired. If disabled, notifications for replied-to posts will
331 @ not be sent until the grace-period has expired. Does not affect
332 @ the handling of the reply itself.</p>
333 @ <hr>
334
335 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
336 @ </div></form>
337 db_end_transaction(0);
338 style_footer();
@@ -1967,10 +1993,11 @@
1993 int type; /* 'c', 'f', 'm', 't', 'w' */
1994 int needMod; /* Pending moderator approval */
1995 Blob hdr; /* Header content, for forum entries */
1996 Blob txt; /* Text description to appear in an alert */
1997 char *zFromName; /* Human name of the sender */
1998 int edited; /* Forum post has been edited */
1999 EmailEvent *pNext; /* Next in chronological order */
2000 };
2001 #endif
2002
2003 /*
@@ -2000,10 +2027,11 @@
2027 EmailEvent anchor;
2028 EmailEvent *pLast;
2029 const char *zUrl = db_get("email-url","http://localhost:8080");
2030 const char *zFrom;
2031 const char *zSub;
2032 const int alert_omit_edited = db_get_int("alert-omit-edited",0);
2033
2034
2035 /* First do non-forum post events */
2036 db_prepare(&q,
2037 "SELECT"
@@ -2024,12 +2052,14 @@
2052 " wantalert.needMod" /* 4 */
2053 " FROM temp.wantalert, event, blob"
2054 " WHERE blob.rid=event.objid"
2055 " AND event.objid=substr(wantalert.eventId,2)+0"
2056 " AND (%d OR eventId NOT GLOB 'f*')"
2057 " AND (%d OR wantalert.edited=false)"
2058 " ORDER BY event.mtime",
2059 doDigest,
2060 !alert_omit_edited
2061 );
2062 memset(&anchor, 0, sizeof(anchor));
2063 pLast = &anchor;
2064 *pnEvent = 0;
2065 while( db_step(&q)==SQLITE_ROW ){
@@ -2037,10 +2067,15 @@
2067 p = fossil_malloc( sizeof(EmailEvent) );
2068 pLast->pNext = p;
2069 pLast = p;
2070 p->type = db_column_text(&q, 3)[0];
2071 p->needMod = db_column_int(&q, 4);
2072 /* For forum posts in a digest, the "edited=false" above will have prevented
2073 ** them being included in the result-set. For non-forum posts, set p->edited
2074 ** to 0 so they are processed as normal.
2075 */
2076 p->edited = 0;
2077 p->zFromName = 0;
2078 p->pNext = 0;
2079 switch( p->type ){
2080 case 'c': zType = "Check-In"; break;
2081 case 'f': zType = "Forum post"; break;
@@ -2086,11 +2121,12 @@
2121 " (SELECT uuid FROM blob WHERE rid=forumpost.fpid)," /* 1 */
2122 " datetime(event.mtime)," /* 2 */
2123 " substr(comment,instr(comment,':')+2)," /* 3 */
2124 " (SELECT uuid FROM blob WHERE rid=forumpost.firt)," /* 4 */
2125 " wantalert.needMod," /* 5 */
2126 " coalesce(trim(substr(info,1,instr(info,'<')-1)),euser,user)," /* 6 */
2127 " wantalert.edited" /* 7 */
2128 " FROM temp.wantalert, event, forumpost"
2129 " LEFT JOIN user ON (login=coalesce(euser,user))"
2130 " WHERE event.objid=substr(wantalert.eventId,2)+0"
2131 " AND eventId GLOB 'f*'"
2132 " AND forumpost.fpid=event.objid"
@@ -2109,10 +2145,11 @@
2145 pLast->pNext = p;
2146 pLast = p;
2147 p->type = 'f';
2148 p->needMod = db_column_int(&q, 5);
2149 z = db_column_text(&q,6);
2150 p->edited = db_column_int(&q, 7);
2151 p->zFromName = z && z[0] ? fossil_strdup(z) : 0;
2152 p->pNext = 0;
2153 blob_init(&p->hdr, 0, 0);
2154 zUuid = db_column_text(&q, 1);
2155 zTitle = db_column_text(&q, 3);
@@ -2198,19 +2235,21 @@
2235 needMod = find_option("needmod",0,0)!=0;
2236 db_find_and_open_repository(0, 0);
2237 verify_all_options();
2238 db_begin_transaction();
2239 alert_schema(0);
2240 db_multi_exec("CREATE TEMP TABLE wantalert(eventid TEXT, needMod BOOLEAN,"
2241 "edited BOOLEAN)");
2242 if( g.argc==2 ){
2243 db_multi_exec(
2244 "INSERT INTO wantalert(eventId,needMod,edited)"
2245 " SELECT eventid, %d, 0 FROM pending_alert", needMod);
2246 }else{
2247 int i;
2248 for(i=2; i<g.argc; i++){
2249 db_multi_exec("INSERT INTO wantalert(eventId,needMod,edited)"
2250 " VALUES(%Q,%d,0)",
2251 g.argv[i], needMod);
2252 }
2253 }
2254 blob_init(&out, 0, 0);
2255 email_header(&out);
@@ -2303,10 +2342,18 @@
2342 ** (1) Create a TEMP table wantalert(eventId,needMod) and fill it with
2343 ** all the events that we want to send alerts about. The needMod
2344 ** flags is set if and only if the event is still awaiting
2345 ** moderator approval. Events with the needMod flag are only
2346 ** shown to users that have moderator privileges.
2347 **
2348 ** (1b) For forum posts, mark those that have been edited so we can
2349 ** avoid notifications for out-of-date posts, if so configured.
2350 **
2351 ** (1c) Purge forum-post entries from wantalert if not enough time
2352 ** has passed since creation (and, optionally, if they have not
2353 ** been replied to). This gives an opportunity for "oops I made
2354 ** a typo" to be corrected before people are notified.
2355 **
2356 ** (2) Call alert_compute_event_text() to compute a list of EmailEvent
2357 ** objects that describe all events about which we want to send
2358 ** alerts.
2359 **
@@ -2335,10 +2382,13 @@
2382 const char *zRepoName;
2383 const char *zFrom;
2384 const char *zDest = (flags & SENDALERT_STDOUT) ? "stdout" : 0;
2385 AlertSender *pSender = 0;
2386 u32 senderFlags = 0;
2387 const int alert_omit_edited = db_get_int("alert-omit-edited", 0);
2388 const int alert_edit_window = db_get_int("alert-edit-window", 0);
2389 const int alert_notify_on_reply = db_get_int("alert-notify-on-reply", 0);
2390
2391 if( g.fSqlTrace ) fossil_trace("-- BEGIN alert_send_alerts(%u)\n", flags);
2392 alert_schema(0);
2393 if( !alert_enabled() ) goto send_alert_done;
2394 zUrl = db_get("email-url",0);
@@ -2354,35 +2404,88 @@
2404
2405 /* Step (1): Compute the alerts that need sending
2406 */
2407 db_multi_exec(
2408 "DROP TABLE IF EXISTS temp.wantalert;"
2409 "CREATE TEMP TABLE wantalert(eventId TEXT, needMod BOOLEAN, sentMod,"
2410 " edited BOOLEAN);"
2411 );
2412 if( flags & SENDALERT_DIGEST ){
2413 /* Unmoderated changes are never sent as part of a digest */
2414 db_multi_exec(
2415 "INSERT INTO wantalert(eventId,needMod,edited)"
2416 " SELECT eventid, 0, 0"
2417 " FROM pending_alert"
2418 " WHERE sentDigest IS FALSE"
2419 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2));"
2420 );
2421 zDigest = "true";
2422 }else{
2423 /* Immediate alerts might include events that are subject to
2424 ** moderator approval */
2425 db_multi_exec(
2426 "INSERT INTO wantalert(eventId,needMod,sentMod,edited)"
2427 " SELECT eventid,"
2428 " EXISTS(SELECT 1 FROM private WHERE rid=substr(eventid,2)),"
2429 " sentMod,0"
2430 " FROM pending_alert"
2431 " WHERE sentSep IS FALSE;"
2432 "DELETE FROM wantalert WHERE needMod AND sentMod;"
2433 );
2434 }
2435
2436 /* Step 1b
2437 ** Mark all entries as "edited" if a forum-post ("f...") and the id (after
2438 ** the "f") appears in the 'fprev' field of a 'forumpost' record. If
2439 ** 'alert-omit-edited' is enabled, notifications for such entries will NOT be
2440 ** generated, but the entries WILL be marked as 'sentSep' or 'sepDigest'.
2441 **
2442 ** Step 1c
2443 ** Delete any entry that matchs all the following:
2444 ** a. Is a forum-post and the 'fmtime' entry from 'forumpost' is less than
2445 ** 'alert-edit-window' minutes in the past.
2446 ** b. Either 'alert-notift-on-reply' is turned off OR there is no reply to
2447 ** this post.
2448 ** c. Does not require approval.
2449 ** Entries matching all the above are removed from 'wantalert' so the original
2450 ** entries in 'pending_alert' will NOT be marked as sent/deleted.
2451 */
2452 db_multi_exec(
2453 "UPDATE wantalert SET edited=1"
2454 " WHERE EXISTS ("
2455 " SELECT 1"
2456 " FROM forumpost"
2457 " WHERE substr(eventid,1,1)='f' AND fprev=substr(eventid,2)"
2458 " );"
2459 "DELETE FROM wantalert"
2460 " WHERE ( SELECT fmtime > julianday('now', '-%d minutes')"
2461 " FROM forumpost"
2462 " WHERE substr(eventid,1,1)='f' AND fpid=substr(eventid,2)"
2463 " )"
2464 " AND ( %d OR NOT EXISTS ("
2465 " SELECT 1"
2466 " FROM forumpost"
2467 " WHERE substr(eventid,1,1)='f' AND firt=substr(eventid,2)"
2468 " )"
2469 " )"
2470 " AND NOT needMod;",
2471 alert_edit_window,
2472 1-alert_notify_on_reply
2473 );
2474
2475 if( g.fSqlTrace ) {
2476 db_prepare(&q, "SELECT eventid, needMod, sentMod, edited FROM wantalert" ) ;
2477 fossil_trace( "%10s %10s %10s %10s\n", "EventID", "NeedMod", "SentMod", "Edited" );
2478 while( db_step(&q)==SQLITE_ROW ){
2479 const char* eventid = db_column_text( &q, 0 ) ;
2480 const char* needMod = db_column_text( &q, 1 ) ;
2481 const char* sentMod = db_column_text( &q, 2 ) ;
2482 const char* edited = db_column_text( &q, 3 ) ;
2483 fossil_trace( "%10s %10s %10s %10s\n", eventid, needMod, sentMod, edited );
2484 }
2485 db_finalize(&q);
2486 }
2487
2488 /* Step 2: compute EmailEvent objects for every notification that
2489 ** needs sending.
2490 */
2491 pEvents = alert_compute_event_text(&nEvent, (flags & SENDALERT_DIGEST)!=0);
@@ -2459,10 +2562,16 @@
2562 case 't': xType = 'r'; break;
2563 case 'w': xType = 'j'; break;
2564 }
2565 if( strchr(zCap,xType)==0 ) continue;
2566 }
2567 /* If 'alert-omit-edited' is enabled, and the current entry
2568 ** has been edited, skip it. This potentially could be made
2569 ** the subject of a user-specific setting.
2570 */
2571 if( alert_omit_edited && p->edited ) continue;
2572
2573 if( blob_size(&p->hdr)>0 ){
2574 /* This alert should be sent as a separate email */
2575 Blob fhdr, fbody;
2576 blob_init(&fhdr, 0, 0);
2577 blob_appendf(&fhdr, "To: <%s>\r\n", zEmail);
2578

Keyboard Shortcuts

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