[freeside-commits] branch master updated. 974fceaaca8e1404750a60a4daafb568b1be5159

Jonathan Prykop jonathan at 420.am
Tue Oct 20 18:57:29 PDT 2015


The branch, master has been updated
       via  974fceaaca8e1404750a60a4daafb568b1be5159 (commit)
      from  b25c22890cc4523988b1dc84938d1e52bc681e25 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 974fceaaca8e1404750a60a4daafb568b1be5159
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Tue Oct 20 20:56:13 2015 -0500

    RT#38217: Send email when logging conditions are met

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index ceb347d..7dc54f7 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -6563,6 +6563,25 @@ sub tables_hashref {
                         ],
     },
 
+    'log_email' => {
+      'columns' => [
+        'logemailnum', 'serial', '', '', '', '',
+        'context', 'varchar', 'NULL', $char_d, '', '',
+        'min_level', 'int',  'NULL', '', '', '',
+        'msgnum', 'int', '',  '', '', '',
+        'to_addr', 'varchar', 'NULL',     255, '', '',
+      ],
+      'primary_key'  => 'logemailnum',
+      'unique'       => [],
+      'index'        => [ ['context'], ['min_level'] ],
+      'foreign_keys' => [
+                          { columns    => [ 'msgnum' ],
+                            table      => 'msg_template',
+                            references => [ 'msgnum' ],
+                          },
+                        ],
+    },
+
     'svc_alarm' => {
       'columns' => [
 #       name               type        null   length   default local
diff --git a/FS/FS/log.pm b/FS/FS/log.pm
index a4ad214..b079105 100644
--- a/FS/FS/log.pm
+++ b/FS/FS/log.pm
@@ -5,6 +5,7 @@ use base qw( FS::Record );
 use FS::Record qw( qsearch qsearchs dbdef );
 use FS::UID qw( dbh driver_name );
 use FS::log_context;
+use FS::log_email;
 
 =head1 NAME
 
@@ -71,6 +72,8 @@ otherwise returns false.
 
 CONTEXT may be a list of context tags to attach to this record.
 
+Will send emails according to the conditions in L<FS::log_email>.
+
 =cut
 
 sub insert {
@@ -78,6 +81,7 @@ sub insert {
   my $self = shift;
   my $error = $self->SUPER::insert;
   return $error if $error;
+  my $contexts = {}; #for quick checks when sending emails
   foreach ( @_ ) {
     my $context = FS::log_context->new({
         'lognum'  => $self->lognum,
@@ -85,11 +89,40 @@ sub insert {
     });
     $error = $context->insert;
     return $error if $error;
+    $contexts->{$_} = 1;
+  }
+  foreach my $log_email (
+    qsearch('log_email',
+      {
+        'disabled' => '',
+        'min_level' => {
+          'op' => '<=',
+          'value' => $self->level,
+        },
+      }
+    )
+  ) {
+    # shouldn't be a lot of these, so not packing this into the qsearch
+    next if $log_email->context && !$contexts->{$log_email->context};
+    my $msg_template = qsearchs('msg_template',{ 'msgnum' => $log_email->msgnum });
+    unless ($msg_template) {
+      warn "Could not send email when logging, could not load message template for logemailnum " . $log_email->logemailnum;
+      next;
+    }
+    my $emailerror = $msg_template->send(
+      'to'            => $log_email->to_addr,
+      'substitutions' => {
+        'loglevel'   => $FS::Log::LEVELS[$self->level], # which has hopefully been loaded...
+        'logcontext' => $log_email->context, # use the one that triggered the email
+        'logmessage' => $self->message,
+      },
+    );
+    warn "Could not send email when logging: $emailerror" if $emailerror;
   }
   '';
 }
 
-# the insert method can be inherited from FS::Record
+# these methods can be inherited from FS::Record
 
 sub delete  { die "Log entries can't be modified." };
 
diff --git a/FS/FS/log_email.pm b/FS/FS/log_email.pm
new file mode 100644
index 0000000..9c53c23
--- /dev/null
+++ b/FS/FS/log_email.pm
@@ -0,0 +1,108 @@
+package FS::log_email;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs dbdef );
+use FS::UID qw( dbh driver_name );
+
+=head1 NAME
+
+FS::log_email - Object methods for log email records
+
+=head1 SYNOPSIS
+
+  use FS::log_email;
+
+  $record = new FS::log_email \%hash;
+  $record = new FS::log_email { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::log object represents the conditions for sending an email
+when a log entry is created.  FS::log inherits from FS::Record.  
+The following fields are currently supported:
+
+=over 4
+
+=item logemailnum - primary key
+
+=item context - the context that will trigger the email (all contexts if unspecified)
+
+=item min_level - the minimum log level that will trigger the email (all levels if unspecified)
+
+=item msgnum - the msg_template that will be used to send the email
+
+=item to_addr - who the email will be sent to (in addition to any bcc on the template)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new log_email entry.
+
+=cut
+
+sub table { 'log_email'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('logemailnum')
+    || $self->ut_textn('context') # not validating against list of contexts in log_context,
+                                  # because not even log_context check currently does so
+    || $self->ut_number('min_level')
+    || $self->ut_foreign_key('msgnum', 'msg_template', 'msgnum')
+    || $self->ut_textn('to_addr')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm
index d17fd41..1d357b1 100644
--- a/FS/FS/msg_template.pm
+++ b/FS/FS/msg_template.pm
@@ -274,7 +274,7 @@ Options are passed as a list of name/value pairs:
 
 =item cust_main
 
-Customer object (required).
+Customer object
 
 =item object
 
@@ -324,7 +324,7 @@ sub prepare_substitutions {
   my( $self, %opt ) = @_;
 
   my $cust_main = $opt{'cust_main'}; # or die 'cust_main required';
-  my $object = $opt{'object'} or die 'object required';
+  my $object = $opt{'object'}; # or die 'object required';
 
   warn "preparing substitutions for '".$self->msgname."'\n"
     if $DEBUG;
diff --git a/FS/FS/msg_template/email.pm b/FS/FS/msg_template/email.pm
index 377dbb1..83ff18f 100644
--- a/FS/FS/msg_template/email.pm
+++ b/FS/FS/msg_template/email.pm
@@ -164,7 +164,7 @@ Options are passed as a list of name/value pairs:
 
 =item cust_main
 
-Customer object (required).
+Customer object
 
 =item object
 
@@ -215,7 +215,7 @@ sub prepare {
   my( $self, %opt ) = @_;
 
   my $cust_main = $opt{'cust_main'}; # or die 'cust_main required';
-  my $object = $opt{'object'} or die 'object required';
+  my $object = $opt{'object'}; # or die 'object required';
 
   my $hashref = $self->prepare_substitutions(%opt);
 
@@ -365,7 +365,7 @@ sub prepare {
   my $env_to = join(', ', @to);
 
   my $cust_msg = FS::cust_msg->new({
-      'custnum'   => $cust_main->custnum,
+      'custnum'   => $cust_main ? $cust_main->custnum : '',
       'msgnum'    => $self->msgnum,
       '_date'     => $time,
       'env_from'  => $env_from,
diff --git a/httemplate/browse/log_email.html b/httemplate/browse/log_email.html
new file mode 100644
index 0000000..0f64dd4
--- /dev/null
+++ b/httemplate/browse/log_email.html
@@ -0,0 +1,92 @@
+<% include('/elements/init_overlib.html') %>
+<% include('/browse/elements/browse.html',
+     'title'         => 'Log email condition configuration',
+     'name_singular' => 'condition',
+     'html_init'     => '<P STYLE="margin-top: 0">'
+                        . $add_condition_link
+                        . ' | '
+                        . $system_log_link
+                        . '</P>'
+                        . '<SCRIPT>'
+                        . $areyousure
+                        . '</SCRIPT>',
+     'query'         => $query,
+     'count_query'   => $count_query,
+     'header'      => [ '#',
+                        'Context', 
+                        'Min. Level', 
+                        'Template', 
+                        'To',
+                        '',
+                      ],
+     'fields'      => [ 'logemailnum',
+                        sub { $_[0]->context || '(all)' },
+                        sub { $FS::Log::LEVELS[$_[0]->min_level] },
+                        'msgname',
+                        'to_addr',
+                        $actions,
+                      ],
+     'sort_fields' => [ 'logemailnum',
+                        'context',
+                        'min_level',
+                        'msgname',
+                        'to_addr',
+                        '',
+                      ],
+     'links'       => [ $editlink,
+                        $editlink,
+                        $editlink,
+                        $editlink,
+                        $editlink,
+                        '',
+                      ],
+
+   ) %>
+
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right([ 'View system logs', 'Configuration' ]);
+
+my $add_condition_link = include('/elements/popup_link.html',
+  'action' => $p.'edit/log_email.html?popup=1',
+  'label'  => 'Add log email condition',
+  'actionlabel' => 'Add log email condition',
+);
+
+my $system_log_link = qq(<A HREF="${p}search/log.html">System Log</A>);
+
+my $query = {
+  'table'   => 'log_email',
+  'select'  => '*',
+  'addl_from' => 'LEFT JOIN msg_template USING (msgnum)',
+  'hashref' => { },
+};
+
+my $count_query = "SELECT COUNT(*) FROM log_email";
+
+my $actions = sub {
+  my $log_email = shift;
+  my $logemailnum = $log_email->logemailnum;
+  qq!<A HREF="javascript:areyousure_delete_log_email($logemailnum)">(delete)</A>!;
+};
+
+my $areyousure_onclick = include('/elements/popup_link_onclick.html',
+  'js_action' => q(') . $p . q(misc/delete-log_email.html?logemailnum=' + logemailnum),
+  'actionlabel' => 'Delete log email condition',
+);
+
+my $areyousure = <<EOF;
+function areyousure_delete_log_email(logemailnum) {
+  if (confirm('Are you sure you want to delete log email condition #'+logemailnum+'?')) {
+${areyousure_onclick}
+  }
+}
+EOF
+
+my $editlink = [ $p.'edit/log_email.html?logemailnum=', 'logemailnum' ];
+
+</%init>
+
diff --git a/httemplate/edit/log_email.html b/httemplate/edit/log_email.html
new file mode 100644
index 0000000..bbce7c7
--- /dev/null
+++ b/httemplate/edit/log_email.html
@@ -0,0 +1,45 @@
+<% include( 'elements/edit.html',
+              'name_singular' => 'log email condition',
+              'table'  => 'log_email',
+              'fields' => [
+                            { 'field' => 'context',
+                              'type' => 'select',
+                              'options' => [ '', @contexts ],
+                              'labels' => { '' => '(all)', map { $_ => $_ } @contexts },
+                              'curr_value' => scalar($cgi->param('context')),
+                            },
+                            { 'field' => 'min_level',
+                              'type'  => 'select',
+                              'options' => [ 0..7 ],
+                              'labels' => { map {$_ => $FS::Log::LEVELS[$_]} 0..7 },
+                              'curr_value' => scalar($cgi->param('min_level')),
+                            },
+                            'to_addr',
+                            { 'field' => 'msgnum',
+                              'type' => 'select-msg_template',
+                              'empty_label' => 'Select template',
+                              'required' => 1,
+                            },
+                          ],
+              'labels' => { 
+                            'context' => 'Context',
+                            'min_level' => 'Min. Level',
+                            'to_addr' => 'To',
+                            'msgnum' => 'Message',
+                          },
+              'viewall_dir' => 'browse',
+              'popup' => $opts{'popup'},
+              'form_init' => $opts{'popup'} ? q(<INPUT TYPE="hidden" NAME="popup" VALUE="1">) : '',
+           )
+%>
+<%once>
+my @contexts = sort FS::log_context->contexts;
+</%once>
+<%init>
+
+my %opts = @_;
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]);
+
+</%init>
diff --git a/httemplate/edit/msg_template/email.html b/httemplate/edit/msg_template/email.html
index dc70ef6..b0c1aa3 100644
--- a/httemplate/edit/msg_template/email.html
+++ b/httemplate/edit/msg_template/email.html
@@ -302,6 +302,11 @@ my %substitutions = (
     '$payinfo'        => 'Card/account# (masked)',
     '$error'          => 'Decline reason',
   ],
+  'system_log' => [
+    '$logmessage'     => 'Log entry message',
+    '$loglevel'       => 'Log entry level',
+    '$logcontext'     => 'Log entry context',
+  ],
 );
 
 tie my %sections, 'Tie::IxHash', (
@@ -315,6 +320,7 @@ tie my %sections, 'Tie::IxHash', (
 'svc_domain'=> 'Domain service fields',
 'svc_phone' => 'Phone service fields',
 'svc_broadband' => 'Broadband service fields',
+'system_log' => 'System log fields',
 );
 
 my $widget = new HTML::Widgets::SelectLayers(
diff --git a/httemplate/edit/process/log_email.html b/httemplate/edit/process/log_email.html
new file mode 100644
index 0000000..769e180
--- /dev/null
+++ b/httemplate/edit/process/log_email.html
@@ -0,0 +1,18 @@
+<% include('elements/process.html',
+    'table' => 'log_email',
+    %processopts
+   ) %>
+<%init>
+
+my %opts = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right([ 'View system logs', 'Configuration' ]);
+
+my %processopts = $opts{'popup'}
+  ? ( 'popup_reload' => 'Logging email added' )
+  : ( 'redirect' => $fsurl.'browse/log_email.html?' ); # id will be needlessly appended, should be harmless
+
+</%init>
diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index ea69331..dcc02c2 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -787,6 +787,10 @@ $config_misc{'Inventory classes and inventory'} = [ $fsurl.'browse/inventory_cla
 $config_misc{'Upload targets'} = [ $fsurl.'browse/upload_target.html', 'Billing and payment upload destinations' ]
   if $curuser->access_right('Configuration');
 
+$config_misc{'System log emails'} = [ $fsurl.'browse/log_email.html', 'Configure conditions for sending email when logging' ]
+  if $curuser->access_right('View system logs')
+  || $curuser->access_right('Configuration');
+
 tie my %config_menu, 'Tie::IxHash';
 if ( $curuser->access_right('Configuration' ) ) {
   %config_menu = (
diff --git a/httemplate/elements/tr-select-msg_template.html b/httemplate/elements/tr-select-msg_template.html
new file mode 100644
index 0000000..1f899e0
--- /dev/null
+++ b/httemplate/elements/tr-select-msg_template.html
@@ -0,0 +1,12 @@
+<% include('/elements/tr-td-label.html',
+     'label'    => $opt{'label'} || 'Message template: ',
+     'required' => $opt{'required'} ) %>
+  <TD><% include('select-msg_template.html', %opt) %></TD>
+</TR>
+
+<%init>
+
+my %opt = @_;
+
+</%init>
+
diff --git a/httemplate/misc/delete-log_email.html b/httemplate/misc/delete-log_email.html
new file mode 100644
index 0000000..cc17b15
--- /dev/null
+++ b/httemplate/misc/delete-log_email.html
@@ -0,0 +1,20 @@
+% if ($error) {
+<P STYLE="color: red"><% $error %></P>
+% } else {
+<H1>Log email condition deleted</H1>
+<SCRIPT>
+window.top.location.reload();
+</SCRIPT>
+% }
+
+<%init>
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]);
+
+my $logemailnum = $cgi->param('logemailnum');
+$logemailnum =~ /^\d+$/ or die "bad logemailnum '$logemailnum'";
+my $log_email = FS::log_email->by_key($logemailnum)
+  or die "logemailnum '$logemailnum' not found";
+my $error = $log_email->delete;
+</%init>
+
diff --git a/httemplate/search/log.html b/httemplate/search/log.html
index d1bfb6c..a707928 100644
--- a/httemplate/search/log.html
+++ b/httemplate/search/log.html
@@ -1,6 +1,7 @@
 <& elements/search.html, 
   'title'         => 'System Log',
   'name_singular' => 'event',
+  'menubar'       => \@menubar,
   'html_init'     => include('.head'),
   'query'         => $query,
   'count_query'   => $count_query,
@@ -204,6 +205,9 @@ my $curuser = $FS::CurrentUser::CurrentUser;
 die "access denied"
   unless $curuser->access_right([ 'View system logs', 'Configuration' ]);
 
+my @menubar = ();
+push @menubar, qq(<A HREF="${fsurl}browse/log_email.html" STYLE="text-decoration: underline;">Configure conditions for sending email when logging</A>),
+
 $cgi->param('min_level', 0) unless defined($cgi->param('min_level'));
 $cgi->param('max_level', 7) unless defined($cgi->param('max_level'));
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Schema.pm                                    |   19 ++++
 FS/FS/log.pm                                       |   35 ++++++-
 FS/FS/log_email.pm                                 |  108 ++++++++++++++++++++
 FS/FS/msg_template.pm                              |    4 +-
 FS/FS/msg_template/email.pm                        |    6 +-
 httemplate/browse/log_email.html                   |   92 +++++++++++++++++
 httemplate/edit/log_email.html                     |   45 ++++++++
 httemplate/edit/msg_template/email.html            |    6 ++
 httemplate/edit/process/log_email.html             |   18 ++++
 httemplate/elements/menu.html                      |    4 +
 ...dware_type.html => tr-select-msg_template.html} |    5 +-
 httemplate/misc/delete-log_email.html              |   20 ++++
 httemplate/search/log.html                         |    4 +
 13 files changed, 358 insertions(+), 8 deletions(-)
 create mode 100644 FS/FS/log_email.pm
 create mode 100644 httemplate/browse/log_email.html
 create mode 100644 httemplate/edit/log_email.html
 create mode 100644 httemplate/edit/process/log_email.html
 copy httemplate/elements/{tr-select-hardware_type.html => tr-select-msg_template.html} (50%)
 create mode 100644 httemplate/misc/delete-log_email.html




More information about the freeside-commits mailing list