JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
add admin_email_templates
authorJason Woofenden <jason@jasonwoof.com>
Fri, 25 Dec 2015 03:16:26 +0000 (22:16 -0500)
committerJason Woofenden <jason@jasonwoof.com>
Mon, 28 Dec 2015 20:46:42 +0000 (15:46 -0500)
admin_email_templates.html [new file with mode: 0644]
admin_email_templates.php [new file with mode: 0644]
admin_email_templates.sql [new file with mode: 0644]
config.php
inc/ckeditor
inc/misc.php
inc/wfpl

diff --git a/admin_email_templates.html b/admin_email_templates.html
new file mode 100644 (file)
index 0000000..a2a3e00
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+       <meta charset="utf-8" />
+       <title><!--~$title show {~-->Email templates<!--~}~--></title>
+</head>
+
+<body>
+<!--~$body show {~-->
+
+       <!--~form {~-->
+               <h2>Edit email template "~title html~"</h2>
+
+               <p>~description htmlbrtab~</p>
+
+               <form action="admin_email_templates" method="post">
+                       <div class="caption">Notes</div>
+                       <div class="field_notes">This is here just for admins to save any kind of notes (for example clarifications on when/how this email template is used, or notes on what the template was like previously.)</div>
+                       <div class="field"><textarea rows="6" cols="22" name="notes">~notes html~</textarea></div>
+
+                       <div class="caption">"From:" email address (required)</div>
+                       <div class="field_notes">When this email template is used, the email generated will be sent <strong>from</strong> this address.</div>
+                       <div class="field_notes">To supply a name also, use this <em>exact</em> format: <code>John Smith &lt;john@example.com&gt;</code></div>
+                       <div class="field"><input type="text" name="from_addr" value="~from_addr attr~"></div>
+
+                       <!--~want_to_addr {~-->
+                               <div class="caption">"To:" email address (required)</div>
+                               <div class="field_notes">When this email template is used, the email generated will sent <strong>to</strong> this address.</div>
+                               <div class="field_notes">To supply a name also, use this <em>exact</em> format: <code>John Smith &lt;john@example.com&gt;</code></div>
+                               <div class="field"><input type="text" name="to_addr" value="~to_addr attr~"></div>
+                       <!--~}~-->
+
+                       <div class="caption">"Cc:" email address (optional)</div>
+                       <div class="field_notes">If you enter an email address here, it will be added to the "Cc:" header, that is, it will get a copy of every email that uses this template. Note that the "Cc:" header is visible to all recipients, so this feature should probably only be used for testing.</div>
+                       <div class="field_notes">To supply a name also, use this <em>exact</em> format: <code>John Smith &lt;john@example.com&gt;</code></div>
+                       <div class="field"><input type="text" name="cc_addr" value="~cc_addr attr~"></div>
+
+                       <div class="caption">"Bcc:" email address (optional)</div>
+                       <div class="field_notes">If you enter an email address here, it will be added to the "Bcc:" header, that is, it will get a copy of every email that uses this template. This email address will <em>not</em> be visible to recipients, and will not be included in replies.</div>
+                       <div class="field_notes">To supply a name also, use this <em>exact</em> format: <code>John Smith &lt;john@example.com&gt;</code></div>
+                       <div class="field"><input type="text" name="bcc_addr" value="~bcc_addr attr~"></div>
+
+                       <div class="caption">Template Variables</div>
+                       <div class="field">You can place variables into the Subject and Message Body fields. This can be used, for example, to insert the recipients username into the message. Below is a table showing the variables that are available for this particular email template:
+                               <table cellspacing="0" cellpadding="4" border="0" summary="" class="evenodd" style="margin-top: 5px">
+                                       <tr>
+                                               <th>Variable</th>
+                                               <th>Description</th>
+                                       </tr>
+                                       <tr>
+                                               <td>~~~~</td>
+                                               <td>Puts a single ~~ in the email. You <em>must</em> do this if you want a ~~ in your email.</td>
+                                       </tr>
+                                       <!--~variables {~-->
+                                               <tr>
+                                                       <td>~~~0~~~</td>
+                                                       <td>~1~</td>
+                                               </tr>
+                                       <!--~}~-->
+                               </table>
+                       </div>
+
+                       <div class="caption">Subject</div>
+                       <div class="field_notes">This field uses template variables, see above.</div>
+                       <div class="field"><input type="text" name="subject" value="~subject attr~"></div>
+
+                       <div class="caption">Message Body</div>
+                       <div class="field_notes">This field uses template variables, see above.</div>
+                       <div class="field"><textarea rows="9" cols="22" name="content">~content html~</textarea></div>
+
+                       <div class="caption"></div>
+                       <div class="field">
+                               <input type="hidden" name="slug" value="~slug attr~">
+                               <input type="submit" name="save" value="Save">
+                       </div>
+
+               </form>
+
+               <div class="caption">&nbsp;</div>
+               <div class="field"><a href="admin_email_templates~id {~?id=~id~~}~">Cancel</a></div>
+       <!--~}~-->
+
+       <!--~listings {~-->
+               <h2>Email Templates</h2>
+
+               <p>Click one to edit:</p>
+
+               <!--~rows once_if {~-->
+                       <table cellspacing="0" cellpadding="4" border="0" summary="" class="evenodd">
+                               <tr>
+                                       <th><a href="?sort=~sorting-by-title~title">Template Title</a></th>
+                                       <th><a href="?sort=~sorting-by-subject~subject">Email Subject</a></th>
+                               </tr><!--~rows {~-->
+                               <tr>
+                                       <td class="listing"><a href="admin_email_templates?slug=~slug~">~title html~<!--~title empty {~--><em>(blank)</em><!--~}~--></a></td>
+                                       <td class="listing"><a href="admin_email_templates?slug=~slug~">~subject html~<!--~subject empty {~--><em>(blank)</em><!--~}~--></a></td>
+                               </tr><!--~}~-->
+
+                       </table>
+               <!--~}~-->
+       <!--~}~-->
+
+<!--~}~-->
+</body>
+</html>
diff --git a/admin_email_templates.php b/admin_email_templates.php
new file mode 100644 (file)
index 0000000..10ed922
--- /dev/null
@@ -0,0 +1,186 @@
+<?php
+
+# This form requires wfpl. See: http://sametwice.com/wfpl
+
+# SETUP
+#
+# in config.php you'll need something like this:
+#
+#      $GLOBALS['email_templates'] = [
+#              'slug' => [
+#                      'title' => "Title shown in admin only",
+#                      'description' => "explain (for admins) what this template is for",
+#                      'variables' => [
+#                              ['name', "explan (for admins) what this variable is for"],
+#                              ['verbing', "admins can put these variables into the template"]
+#                      ],
+#                      'subject' => "email subject",
+#                      'content' => "Hi, ~name~ this is the email body, thanks for ~verbing~!",
+#                      'from_addr' => 'noreply@airservices.info',
+#                      'to_addr' => 'optional@to.address' # optional
+#              ]
+#              # , 'slug2' => ...
+#      ];
+
+# To save results to a database, you'll need to create the email_templates table.
+# The file admin_email_templates.sql should help with this
+#
+# if you rename any of the database fields, you'll need to update this:
+define('ADMIN_EMAIL_TEMPLATES_DB_FIELDS', 'slug,notes,from_addr,to_addr,cc_addr,bcc_addr,subject,content');
+
+
+$GLOBALS['admin_email_templates_field_to_caption'] = array(
+       'slug' => 'Slug',
+       'notes' => 'Notes',
+       'from_addr' => 'From Address',
+       'to_addr' => 'To Address',
+       'cc_addr' => 'Cc Address',
+       'bcc_addr' => 'Bcc Address',
+       'subject' => 'Subject',
+       'content' => 'Content'
+);
+
+function admin_email_templates_get_fields() {
+       $data = array();
+
+       # slug is cut in *_main()
+       $data['notes'] = format_unix(_REQUEST_cut('notes'));
+       $data['to_addr'] = format_email(trim(_REQUEST_cut('to_addr')));
+       $data['from_addr'] = format_email(trim(_REQUEST_cut('from_addr')));
+       $data['cc_addr'] = format_email(trim(_REQUEST_cut('cc_addr')));
+       $data['bcc_addr'] = format_email(trim(_REQUEST_cut('bcc_addr')));
+       $data['subject'] = format_oneline(trim(_REQUEST_cut('subject')));
+       $data['content'] = format_unix(_REQUEST_cut('content'));
+
+       return $data;
+}
+
+
+function admin_email_templates_main() {
+       session_auth_must('admin_email_templates');
+
+       $slug = _REQUEST_cut('slug');
+       if ($slug && isset($GLOBALS['email_templates'][$slug])) {
+               return admin_email_templates_main_form($slug);
+       }
+
+       # default action:
+       return admin_email_templates_main_listing();
+}
+
+function admin_email_templates_main_sort_title($a, $b) {
+       return strcasecmp($a['title'], $b['title']);
+}
+function admin_email_templates_main_sort_title_reverse($a, $b) {
+       return strcasecmp($b['title'], $a['title']);
+}
+function admin_email_templates_main_sort_subject($a, $b) {
+       return strcasecmp($a['subject'], $b['subject']);
+}
+function admin_email_templates_main_sort_subject_reverse($a, $b) {
+       return strcasecmp($b['subject'], $a['subject']);
+}
+
+function admin_email_templates_main_listing() {
+       $data = array();
+       $reverse = '';
+       $sort = _REQUEST_cut('sort');
+       if ($sort && substr($sort, 0, 1) === '-') {
+               $sort = substr($sort, 1);
+               $reverse = "_reverse";
+       } else {
+               $data["sorting-by-$sort"] = '-';
+       }
+       $legal_sorts = array('title', 'subject');
+       if (!$sort || !in_array($sort, $legal_sorts)) {
+               $sort = 'title';
+       }
+
+       $data['rows'] = array();
+
+       $rows = db_get_assocs('email_templates', 'slug,from_addr,cc_addr,bcc_addr,subject');
+       $by_slug = array();
+       foreach ($rows as $row) {
+               $by_slug[$row['slug']] = $row;
+       }
+       foreach ($GLOBALS['email_templates'] as $slug => $row) {
+               $out = array('slug' => $slug);
+               # defaults from config
+               foreach($row as $k => $v) {
+                       $out[$k] = $v;
+               }
+               # overwrite with db (if it's in the db)
+               if ($by_slug[$slug]) {
+                       foreach($by_slug[$slug] as $k => $v) {
+                               $out[$k] = $v;
+                       }
+               }
+               $data['rows'][] = $out;
+       }
+
+       usort($data['rows'], "admin_email_templates_main_sort_$sort$reverse");
+
+       tem_set('listings', $data);
+}
+
+function admin_email_templates_main_form($slug) {
+       if (isset($_POST['subject'])) {
+               $data = admin_email_templates_get_fields();
+               $data['slug'] = $slug;
+
+               $all_good = true;
+               $email_fields = ['from', 'to', 'cc', 'bcc'];
+               foreach ($email_fields as &$field) {
+                       $value = $data[$field . '_addr'];
+                       if (strlen($value)) {
+                               if (!email_header($value)) {
+                                       $pretty = ucfirst($field) . ':';
+                                       message("ERROR: invalid value in \"$pretty\" field. Be very careful with formatting, and only put one address in this field.");
+                                       $all_good = false;
+                               }
+                       }
+               } unset($field);
+
+               if (strlen($data['from_addr']) == 0) {
+                       message("ERROR: the \"From:\" field is required.");
+                       $all_good = false;
+               }
+
+               if (strlen($data['to_addr']) == 0 && isset($GLOBALS['email_templates'][$slug]['to_addr'])) {
+                       message("ERROR: the \"To:\" field is required for this template.");
+                       $all_good = false;
+               }
+               if ($all_good) {
+                       if (0 < db_count('email_templates', 'where slug=%"', $slug)) {
+                               db_update_assoc('email_templates', $data, 'where slug=%"', $slug);
+                       } else {
+                               db_insert_assoc('email_templates', $data);
+                       }
+                       message('Email template updated.');
+                       if ($error !== true) {
+                               return './admin_email_templates';
+                       }
+               } else {
+                       $custom = $data;
+               }
+       } else {
+               $custom = db_get_assoc('email_templates', ADMIN_EMAIL_TEMPLATES_DB_FIELDS, 'where slug=%"', $slug);
+       }
+
+       $out = array('slug' => $slug);
+       # defaults from globals
+       foreach($GLOBALS['email_templates'][$slug] as $k => $v) {
+               $out[$k] = $v;
+       }
+       # show 'to_addr' field if it's relevant
+       if (isset($out['to_addr'])) {
+               $out['want_to_addr'] = true;
+       }
+       # override with db values
+       if ($custom) {
+               foreach($custom as $k => $v) {
+                       $out[$k] = $v;
+               }
+       }
+       tem_set('form', $out);
+}
diff --git a/admin_email_templates.sql b/admin_email_templates.sql
new file mode 100644 (file)
index 0000000..dc11783
--- /dev/null
@@ -0,0 +1,12 @@
+drop table if exists email_templates;
+create table email_templates (
+    id int unique auto_increment,
+    slug varchar(200) binary not null default "",
+    notes text binary not null default "",
+    from_addr varchar(100) binary not null default "",
+    to_addr varchar(100) binary not null default "",
+    cc_addr varchar(100) binary not null default "",
+    bcc_addr varchar(100) binary not null default "",
+    subject varchar(200) binary not null default "",
+    content text binary not null default ""
+) CHARSET=utf8;
index 59b1c98..da021ef 100644 (file)
@@ -35,3 +35,18 @@ if (isset($_SERVER['HTTP_X_UPGRADE_DB_NOW'])) {
        require_once(DOCROOT . 'inc/db_upgrade.php');
        db_upgrade();
 }
