From 02610faa68566f37b97bf00a18b0c18a74a5c5bd Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Fri, 25 Apr 2014 14:20:23 +0200 Subject: [PATCH] MT#6789 Implement email template management. Basic functionality to create, edit and delete email templates. --- debian/control | 4 + lib/NGCP/Panel.pm | 15 ++ lib/NGCP/Panel/Controller/EmailTemplate.pm | 244 ++++++++++++++++++ lib/NGCP/Panel/Form/EmailTemplate/Admin.pm | 20 ++ lib/NGCP/Panel/Form/EmailTemplate/Reseller.pm | 76 ++++++ lib/NGCP/Panel/View/TT.pm | 40 +++ share/templates/emailtemplate/list.tt | 27 ++ share/templates/emailtemplate/test.tt | 7 + .../widgets/admin_topmenu_settings.tt | 1 + .../widgets/reseller_topmenu_settings.tt | 1 + 10 files changed, 435 insertions(+) create mode 100644 lib/NGCP/Panel/Controller/EmailTemplate.pm create mode 100644 lib/NGCP/Panel/Form/EmailTemplate/Admin.pm create mode 100644 lib/NGCP/Panel/Form/EmailTemplate/Reseller.pm create mode 100644 lib/NGCP/Panel/View/TT.pm create mode 100644 share/templates/emailtemplate/list.tt create mode 100644 share/templates/emailtemplate/test.tt diff --git a/debian/control b/debian/control index cd26ccb327..d420b27d9d 100644 --- a/debian/control +++ b/debian/control @@ -24,6 +24,8 @@ Build-Depends: debhelper (>= 8), libdatetime-format-rfc3339-perl, libdbix-class-resultset-recursiveupdate-perl (>= 0.30~), libdevel-cover-perl, + libemail-mime-perl, + libemail-send-perl, libfile-spec-perl (>= 3.4000~), libfile-type-perl, libgd-gd2-perl, @@ -92,6 +94,8 @@ Depends: gettext, libdatetime-perl, libdbix-class-resultset-recursiveupdate-perl (>= 0.30~), libdigest-sha3-perl, + libemail-mime-perl, + libemail-send-perl, libemail-valid-perl, libfcgi-procmanager-perl, libfile-spec-perl (>= 3.4000~), diff --git a/lib/NGCP/Panel.pm b/lib/NGCP/Panel.pm index 8f09334674..b5a6086a02 100644 --- a/lib/NGCP/Panel.pm +++ b/lib/NGCP/Panel.pm @@ -24,6 +24,7 @@ use Catalyst qw/ Session::Store::FastMmap Session::State::Cookie I18N + Email /; # EnableMiddleware use Log::Log4perl::Catalyst qw(); @@ -85,6 +86,18 @@ __PACKAGE__->config( #(sEcho iTotalRecords iTotalDisplayRecords aaData) for datatables expose_stash => [ qw(sEcho iTotalRecords iTotalDisplayRecords aaData) ], }, + 'View::TT' => { + INCLUDE_PATH => [ + '/usr/share/ngcp-panel/templates', + '/usr/share/ngcp-panel/layout', + '/usr/share/ngcp-panel/static', + __PACKAGE__->path_to('share', 'templates'), + __PACKAGE__->path_to('share', 'layout'), + __PACKAGE__->path_to('share', 'static'), + ], + ABSOLUTE => 1, + EVAL_PERL => 1, + }, 'Plugin::Static::Simple' => { include_path => [ @@ -173,6 +186,8 @@ __PACKAGE__->config( ); __PACKAGE__->config( default_view => 'HTML' ); +__PACKAGE__->config( email => ['Sendmail'] ); + __PACKAGE__->log(Log::Log4perl::Catalyst->new($logger_config)); # Start the application diff --git a/lib/NGCP/Panel/Controller/EmailTemplate.pm b/lib/NGCP/Panel/Controller/EmailTemplate.pm new file mode 100644 index 0000000000..3fd77f72cb --- /dev/null +++ b/lib/NGCP/Panel/Controller/EmailTemplate.pm @@ -0,0 +1,244 @@ +package NGCP::Panel::Controller::EmailTemplate; +use Sipwise::Base; + +BEGIN { extends 'Catalyst::Controller'; } + +use NGCP::Panel::Form::EmailTemplate::Reseller; +use NGCP::Panel::Form::EmailTemplate::Admin; +use NGCP::Panel::Utils::Message; + +sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) { + my ($self, $c) = @_; + $c->log->debug(__PACKAGE__ . '::auto'); + NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c); + + $c->stash(template => 'emailtemplate/test.tt'); + +} + +sub tmpl_list :Chained('/') :PathPart('emailtemplate') :CaptureArgs(0) { + my ( $self, $c ) = @_; + + my $tmpl_rs = $c->model('DB')->resultset('email_templates'); + if($c->user->roles eq "admin") { + } elsif($c->user->roles eq "reseller") { + $tmpl_rs = $tmpl_rs->search({ + reseller_id => $c->user->reseller_id, + }); + } + + $c->stash->{tmpl_rs} = $tmpl_rs; + $c->stash->{template_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ + { name => 'id', search => 1, title => $c->loc('#') }, + { name => 'reseller.name', search => 1, title => $c->loc('Reseller') }, + { name => 'name', search => 1, title => $c->loc('Name') }, + { name => 'from_email', search => 1, title => $c->loc('From') }, + { name => 'subject', search => 1, title => $c->loc('Subject') }, + ]); + + $c->stash(template => 'emailtemplate/list.tt'); +} + +sub tmpl_root :Chained('tmpl_list') :PathPart('') :Args(0) { + my ($self, $c) = @_; +} + +sub tmpl_ajax :Chained('tmpl_list') :PathPart('ajax') :Args(0) { + my ($self, $c) = @_; + + my $rs = $c->stash->{tmpl_rs}; + NGCP::Panel::Utils::Datatables::process($c, $rs, $c->stash->{template_dt_columns}); + + $c->detach( $c->view("JSON") ); +} + +sub tmpl_create :Chained('tmpl_list') :PathPart('create') :Args(0) { + my ($self, $c) = @_; + + my $posted = ($c->request->method eq 'POST'); + my $form; + my $params = {}; + $params = $params->merge($c->session->{created_objects}); + if($c->user->roles eq "admin") { + $form = NGCP::Panel::Form::EmailTemplate::Admin->new; + } elsif($c->user->roles eq "reseller") { + $form = NGCP::Panel::Form::EmailTemplate::Reseller->new; + } + $form->process( + posted => $posted, + params => $c->request->params, + item => $params, + ); + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => { + 'reseller.create' => $c->uri_for('/reseller/create'), + }, + back_uri => $c->req->uri, + ); + if($posted && $form->validated) { + try { + if($c->user->roles eq "admin") { + $form->values->{reseller_id} = $form->values->{reseller}{id}; + } elsif($c->user->roles eq "reseller") { + $form->values->{reseller_id} = $c->user->reseller_id; + } + delete $form->values->{reseller}; + + my $schema = $c->model('DB'); + $schema->txn_do(sub { + my $tmpl = $c->stash->{tmpl_rs}->create($form->values); + }); + + delete $c->session->{created_objects}->{reseller}; + $c->flash(messages => [{type => 'success', text => $c->loc('Email template successfully created')}]); + } catch($e) { + NGCP::Panel::Utils::Message->error( + c => $c, + error => $e, + desc => $c->loc('Failed to create email template'), + ); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emailtemplate')); + } + + $c->stash( + form => $form, + create_flag => 1, + ); +} + +sub tmpl_base :Chained('tmpl_list') :PathPart('') :CaptureArgs(1) { + my ($self, $c, $tmpl_id) = @_; + + $c->detach('/denied_page') + if($c->user->read_only); + + unless($tmpl_id && $tmpl_id->is_integer) { + NGCP::Panel::Utils::Message->error( + c => $c, + log => 'Invalid email template id detected', + desc => $c->log('Invalid email template id detected'), + ); + $c->response->redirect($c->uri_for()); + $c->detach; + return; + } + + my $res = $c->stash->{tmpl_rs}->find($tmpl_id); + unless(defined($res)) { + NGCP::Panel::Utils::Message->error( + c => $c, + log => 'Email template does not exist', + desc => $c->log('Email template does not exist'), + ); + $c->response->redirect($c->uri_for()); + $c->detach; + return; + } + + $c->stash->{tmpl} = $res; +} + +sub tmpl_delete :Chained('tmpl_base') :PathPart('delete') { + my ($self, $c) = @_; + + try { + # manually delete hosts in group to let triggers hit in + $c->stash->{tmpl}->delete; + $c->flash(messages => [{type => 'success', text => $c->loc('Email template successfully deleted') }]); + } catch ($e) { + NGCP::Panel::Utils::Message->error( + c => $c, + error => $e, + desc => $c->loc('Failed to delete email template'), + ); + }; + $c->response->redirect($c->uri_for()); +} + +sub tmpl_edit :Chained('tmpl_base') :PathPart('edit') { + my ($self, $c) = @_; + + my $posted = ($c->request->method eq 'POST'); + my $form; + my $params = { $c->stash->{tmpl}->get_inflated_columns }; + $params->{reseller}{id} = delete $params->{reseller_id}; + $params = $params->merge($c->session->{created_objects}); + if($c->user->roles eq "admin") { + $form = NGCP::Panel::Form::EmailTemplate::Admin->new; + } elsif($c->user->roles eq "reseller") { + $form = NGCP::Panel::Form::EmailTemplate::Reseller->new; + } + $form->process( + posted => $posted, + params => $c->request->params, + item => $params, + ); + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => { + 'reseller.create' => $c->uri_for('/reseller/create'), + }, + back_uri => $c->req->uri, + ); + if($posted && $form->validated) { + try { + if($c->user->roles eq "admin") { + $form->values->{reseller_id} = $form->values->{reseller}{id}; + } elsif($c->user->roles eq "reseller") { + # don't allow to change reseller id + } + delete $form->values->{reseller}; + $c->model('DB')->txn_do(sub { + $c->stash->{tmpl}->update($form->values); + + }); + delete $c->session->{created_objects}->{reseller}; + $c->flash(messages => [{type => 'success', text => $c->loc('Email template successfully updated')}]); + } catch($e) { + NGCP::Panel::Utils::Message->error( + c => $c, + error => $e, + desc => $c->loc('Failed to update email template'), + ); + }; + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/emailtemplate')); + } + + $c->stash( + form => $form, + edit_flag => 1, + ); +} + + +sub send_test :Chained('tmpl_list') :PathPart('test') :Args(0) { + my ($self, $c) = @_; + + $c->stash( + template => 'emailtemplate/test.tt', + username => 'foobar', + url => 'http://foo.example.com', + ); + + $c->forward($c->view('TT')); + my $body = $c->res->body; + $c->res->body(undef); + $c->email( + header => [ + From => 'noreply@yoursipserver.com', + To => 'agranig@sipwise.com', + Subject => 'test from catalyst ' . time, + ], + body => $body, + ); + + $c->res->redirect($c->uri_for('/')); +} + +__PACKAGE__->meta->make_immutable; +1; +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/EmailTemplate/Admin.pm b/lib/NGCP/Panel/Form/EmailTemplate/Admin.pm new file mode 100644 index 0000000000..7e03ef9298 --- /dev/null +++ b/lib/NGCP/Panel/Form/EmailTemplate/Admin.pm @@ -0,0 +1,20 @@ +package NGCP::Panel::Form::EmailTemplate::Admin; + +use HTML::FormHandler::Moose; +extends 'NGCP::Panel::Form::EmailTemplate::Reseller'; +use Moose::Util::TypeConstraints; + +has_field 'reseller' => ( + type => '+NGCP::Panel::Field::Reseller', + validate_when_empty => 1, +); + +has_block 'fields' => ( + tag => 'div', + class => [qw/modal-body/], + render_list => [qw/reseller name from_email subject body/], +); + +1; + +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/EmailTemplate/Reseller.pm b/lib/NGCP/Panel/Form/EmailTemplate/Reseller.pm new file mode 100644 index 0000000000..6b2a2f9747 --- /dev/null +++ b/lib/NGCP/Panel/Form/EmailTemplate/Reseller.pm @@ -0,0 +1,76 @@ +package NGCP::Panel::Form::EmailTemplate::Reseller; + +use HTML::FormHandler::Moose; +extends 'HTML::FormHandler'; +use Moose::Util::TypeConstraints; + +use HTML::FormHandler::Widget::Block::Bootstrap; + +has '+widget_wrapper' => ( default => 'Bootstrap' ); +has_field 'submitid' => ( type => 'Hidden' ); +sub build_render_list {[qw/submitid fields actions/]} +sub build_form_element_class {[qw(form-horizontal)]} + +has_field 'name' => ( + type => 'Text', + label => 'Name', + required => 1, + maxlength => 255, +); + +has_field 'from_email' => ( + type => 'Email', + label => 'From Email Address', + required => 1, +); + +has_field 'subject' => ( + type => 'Text', + label => 'Subject', + required => 1, + maxlength => 255, +); + +has_field 'body' => ( + type => 'TextArea', + required => 1, + label => 'Body Template', + cols => 200, + rows => 10, + maxlength => '67108864', # 64MB + element_class => [qw/ngcp-autoconf-area/], + default => +'Dear Customer, + +A new subscriber [% subscriber %] has been created. + +Go to [% url %] to log into your self-care interface. + +Your faithful Sipwise system + +-- +This is an automatically generated message. Do not reply. ' +); + +has_field 'save' => ( + type => 'Submit', + value => 'Save', + element_class => [qw/btn btn-primary/], + label => '', +); + +has_block 'fields' => ( + tag => 'div', + class => [qw/modal-body/], + render_list => [qw/name from_email subject body/], +); + +has_block 'actions' => ( + tag => 'div', + class => [qw/modal-footer/], + render_list => [qw/save/], +); + +1; + +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/View/TT.pm b/lib/NGCP/Panel/View/TT.pm new file mode 100644 index 0000000000..a69219697a --- /dev/null +++ b/lib/NGCP/Panel/View/TT.pm @@ -0,0 +1,40 @@ +package NGCP::Panel::View::TT; + +use strict; +use base 'Catalyst::View::TT'; + +__PACKAGE__->config( + TEMPLATE_EXTENSION => '.tt', + render_die => 1, + ENCODING => 'UTF-8', + FILTERS => { + uri_unescape => sub { + URI::Escape::uri_unescape(@_); + }, + }, +); + +=head1 NAME + +NGCP::Panel::View::TT - Catalyst plain TT View + +=head1 SYNOPSIS + +See L + +=head1 DESCRIPTION + +Catalyst JSON View. + +=head1 AUTHOR + +Gerhard,,, + +=head1 LICENSE + +This library is free software, you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + +1; diff --git a/share/templates/emailtemplate/list.tt b/share/templates/emailtemplate/list.tt new file mode 100644 index 0000000000..af4e3adf24 --- /dev/null +++ b/share/templates/emailtemplate/list.tt @@ -0,0 +1,27 @@ +[% site_config.title = c.loc('Email Templates') -%] +[% + helper.name = c.loc('Email Template'); + helper.identifier = 'email_template'; + helper.messages = messages; + helper.dt_columns = template_dt_columns; + helper.length_change = 1; + + helper.close_target = close_target; + helper.create_flag = create_flag; + helper.edit_flag = edit_flag; + helper.form_object = form; + helper.ajax_uri = c.uri_for_action("/emailtemplate/tmpl_ajax"); + + UNLESS c.user.read_only; + helper.dt_buttons = [ + { name = c.loc('Edit'), uri = "/emailtemplate/'+full.id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, + { name = c.loc('Delete'), uri = "/emailtemplate/'+full.id+'/delete", class = 'btn-small btn-secondary', icon = 'icon-trash' }, + ]; + helper.top_buttons = [ + { name = c.loc('Create Email Template'), uri = c.uri_for('/emailtemplate/create'), icon = 'icon-star' }, + ]; + END; + + PROCESS 'helpers/datatables.tt'; +-%] +[% # vim: set tabstop=4 syntax=html expandtab: -%] diff --git a/share/templates/emailtemplate/test.tt b/share/templates/emailtemplate/test.tt new file mode 100644 index 0000000000..854d4c76ac --- /dev/null +++ b/share/templates/emailtemplate/test.tt @@ -0,0 +1,7 @@ +Hi, [% username %]! + +Please visit [% url %]. lalalala. + +-- +Regards, +test foo diff --git a/share/templates/widgets/admin_topmenu_settings.tt b/share/templates/widgets/admin_topmenu_settings.tt index ffc3601761..1c7c5dfb93 100644 --- a/share/templates/widgets/admin_topmenu_settings.tt +++ b/share/templates/widgets/admin_topmenu_settings.tt @@ -32,6 +32,7 @@
  • [% c.loc('Rewrite Rule Sets') %]
  • [% c.loc('NCOS Levels') %]
  • [% c.loc('Sound Sets') %]
  • +
  • [% c.loc('Email Templates') %]
  • [% c.loc('Security Bans') %]
  • [% IF c.config.features.cloudpbx -%]
  • [% c.loc('Device Management') %]
  • diff --git a/share/templates/widgets/reseller_topmenu_settings.tt b/share/templates/widgets/reseller_topmenu_settings.tt index 1edfb35ec2..9aa8f1c6bf 100644 --- a/share/templates/widgets/reseller_topmenu_settings.tt +++ b/share/templates/widgets/reseller_topmenu_settings.tt @@ -16,6 +16,7 @@
  • [% c.loc('Rewrite Rule Sets') %]
  • [% c.loc('NCOS Levels') %]
  • [% c.loc('Sound Sets') %]
  • +
  • [% c.loc('Email Templates') %]
  • [% IF c.config.features.cloudpbx -%]
  • [% c.loc('Device Management') %]
  • [% END -%]