From d37314bfc15aa0cf892c0c0d5c6da203cfb513d5 Mon Sep 17 00:00:00 2001 From: Lars Dieckow Date: Wed, 26 Jun 2013 16:34:03 +0200 Subject: [PATCH] create reseller with defaults --- Build.PL | 2 + lib/NGCP/Panel/Controller/Administrator.pm | 6 +- lib/NGCP/Panel/Controller/Reseller.pm | 188 ++++++++++++++++++--- share/templates/helpers/datatables.tt | 4 +- share/templates/reseller/details.tt | 108 ++++++++++++ share/templates/reseller/list.tt | 1 + 6 files changed, 281 insertions(+), 28 deletions(-) create mode 100644 share/templates/reseller/details.tt diff --git a/Build.PL b/Build.PL index 577edc9ac9..489ef8140e 100644 --- a/Build.PL +++ b/Build.PL @@ -27,6 +27,7 @@ my $builder = Local::Module::Build->new( 'Catalyst::View::JSON' => 0, 'Catalyst::View::TT' => 0, 'Config::General' => 0, + 'DateTime' => 0, 'HTML::FormHandler' => 0, 'HTML::FormHandler::Field' => 0, 'HTML::FormHandler::Field::Compound' => 0, @@ -34,6 +35,7 @@ my $builder = Local::Module::Build->new( 'HTML::FormHandler::Model::DBIC' => 0, 'HTML::FormHandler::Moose' => 0, 'HTML::FormHandler::Widget::Block::Bootstrap' => 0, + 'HTTP::Status' => 0, 'Log::Log4perl::Catalyst' => 0, 'Module::Runtime' => 0, 'Moose' => 2, diff --git a/lib/NGCP/Panel/Controller/Administrator.pm b/lib/NGCP/Panel/Controller/Administrator.pm index 9cb4e8d352..84d01b72c1 100644 --- a/lib/NGCP/Panel/Controller/Administrator.pm +++ b/lib/NGCP/Panel/Controller/Administrator.pm @@ -10,10 +10,8 @@ use NGCP::Panel::Utils qw(); sub list_admin :PathPart('administrator') :Chained('/') :CaptureArgs(0) { my ($self, $c) = @_; $c->stash( - admins => $c->model('billing') - ->resultset('admins') - ->search_rs({is_superuser => 1}), - template => 'administrator/list.tt' + admins => $c->model('billing')->resultset('admins'), + template => 'administrator/list.tt', ); return; } diff --git a/lib/NGCP/Panel/Controller/Reseller.pm b/lib/NGCP/Panel/Controller/Reseller.pm index 1c3d45dcc0..cbfe9adf1f 100644 --- a/lib/NGCP/Panel/Controller/Reseller.pm +++ b/lib/NGCP/Panel/Controller/Reseller.pm @@ -2,23 +2,11 @@ package NGCP::Panel::Controller::Reseller; use Sipwise::Base; use namespace::sweep; BEGIN { extends 'Catalyst::Controller'; } +use DateTime qw(); +use HTTP::Status qw(HTTP_SEE_OTHER); use NGCP::Panel::Form::Reseller; use NGCP::Panel::Utils; -use Data::Printer; - -=head1 NAME - -NGCP::Panel::Controller::Reseller - Catalyst Controller - -=head1 DESCRIPTION - -Catalyst Controller. - -=head1 METHODS - -=cut - sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; $c->log->debug(__PACKAGE__ . '::auto'); @@ -108,6 +96,63 @@ sub base :Chained('list_reseller') :PathPart('') :CaptureArgs(1) { $c->stash(reseller => $c->stash->{resellers}->find({id => $reseller_id})); } +sub reseller_contacts :Chained('base') :PathPart('contacts') :Args(0) { + my ($self, $c) = @_; + $c->forward( + '/ajax_process_resultset', [ + $c->model('billing')->resultset('contacts') + ->search_rs({ id => $c->stash->{reseller}->related_resultset('contract')->find( + $c->stash->{resellers}->find($c->req->captures->[0])->contract_id + )->contact_id }), + [qw(id firstname lastname email create_timestamp)], + [ 1, ] + ] + ); + $c->detach($c->view('JSON')); + return; +} + +sub reseller_contracts :Chained('base') :PathPart('contracts') :Args(0) { + my ($self, $c) = @_; + $c->forward( + '/ajax_process_resultset', [ + $c->stash->{reseller}->search_related_rs( + 'contract', { id => $c->stash->{resellers}->find($c->req->captures->[0])->contract_id } + ), + [qw(id contact_id)], + [ 1, ] + ] + ); + $c->detach($c->view('JSON')); + return; +} + +sub reseller_single :Chained('base') :PathPart('single') :Args(0) { + my ($self, $c) = @_; + $c->forward( + '/ajax_process_resultset', [ + $c->stash->{resellers}->search_rs({ id => $c->req->captures->[0] }), + [qw(id contract_id name status)], + [ 1, ] + ] + ); + $c->detach($c->view('JSON')); + return; +} + +sub reseller_admin :Chained('base') :PathPart('admin') :Args(0) { + my ($self, $c) = @_; + $c->forward( + '/ajax_process_resultset', [ + $c->stash->{reseller}->related_resultset('admins')->search_rs({ reseller_id => $c->req->captures->[0] }), + [qw(id reseller_id login)], + [ 1, ] + ] + ); + $c->detach($c->view('JSON')); + return; +} + sub edit :Chained('base') :PathPart('edit') :Args(0) { my ($self, $c) = @_; @@ -160,6 +205,12 @@ sub delete :Chained('base') :PathPart('delete') :Args(0) { $c->response->redirect($c->uri_for()); } +sub details :Chained('base') :PathPart('details') :Args(0) { + my ($self, $c) = @_; + $c->stash(template => 'reseller/details.tt'); + return; +} + sub ajax_contract :Chained('list_reseller') :PathPart('ajax_contract') :Args(0) { my ($self, $c) = @_; @@ -186,6 +237,107 @@ sub ajax_contract :Chained('list_reseller') :PathPart('ajax_contract') :Args(0) $c->detach( $c->view("JSON") ); } +sub create_defaults :Path('create_defaults') :Args(0) { + my ($self, $c) = @_; + $c->detach('/denied_page') unless $c->request->method eq 'POST'; + my $now = DateTime->now; + my %defaults = ( + contacts => { + firstname => 'Default', + lastname => 'Contact', + email => 'default_contact@example.invalid', # RFC 2606 + create_timestamp => $now, + }, + contracts => { + status => 'active', + create_timestamp => $now, + activate_timestamp => $now, + }, + resellers => { + name => 'Default reseller' . sprintf('%04d', rand 10000), + status => 'active', + }, + billing_mappings => { + start_date => $now, + }, + admins => { + md5pass => 'defaultresellerpassword', + is_active => 1, + show_passwords => 1, + call_data => 1, + }, + ); + my $billing = $c->model('billing'); + my %r; + try { + $billing->txn_do(sub { + $r{contacts} = $billing->resultset('contacts')->create({ %{ $defaults{contacts} } }); + $r{contracts} = $billing->resultset('contracts')->create({ + %{ $defaults{contracts} }, + contact_id => $r{contacts}->id, + }); + $r{resellers} = $billing->resultset('resellers')->create({ + %{ $defaults{resellers} }, + contract_id => $r{contracts}->id, + }); + $r{billing_mappings} = $billing->resultset('billing_mappings')->create({ + %{ $defaults{billing_mappings} }, + billing_profile_id => 1, + contract_id => $r{contracts}->id, + product_id => $billing->resultset('products')->search({ class => 'reseller' })->first->id, + }); + $r{admins} = $billing->resultset('admins')->create({ + %{ $defaults{admins} }, + reseller_id => $r{resellers}->id, + login => $r{resellers}->name =~ tr/A-Za-z0-9//cdr, + }); + }); + } catch($e) { + $c->log->error($e); + $c->flash(messages => [{type => 'error', text => 'Creating reseller failed.'}]); + }; + $c->flash(messages => [{type => 'success', text => 'Reseller successfully created, review:'}]); + $c->res->redirect(sprintf('/reseller/%d/details', $r{resellers}->id), HTTP_SEE_OTHER); + $c->detach; + return; +} + +__PACKAGE__->meta->make_immutable; + +__END__ + +=encoding UTF-8 + +=head1 NAME + +NGCP::Panel::Controller::Reseller - Catalyst Controller + +=head1 DESCRIPTION + +Catalyst Controller. + +=head1 METHODS + +=head2 C + +=head2 C + +=head2 C + +=head2 C + +These are Ajax actions called from L, rendering datatables with a single result each. + +=head2 C
+ +Renders the F template, whose datatables relate to and are derived from a reseller id in the +captures. + +=head2 C + +Creates a reseller with all dependent contract, contact, billing mapping, admin login in a single step with default +values. Redirects to L
. + =head1 AUTHOR Andreas Granig,,, @@ -194,11 +346,3 @@ Andreas Granig,,, This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself. - -=cut - -__PACKAGE__->meta->make_immutable; - -1; - -# vim: set tabstop=4 expandtab: diff --git a/share/templates/helpers/datatables.tt b/share/templates/helpers/datatables.tt index bb25bd28d6..b936b37406 100644 --- a/share/templates/helpers/datatables.tt +++ b/share/templates/helpers/datatables.tt @@ -13,7 +13,8 @@ $(document).ready(function() { "sDom": "<'row'<'span6'r><'span6'f>>t<'row'<'span6'i><'span6'p>>", "bProcessing": true, "bServerSide": true, - "bPaginate": true, + "bPaginate": [% helper.paginate || 'true' %], + "bFilter": [% helper.filter || 'true' %], "sPaginationType": "bootstrap", "bLengthChange": true, "bSort": true, @@ -52,7 +53,6 @@ $(document).ready(function() { return nRow; }, } ); - } ); diff --git a/share/templates/reseller/details.tt b/share/templates/reseller/details.tt new file mode 100644 index 0000000000..66863daf17 --- /dev/null +++ b/share/templates/reseller/details.tt @@ -0,0 +1,108 @@ +[% META title = 'Reseller Details' -%] + +[% FOREACH m IN messages -%] +
[% m.text %]
+[% END -%] + +
+
+
+ Contact +
+
+
+[% + helper.name = 'Contact'; + helper.messages = messages; + helper.column_titles = [ '#', 'First name', 'Last name', 'Email address', 'created' ]; + helper.column_fields = [ 'id', 'firstname', 'lastname', 'email', 'create_timestamp' ]; + helper.paginate = 'false'; + helper.filter = 'false'; + helper.close_target = c.uri_for(''); + helper.create_flag = create_flag; + helper.edit_flag = edit_flag; + helper.form_object = form; + helper.ajax_uri = c.uri_for_action('/reseller/reseller_contacts', c.req.captures ); + helper.base_uri = c.uri_for_action('/contact/root'); + + PROCESS 'helpers/datatables.tt'; +-%] +
+
+
+
+
+ Contract +
+
+
+[% + helper.name = 'Contract'; + helper.messages = messages; + helper.column_titles = [ '#', 'Contact #']; + helper.column_fields = [ 'id', 'contact_id']; + helper.paginate = 'false'; + helper.filter = 'false'; + 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('/reseller/reseller_contracts', c.req.captures ); + helper.base_uri = c.uri_for_action('/contract/root'); + + PROCESS 'helpers/datatables.tt'; +-%] +
+
+
+
+
+ Reseller +
+
+
+[% + helper.name = 'Reseller'; + helper.messages = messages; + helper.column_titles = [ '#', 'Contract #', 'Name', 'Status' ]; + helper.column_fields = [ 'id', 'contract_id', 'name', 'status' ]; + helper.paginate = 'false'; + helper.filter = 'false'; + 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('/reseller/reseller_single', c.req.captures ); + helper.base_uri = c.uri_for_action('/reseller/root'); + + PROCESS 'helpers/datatables.tt'; +-%] +
+
+
+
+ +
+
+[% + helper.name = 'Administrator'; + helper.messages = messages; + helper.column_titles = [ '#', 'Reseller #', 'Login' ]; + helper.column_fields = [ 'id', 'reseller_id', 'login' ]; + helper.paginate = 'false'; + helper.filter = 'false'; + 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('/reseller/reseller_admin', c.req.captures ); + helper.base_uri = c.uri_for_action('/administrator/root'); + + PROCESS 'helpers/datatables.tt'; +-%] +
+
+
+
diff --git a/share/templates/reseller/list.tt b/share/templates/reseller/list.tt index 3cf6162974..8756f4ea11 100644 --- a/share/templates/reseller/list.tt +++ b/share/templates/reseller/list.tt @@ -18,6 +18,7 @@ ]; helper.top_buttons = [ { name = 'Create Reseller', uri = c.uri_for('/reseller/create'), icon = 'icon-star' }, + { name = 'Create Reseller with default values', uri = c.uri_for('/reseller/create_defaults'), icon = 'icon-star' }, ]; PROCESS 'helpers/datatables.tt';