+
+$GLOBALS['email_templates'] = [
+       'backend_bug' => [
+               'title' => "Notification for site programmer(s)",
+               'description' => "This email template is used if/when the back-end code of this site encounters an unusual/suspicious situation that it's not sure how to cope with.",
+               'variables' => [
+                       ['message', "details about the unusual/suspicious situation"]
+               ],
+               'subject' => "backend alert",
+               'content' => "Hi developer,\n\nPlease investigate the following debugging message from the site:\n\n~message~"
+               'from_addr' => 'noreply@example.com',
+               'to_addr' => 'fixme@example.com' # not all templates need this field
+       ]
+       # ...
+];
index a0df3d0..34d2dd8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a0df3d0ab0c5252b5e2e0fd274705ede834c2276
+Subproject commit 34d2dd88753d873bd36d07d9917b326fa84ac464
index 429482d..aed971d 100644 (file)
@@ -1,6 +1,58 @@
 <?php
 
+require_once(DOCROOT . 'inc/wfpl/email.php');
+
 # call this when you have class="unix_time" or class="unix_date"
 function render_timestamps() {
        $GLOBALS['wfpl_main_template']->set('$render_timestamps');
 }
+
+# helper for email_with_template() below
+function get_email_template($slug, $template_variables, $to_addr) {
+       # defaults
+       $out = array(
+               'subject' => $GLOBALS['email_templates'][$slug]['subject'],
+               'content' => $GLOBALS['email_templates'][$slug]['content'],
+               'from_addr' => $GLOBALS['email_templates'][$slug]['from_addr'],
+               'to_addr' => '',
+               'cc_addr' => '',
+               'bcc_addr' => ''
+       );
+       if (isset($GLOBALS['email_templates'][$slug]['to_addr'])) {
+               $out['to_addr'] = $GLOBALS['email_templates'][$slug]['to_addr'];
+       } else {
+               if ($to_addr == null) {
+                       die("ERROR: email_with_template(\"$slug\") needs a to_addr (put in \$GLOBALS['email_templates']['$slug'] or pass as argument)");
+               }
+       }
+       # override with DB (if it exists)
+       $row = db_get_assoc('email_templates', 'from_addr,to_addr,cc_addr,bcc_addr,subject,content', 'where slug=%"', $slug);
+       if ($row) {
+               foreach($row as $key => $value) {
+                       $out[$key] = $value;
+               }
+       }
+       # argument wins no matter what
+       if ($to_addr !== null) {
+               $out['to_addr'] = $to_addr;
+       }
+       if (strpos($out['content'], '~') !== false) {
+               $tem = new tem();
+               $tem->load_str($out['content']);
+               $tem->sets($template_variables);
+               $out['content'] = $tem->run();
+       }
+       if (strpos($out['subject'], '~') !== false) {
+               $tem = new tem();
+               $tem->load_str($out['subject']);
+               $tem->sets($template_variables);
+               $out['subject'] = $tem->run();
+       }
+       return $out;
+}
+
+# pass null as first arg if "to_addr" should come from the DB
+function email_with_template($to_addr, $template_slug, $template_vars, $reply_to = '') {
+       $t = get_email_template($template_slug, $template_vars, $to_addr);
+       return email($t['from_addr'], $t['to_addr'], $t['subject'], $t['content'], $reply_to, $t['cc_addr'], $t['bcc_addr']);
+}
index 1cc2fd7..f58acc2 160000 (submodule)
--- a/inc/wfpl
+++ b/inc/wfpl
@@ -1 +1 @@
-Subproject commit 1cc2fd791d55bca1a63afbeb2628dd1a8bd2ba3f
+Subproject commit f58acc2fd5e5fbfb4a01d6b66711b2f62bf77c4a