Fossil SCM

Add logic to generate the text of email alert messages.

drh 2018-06-22 15:34 UTC email-alerts
Commit bb30d02efdb768b424b05efa50649bfba11b0e447ce78f36bd21b099a017c912
1 file changed +151 -8
+151 -8
--- src/email.c
+++ src/email.c
@@ -166,16 +166,46 @@
166166
email_subscriber_list_link();
167167
style_header("Email Notification Setup");
168168
@ <form action="%R/setup_email" method="post"><div>
169169
@ <input type="submit" name="submit" value="Apply Changes" /><hr>
170170
login_insert_csrf_secret();
171
+
172
+ entry_attribute("Canonical Server URL", 40, "email-url",
173
+ "eurl", "", 0);
174
+ @ <p><b>Required.</b>
175
+ @ This is URL used as the basename for hyperlinks included in
176
+ @ email alert text. Omit the trailing "/".
177
+ @ Suggested value: "%h(g.zBaseURL)"
178
+ @ (Property: "email-url")</p>
179
+ @ <hr>
180
+
181
+ entry_attribute("\"From\" email address", 20, "email-self",
182
+ "eself", "", 0);
183
+ @ <p><b>Required.</b>
184
+ @ This is the email from which email notifications are sent. The
185
+ @ system administrator should arrange for emails sent to this address
186
+ @ to be handed off to the "fossil email incoming" command so that Fossil
187
+ @ can handle bounces. (Property: "email-self")</p>
188
+ @ <hr>
189
+
190
+ entry_attribute("Repository Nickname", 16, "email-subname",
191
+ "enn", "", 0);
192
+ @ <p><b>Required.</b>
193
+ @ This is short name used to identifies the repository in the
194
+ @ Subject: line of email alerts. Traditionally this name is
195
+ @ included in square brackets. Examples: "[fossil-src]", "[sqlite-src]".
196
+ @ (Property: "email-subname")</p>
197
+ @ <hr>
198
+
171199
multiple_choice_attribute("Email Send Method", "email-send-method", "esm",
172200
"off", count(azSendMethods)/2, azSendMethods);
173201
@ <p>How to send email. The "Pipe to a command"
174202
@ method is the usual choice in production.
175203
@ (Property: "email-send-method")</p>
176204
@ <hr>
205
+
206
+
177207
entry_attribute("Command To Pipe Email To", 80, "email-send-command",
178208
"ecmd", "sendmail -t", 0);
179209
@ <p>When the send method is "pipe to a command", this is the command
180210
@ that is run. Email messages are piped into the standard input of this
181211
@ command. The command is expected to extract the sender address,
@@ -193,18 +223,10 @@
193223
@ <p>When the send method is "store in a directory", each email message is
194224
@ stored as a separate file in the directory shown here.
195225
@ (Property: "email-send-dir")</p>
196226
@ <hr>
197227
198
- entry_attribute("\"From\" email address", 40, "email-self",
199
- "eself", "", 0);
200
- @ <p>This is the email from which email notifications are sent. The
201
- @ system administrator should arrange for emails sent to this address
202
- @ to be handed off to the "fossil email incoming" command so that Fossil
203
- @ can handle bounces. (Property: "email-self")</p>
204
- @ <hr>
205
-
206228
entry_attribute("Administrator email address", 40, "email-admin",
207229
"eadmin", "", 0);
208230
@ <p>This is the email for the human administrator for the system.
209231
@ Abuse and trouble reports are send here.
210232
@ (Property: "email-admin")</p>
@@ -1213,5 +1235,126 @@
12131235
}
12141236
@ </table>
12151237
db_finalize(&q);
12161238
style_footer();
12171239
}
1240
+
1241
+#if LOCAL_INTERFACE
1242
+/* Allowed values for the mAlert flags parameter to email_alert_text
1243
+*/
1244
+#define ALERT_HTML 0x01 /* Generate HTML instead of plain text */
1245
+#endif
1246
+
1247
+/*
1248
+** Append the text for a single alert to the end of pOut
1249
+*/
1250
+void email_one_alert(const char *zEvent, u32 mAlert, Blob *pOut){
1251
+ static Stmt q;
1252
+ int id;
1253
+ const char *zType = "";
1254
+ db_static_prepare(&q,
1255
+ "SELECT"
1256
+ " blob.uuid," /* 0 */
1257
+ " datetime(event.mtime)," /* 1 */
1258
+ " coalesce(ecomment,comment)"
1259
+ " || ' (user: ' || coalesce(euser,user,'?')"
1260
+ " || (SELECT case when length(x)>0 then ' tags: ' || x else '' end"
1261
+ " FROM (SELECT group_concat(substr(tagname,5), ', ') AS x"
1262
+ " FROM tag, tagxref"
1263
+ " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
1264
+ " AND tagxref.rid=blob.rid AND tagxref.tagtype>0))"
1265
+ " || ')' as comment," /* 2 */
1266
+ " tagxref.value AS branch" /* 3 */
1267
+ " FROM tag CROSS JOIN event CROSS JOIN blob"
1268
+ " LEFT JOIN tagxref ON tagxref.tagid=tag.tagid"
1269
+ " AND tagxref.tagtype>0"
1270
+ " AND tagxref.rid=blob.rid"
1271
+ " WHERE blob.rid=event.objid"
1272
+ " AND tag.tagname='branch'"
1273
+ " AND event.objid=:objid"
1274
+ );
1275
+ switch( zEvent[0] ){
1276
+ case 'c': zType = "Check-In"; break;
1277
+ case 't': zType = "Wiki Edit"; break;
1278
+ case 'w': zType = "Ticket Change"; break;
1279
+ default: return;
1280
+ }
1281
+ id = atoi(zEvent+1);
1282
+ if( id<=0 ) return;
1283
+ db_bind_int(&q, ":objid", id);
1284
+ if( db_step(&q)==SQLITE_ROW ){
1285
+ blob_appendf(pOut,"\n== %s %s ==\n%s\n%s/info/%.20s\n",
1286
+ db_column_text(&q,1),
1287
+ zType,
1288
+ db_column_text(&q,2),
1289
+ db_get("email-url","http://localhost:8080"),
1290
+ db_column_text(&q,0)
1291
+ );
1292
+ }
1293
+ db_reset(&q);
1294
+}
1295
+
1296
+/*
1297
+** Put a header on an alert email
1298
+*/
1299
+void email_header(u32 mAlert, Blob *pOut){
1300
+ blob_appendf(pOut,
1301
+ "This is an automated email reporting changes "
1302
+ "on Fossil repository %s (%s/timeline)\n",
1303
+ db_get("email-subname","(unknown)"),
1304
+ db_get("email-url","http://localhost:8080"));
1305
+}
1306
+
1307
+/*
1308
+** Append the "unsubscribe" notification and other footer text to
1309
+** the end of an email alert being assemblied in pOut.
1310
+*/
1311
+void email_footer(u32 mAlert, Blob *pOut){
1312
+ blob_appendf(pOut, "\n%.72c\nTo unsubscribe: %s/unsubscribe\n",
1313
+ '-', db_get("email-url","http://localhost:8080"));
1314
+}
1315
+
1316
+/*
1317
+** COMMAND: test-generate-alert
1318
+**
1319
+** Usage: %fossil test-generate-alert [--html] [--actual] EVENTID ...
1320
+**
1321
+** Generate the text of an email alert for all of the EVENTIDs
1322
+** listed on the command-line. Write that text to standard
1323
+** output. If the --actual flag is present, then the EVENTIDs are
1324
+** the actual event-ids in the pending_alert table.
1325
+**
1326
+** This command is intended for testing and debugging the logic
1327
+** that generates email alert text.
1328
+**
1329
+** The mimetype is text/plain by default. Use the --html option
1330
+** to generate text/html alert text.
1331
+*/
1332
+void test_generate_alert_cmd(void){
1333
+ u32 mAlert = 0;
1334
+ int bActual = find_option("actual",0,0)!=0;
1335
+ Blob out;
1336
+ int i;
1337
+
1338
+ if( find_option("html",0,0)!=0 ) mAlert |= ALERT_HTML;
1339
+ db_find_and_open_repository(0, 0);
1340
+ verify_all_options();
1341
+ email_schema();
1342
+ blob_init(&out, 0, 0);
1343
+ email_header(mAlert, &out);
1344
+ if( bActual ){
1345
+ Stmt q;
1346
+ db_prepare(&q, "SELECT eventid FROM pending_alert");
1347
+ while( db_step(&q)==SQLITE_ROW ){
1348
+ email_one_alert(db_column_text(&q,0), mAlert, &out);
1349
+ }
1350
+ db_finalize(&q);
1351
+ }else{
1352
+ int i;
1353
+ for(i=2; i<g.argc; i++){
1354
+ email_one_alert(g.argv[i], mAlert, &out);
1355
+ }
1356
+ }
1357
+ email_footer(mAlert, &out);
1358
+ fossil_print("%s", blob_str(&out));
1359
+ blob_zero(&out);
1360
+}
12181361
--- src/email.c
+++ src/email.c
@@ -166,16 +166,46 @@
166 email_subscriber_list_link();
167 style_header("Email Notification Setup");
168 @ <form action="%R/setup_email" method="post"><div>
169 @ <input type="submit" name="submit" value="Apply Changes" /><hr>
170 login_insert_csrf_secret();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171 multiple_choice_attribute("Email Send Method", "email-send-method", "esm",
172 "off", count(azSendMethods)/2, azSendMethods);
173 @ <p>How to send email. The "Pipe to a command"
174 @ method is the usual choice in production.
175 @ (Property: "email-send-method")</p>
176 @ <hr>
 
 
177 entry_attribute("Command To Pipe Email To", 80, "email-send-command",
178 "ecmd", "sendmail -t", 0);
179 @ <p>When the send method is "pipe to a command", this is the command
180 @ that is run. Email messages are piped into the standard input of this
181 @ command. The command is expected to extract the sender address,
@@ -193,18 +223,10 @@
193 @ <p>When the send method is "store in a directory", each email message is
194 @ stored as a separate file in the directory shown here.
195 @ (Property: "email-send-dir")</p>
196 @ <hr>
197
198 entry_attribute("\"From\" email address", 40, "email-self",
199 "eself", "", 0);
200 @ <p>This is the email from which email notifications are sent. The
201 @ system administrator should arrange for emails sent to this address
202 @ to be handed off to the "fossil email incoming" command so that Fossil
203 @ can handle bounces. (Property: "email-self")</p>
204 @ <hr>
205
206 entry_attribute("Administrator email address", 40, "email-admin",
207 "eadmin", "", 0);
208 @ <p>This is the email for the human administrator for the system.
209 @ Abuse and trouble reports are send here.
210 @ (Property: "email-admin")</p>
@@ -1213,5 +1235,126 @@
1213 }
1214 @ </table>
1215 db_finalize(&q);
1216 style_footer();
1217 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1218
--- src/email.c
+++ src/email.c
@@ -166,16 +166,46 @@
166 email_subscriber_list_link();
167 style_header("Email Notification Setup");
168 @ <form action="%R/setup_email" method="post"><div>
169 @ <input type="submit" name="submit" value="Apply Changes" /><hr>
170 login_insert_csrf_secret();
171
172 entry_attribute("Canonical Server URL", 40, "email-url",
173 "eurl", "", 0);
174 @ <p><b>Required.</b>
175 @ This is URL used as the basename for hyperlinks included in
176 @ email alert text. Omit the trailing "/".
177 @ Suggested value: "%h(g.zBaseURL)"
178 @ (Property: "email-url")</p>
179 @ <hr>
180
181 entry_attribute("\"From\" email address", 20, "email-self",
182 "eself", "", 0);
183 @ <p><b>Required.</b>
184 @ This is the email from which email notifications are sent. The
185 @ system administrator should arrange for emails sent to this address
186 @ to be handed off to the "fossil email incoming" command so that Fossil
187 @ can handle bounces. (Property: "email-self")</p>
188 @ <hr>
189
190 entry_attribute("Repository Nickname", 16, "email-subname",
191 "enn", "", 0);
192 @ <p><b>Required.</b>
193 @ This is short name used to identifies the repository in the
194 @ Subject: line of email alerts. Traditionally this name is
195 @ included in square brackets. Examples: "[fossil-src]", "[sqlite-src]".
196 @ (Property: "email-subname")</p>
197 @ <hr>
198
199 multiple_choice_attribute("Email Send Method", "email-send-method", "esm",
200 "off", count(azSendMethods)/2, azSendMethods);
201 @ <p>How to send email. The "Pipe to a command"
202 @ method is the usual choice in production.
203 @ (Property: "email-send-method")</p>
204 @ <hr>
205
206
207 entry_attribute("Command To Pipe Email To", 80, "email-send-command",
208 "ecmd", "sendmail -t", 0);
209 @ <p>When the send method is "pipe to a command", this is the command
210 @ that is run. Email messages are piped into the standard input of this
211 @ command. The command is expected to extract the sender address,
@@ -193,18 +223,10 @@
223 @ <p>When the send method is "store in a directory", each email message is
224 @ stored as a separate file in the directory shown here.
225 @ (Property: "email-send-dir")</p>
226 @ <hr>
227
 
 
 
 
 
 
 
 
228 entry_attribute("Administrator email address", 40, "email-admin",
229 "eadmin", "", 0);
230 @ <p>This is the email for the human administrator for the system.
231 @ Abuse and trouble reports are send here.
232 @ (Property: "email-admin")</p>
@@ -1213,5 +1235,126 @@
1235 }
1236 @ </table>
1237 db_finalize(&q);
1238 style_footer();
1239 }
1240
1241 #if LOCAL_INTERFACE
1242 /* Allowed values for the mAlert flags parameter to email_alert_text
1243 */
1244 #define ALERT_HTML 0x01 /* Generate HTML instead of plain text */
1245 #endif
1246
1247 /*
1248 ** Append the text for a single alert to the end of pOut
1249 */
1250 void email_one_alert(const char *zEvent, u32 mAlert, Blob *pOut){
1251 static Stmt q;
1252 int id;
1253 const char *zType = "";
1254 db_static_prepare(&q,
1255 "SELECT"
1256 " blob.uuid," /* 0 */
1257 " datetime(event.mtime)," /* 1 */
1258 " coalesce(ecomment,comment)"
1259 " || ' (user: ' || coalesce(euser,user,'?')"
1260 " || (SELECT case when length(x)>0 then ' tags: ' || x else '' end"
1261 " FROM (SELECT group_concat(substr(tagname,5), ', ') AS x"
1262 " FROM tag, tagxref"
1263 " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
1264 " AND tagxref.rid=blob.rid AND tagxref.tagtype>0))"
1265 " || ')' as comment," /* 2 */
1266 " tagxref.value AS branch" /* 3 */
1267 " FROM tag CROSS JOIN event CROSS JOIN blob"
1268 " LEFT JOIN tagxref ON tagxref.tagid=tag.tagid"
1269 " AND tagxref.tagtype>0"
1270 " AND tagxref.rid=blob.rid"
1271 " WHERE blob.rid=event.objid"
1272 " AND tag.tagname='branch'"
1273 " AND event.objid=:objid"
1274 );
1275 switch( zEvent[0] ){
1276 case 'c': zType = "Check-In"; break;
1277 case 't': zType = "Wiki Edit"; break;
1278 case 'w': zType = "Ticket Change"; break;
1279 default: return;
1280 }
1281 id = atoi(zEvent+1);
1282 if( id<=0 ) return;
1283 db_bind_int(&q, ":objid", id);
1284 if( db_step(&q)==SQLITE_ROW ){
1285 blob_appendf(pOut,"\n== %s %s ==\n%s\n%s/info/%.20s\n",
1286 db_column_text(&q,1),
1287 zType,
1288 db_column_text(&q,2),
1289 db_get("email-url","http://localhost:8080"),
1290 db_column_text(&q,0)
1291 );
1292 }
1293 db_reset(&q);
1294 }
1295
1296 /*
1297 ** Put a header on an alert email
1298 */
1299 void email_header(u32 mAlert, Blob *pOut){
1300 blob_appendf(pOut,
1301 "This is an automated email reporting changes "
1302 "on Fossil repository %s (%s/timeline)\n",
1303 db_get("email-subname","(unknown)"),
1304 db_get("email-url","http://localhost:8080"));
1305 }
1306
1307 /*
1308 ** Append the "unsubscribe" notification and other footer text to
1309 ** the end of an email alert being assemblied in pOut.
1310 */
1311 void email_footer(u32 mAlert, Blob *pOut){
1312 blob_appendf(pOut, "\n%.72c\nTo unsubscribe: %s/unsubscribe\n",
1313 '-', db_get("email-url","http://localhost:8080"));
1314 }
1315
1316 /*
1317 ** COMMAND: test-generate-alert
1318 **
1319 ** Usage: %fossil test-generate-alert [--html] [--actual] EVENTID ...
1320 **
1321 ** Generate the text of an email alert for all of the EVENTIDs
1322 ** listed on the command-line. Write that text to standard
1323 ** output. If the --actual flag is present, then the EVENTIDs are
1324 ** the actual event-ids in the pending_alert table.
1325 **
1326 ** This command is intended for testing and debugging the logic
1327 ** that generates email alert text.
1328 **
1329 ** The mimetype is text/plain by default. Use the --html option
1330 ** to generate text/html alert text.
1331 */
1332 void test_generate_alert_cmd(void){
1333 u32 mAlert = 0;
1334 int bActual = find_option("actual",0,0)!=0;
1335 Blob out;
1336 int i;
1337
1338 if( find_option("html",0,0)!=0 ) mAlert |= ALERT_HTML;
1339 db_find_and_open_repository(0, 0);
1340 verify_all_options();
1341 email_schema();
1342 blob_init(&out, 0, 0);
1343 email_header(mAlert, &out);
1344 if( bActual ){
1345 Stmt q;
1346 db_prepare(&q, "SELECT eventid FROM pending_alert");
1347 while( db_step(&q)==SQLITE_ROW ){
1348 email_one_alert(db_column_text(&q,0), mAlert, &out);
1349 }
1350 db_finalize(&q);
1351 }else{
1352 int i;
1353 for(i=2; i<g.argc; i++){
1354 email_one_alert(g.argv[i], mAlert, &out);
1355 }
1356 }
1357 email_footer(mAlert, &out);
1358 fossil_print("%s", blob_str(&out));
1359 blob_zero(&out);
1360 }
1361

Keyboard Shortcuts

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