From 32f704451ac9d8724ea9e834c09b31f01e88c623 Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Mon, 31 Mar 2014 09:48:32 +0200 Subject: [PATCH 01/13] MT#6459 Fix peering contract and peer auth pref. - Properly call localization functions on error when changing peering contract. - Properly handle preference update in case of empty value. Reported by Marc Storck on spce-users. --- lib/NGCP/Panel/Controller/Peering.pm | 4 +- lib/NGCP/Panel/Utils/Preferences.pm | 239 ++++++++++++++++++--------- 2 files changed, 159 insertions(+), 84 deletions(-) diff --git a/lib/NGCP/Panel/Controller/Peering.pm b/lib/NGCP/Panel/Controller/Peering.pm index 4595b6ae6b..fa4723a1d0 100644 --- a/lib/NGCP/Panel/Controller/Peering.pm +++ b/lib/NGCP/Panel/Controller/Peering.pm @@ -119,12 +119,12 @@ sub edit :Chained('base') :PathPart('edit') { $c->stash->{group_result}->update($form->custom_get_values); $self->_sip_lcr_reload; delete $c->session->{created_objects}->{contract}; - $c->flash(messages => [{type => 'success', text => $c->('Peering group successfully updated')}]); + $c->flash(messages => [{type => 'success', text => $c->loc('Peering group successfully updated')}]); } catch ($e) { NGCP::Panel::Utils::Message->error( c => $c, error => $e, - desc => $c->('Failed to update peering group.'), + desc => $c->loc('Failed to update peering group.'), ); }; NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for) diff --git a/lib/NGCP/Panel/Utils/Preferences.pm b/lib/NGCP/Panel/Utils/Preferences.pm index e3fed5d387..3ddc49e5bb 100644 --- a/lib/NGCP/Panel/Utils/Preferences.pm +++ b/lib/NGCP/Panel/Utils/Preferences.pm @@ -214,68 +214,102 @@ sub create_preference_form { back_uri => $c->req->uri, ); if($posted && $form->validated) { - my $preference_id = $c->stash->{preference}->first ? $c->stash->{preference}->first->id : undef; - my $attribute = $c->stash->{preference_meta}->attribute; + my $preference_id = $c->stash->{preference}->first ? $c->stash->{preference}->first->id : undef; + my $attribute = $c->stash->{preference_meta}->attribute; if ($attribute eq "allowed_ips") { unless(validate_ipnet($form->field($attribute))) { goto OUT; } unless (defined $aip_group_id) { - #TODO put this in a transaction - my $new_group = $c->model('DB')->resultset('voip_aig_sequence') - ->create({}); - my $aig_preference_id = $c->model('DB') - ->resultset('voip_preferences') - ->find({ attribute => 'allowed_ips_grp' }) - ->id; - $pref_rs->create({ - value => $new_group->id, - attribute_id => $aig_preference_id, - }); - $aip_group_id = $new_group->id; - $aip_grp_rs = $c->model('DB')->resultset('voip_allowed_ip_groups') - ->search({ group_id => $aip_group_id }); - $c->model('DB')->resultset('voip_aig_sequence')->search_rs({ - id => { '<' => $new_group->id }, - })->delete_all; + try { + my $new_group = $c->model('DB')->resultset('voip_aig_sequence') + ->create({}); + my $aig_preference_id = $c->model('DB') + ->resultset('voip_preferences') + ->find({ attribute => 'allowed_ips_grp' }) + ->id; + $pref_rs->create({ + value => $new_group->id, + attribute_id => $aig_preference_id, + }); + $aip_group_id = $new_group->id; + $aip_grp_rs = $c->model('DB')->resultset('voip_allowed_ip_groups') + ->search({ group_id => $aip_group_id }); + $c->model('DB')->resultset('voip_aig_sequence')->search_rs({ + id => { '<' => $new_group->id }, + })->delete_all; + } catch($e) { + $c->log->error("failed to generate ip group sequence: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to generate ip group sequence."}]); + $c->response->redirect($base_uri); + return 1; + } + } + try { + $aip_grp_rs->create({ + group_id => $aip_group_id, + ipnet => $form->field($attribute)->value, + }); + } catch($e) { + $c->log->error("failed to create allowed_ip_grp: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to create allowed_ip_grp."}]); + $c->response->redirect($base_uri); + return 1; } - $aip_grp_rs->create({ - group_id => $aip_group_id, - ipnet => $form->field($attribute)->value, - }); } elsif ($attribute eq "man_allowed_ips") { unless(validate_ipnet($form->field($attribute))) { goto OUT; } unless (defined $man_aip_group_id) { - #TODO put this in a transaction - my $new_group = $c->model('DB')->resultset('voip_aig_sequence') - ->create({}); - my $man_aig_preference_id = $c->model('DB') - ->resultset('voip_preferences') - ->find({ attribute => 'man_allowed_ips_grp' }) - ->id; - $pref_rs->create({ - value => $new_group->id, - attribute_id => $man_aig_preference_id, - }); - $man_aip_group_id = $new_group->id; - $man_aip_grp_rs = $c->model('DB')->resultset('voip_allowed_ip_groups') - ->search({ group_id => $man_aip_group_id }); - $c->model('DB')->resultset('voip_aig_sequence')->search_rs({ - id => { '<' => $new_group->id }, - })->delete_all; + try { + my $new_group = $c->model('DB')->resultset('voip_aig_sequence') + ->create({}); + my $man_aig_preference_id = $c->model('DB') + ->resultset('voip_preferences') + ->find({ attribute => 'man_allowed_ips_grp' }) + ->id; + $pref_rs->create({ + value => $new_group->id, + attribute_id => $man_aig_preference_id, + }); + $man_aip_group_id = $new_group->id; + $man_aip_grp_rs = $c->model('DB')->resultset('voip_allowed_ip_groups') + ->search({ group_id => $man_aip_group_id }); + $c->model('DB')->resultset('voip_aig_sequence')->search_rs({ + id => { '<' => $new_group->id }, + })->delete_all; + + } catch($e) { + $c->log->error("failed to create manual ip group sequence: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to generate manual ip group sequence."}]); + $c->response->redirect($base_uri); + return 1; + } + } + try { + $man_aip_grp_rs->create({ + group_id => $man_aip_group_id, + ipnet => $form->field($attribute)->value, + }); + } catch($e) { + $c->log->error("failed to create man_allowed_ip_grp: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to create man_allowed_ip_grp."}]); + $c->response->redirect($base_uri); + return 1; } - $man_aip_grp_rs->create({ - group_id => $man_aip_group_id, - ipnet => $form->field($attribute)->value, - }); } elsif ($c->stash->{preference_meta}->max_occur != 1) { - $pref_rs->create({ - attribute_id => $c->stash->{preference_meta}->id, - value => $form->field($c->stash->{preference_meta}->attribute)->value, - }); + try { + $pref_rs->create({ + attribute_id => $c->stash->{preference_meta}->id, + value => $form->field($c->stash->{preference_meta}->attribute)->value, + }); + } catch($e) { + $c->log->error("failed to create preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to delete preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; + } } elsif ($attribute eq "rewrite_rule_set") { my $selected_rwrs = $c->stash->{rwr_sets_rs}->find( $form->field($attribute)->value @@ -295,14 +329,20 @@ sub create_preference_form { my $attribute_id = $c->model('DB')->resultset('voip_preferences') ->find({attribute => $attribute."_id"})->id; - - my $preference = $pref_rs->search({ attribute_id => $attribute_id }); - if(!defined $selected_level) { - $preference->first->delete if $preference->first; - } elsif($preference->first) { - $preference->first->update({ value => $selected_level->id }); - } else { - $preference->create({ value => $selected_level->id }); + try { + my $preference = $pref_rs->search({ attribute_id => $attribute_id }); + if(!defined $selected_level) { + $preference->first->delete if $preference->first; + } elsif($preference->first) { + $preference->first->update({ value => $selected_level->id }); + } else { + $preference->create({ value => $selected_level->id }); + } + } catch($e) { + $c->log->error("failed to update preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to update preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; } $c->flash(messages => [{type => 'success', text => "Preference $attribute successfully updated."}]); @@ -313,14 +353,21 @@ sub create_preference_form { $form->field($attribute)->value ); - my $preference = $pref_rs->search({ - attribute_id => $c->stash->{preference_meta}->id }); - if(!defined $selected_set) { - $preference->first->delete if $preference->first; - } elsif($preference->first) { - $preference->first->update({ value => $selected_set->id }); - } else { - $preference->create({ value => $selected_set->id }); + try { + my $preference = $pref_rs->search({ + attribute_id => $c->stash->{preference_meta}->id }); + if(!defined $selected_set) { + $preference->first->delete if $preference->first; + } elsif($preference->first) { + $preference->first->update({ value => $selected_set->id }); + } else { + $preference->create({ value => $selected_set->id }); + } + } catch($e) { + $c->log->error("failed to update preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to update preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; } $c->flash(messages => [{type => 'success', text => "Preference $attribute successfully updated."}]); @@ -331,14 +378,21 @@ sub create_preference_form { $form->field($attribute)->value ); - my $preference = $pref_rs->search({ - attribute_id => $c->stash->{preference_meta}->id }); - if(!defined $selected_set) { - $preference->first->delete if $preference->first; - } elsif($preference->first) { - $preference->first->update({ value => $selected_set->id }); - } else { - $preference->create({ value => $selected_set->id }); + try { + my $preference = $pref_rs->search({ + attribute_id => $c->stash->{preference_meta}->id }); + if(!defined $selected_set) { + $preference->first->delete if $preference->first; + } elsif($preference->first) { + $preference->first->update({ value => $selected_set->id }); + } else { + $preference->create({ value => $selected_set->id }); + } + } catch($e) { + $c->log->error("failed to update preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to update preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; } $c->flash(messages => [{type => 'success', text => "Preference $attribute successfully updated."}]); @@ -346,22 +400,43 @@ sub create_preference_form { return 1; } else { if( ($c->stash->{preference_meta}->data_type ne 'enum' && - $form->field($attribute)->value eq '') || + (!defined $form->field($attribute)->value || $form->field($attribute)->value eq '')) || ($c->stash->{preference_meta}->data_type eq 'enum' && ! defined $form->field($attribute)->value) ) { - my $preference = $pref_rs->find($preference_id); - $preference->delete if $preference; + try { + my $preference = $pref_rs->find($preference_id); + $preference->delete if $preference; + } catch($e) { + $c->log->error("failed to delete preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to delete preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; + } } elsif($c->stash->{preference_meta}->data_type eq 'boolean' && $form->field($attribute)->value == 0) { - my $preference = $pref_rs->find($preference_id); - $preference->delete if $preference; + try { + my $preference = $pref_rs->find($preference_id); + $preference->delete if $preference; + } catch($e) { + $c->log->error("failed to delete preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to delete preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; + } } else { - $pref_rs->update_or_create({ - id => $preference_id, - attribute_id => $c->stash->{preference_meta}->id, - value => $form->field($attribute)->value, - }); + try { + $pref_rs->update_or_create({ + id => $preference_id, + attribute_id => $c->stash->{preference_meta}->id, + value => $form->field($attribute)->value, + }); + } catch($e) { + $c->log->error("failed to update preference $attribute: $e"); + $c->flash(messages => [{type => 'error', text => "Failed to update preference $attribute."}]); + $c->response->redirect($base_uri); + return 1; + } } $c->flash(messages => [{type => 'success', text => "Preference $attribute successfully updated."}]); $c->response->redirect($base_uri); From 51b508fd60321abfe6b5a11095c7f1c69e2e6bee Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Fri, 28 Mar 2014 14:32:24 +0100 Subject: [PATCH 02/13] MT#6443 Calculate dashboard costs correctly --- .../Widget/Plugin/AdminBillingOverview.pm | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/NGCP/Panel/Widget/Plugin/AdminBillingOverview.pm b/lib/NGCP/Panel/Widget/Plugin/AdminBillingOverview.pm index 4f729e972a..5faa41aea4 100644 --- a/lib/NGCP/Panel/Widget/Plugin/AdminBillingOverview.pm +++ b/lib/NGCP/Panel/Widget/Plugin/AdminBillingOverview.pm @@ -30,29 +30,35 @@ around handle => sub { peering_sum => $c->model('DB')->resultset('contract_balances')->search_rs({ 'start' => { '>=' => $stime }, 'end' => { '<' => $etime}, - 'product.class' => 'sippeering', - }, { - join => { - 'contract' => { 'billing_mappings' => 'product' }, - }, + -exists => $c->model('DB')->resultset('billing_mappings')->search({ + contract_id => \'= me.contract_id', + 'product.class' => 'sippeering', + },{ + alias => 'myinner', + join => 'product', + })->as_query, })->get_column('cash_balance_interval')->sum, reseller_sum => $c->model('DB')->resultset('contract_balances')->search_rs({ 'start' => { '>=' => $stime }, 'end' => { '<' => $etime}, - 'product.class' => 'reseller', - }, { - join => { - 'contract' => { 'billing_mappings' => 'product' }, - }, + -exists => $c->model('DB')->resultset('billing_mappings')->search({ + contract_id => \'= me.contract_id', + 'product.class' => 'reseller', + },{ + alias => 'myinner', + join => 'product', + })->as_query, })->get_column('cash_balance_interval')->sum, customer_sum => $c->model('DB')->resultset('contract_balances')->search_rs({ 'start' => { '>=' => $stime }, 'end' => { '<' => $etime}, - 'billing_mappings.product_id' => undef, - }, { - join => { - 'contract' => 'billing_mappings', - }, + -exists => $c->model('DB')->resultset('billing_mappings')->search({ + contract_id => \'= me.contract_id', + 'product.class' => 'sipaccount', + },{ + alias => 'myinner', + join => 'product', + })->as_query, })->get_column('cash_balance_interval')->sum, ); return; From 7cbb8633ab9f6ef194ebc3f0efdf717031e755e0 Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Mon, 31 Mar 2014 12:59:15 +0200 Subject: [PATCH 03/13] MT#6461 Let admin rebrand reseller. Reseller rebranding itself not yet there. --- lib/NGCP/Panel/Controller/Reseller.pm | 154 +++++++++++++++++++++-- lib/NGCP/Panel/Form/Reseller/Branding.pm | 51 ++++++++ share/layout/html.tt | 9 ++ share/templates/reseller/details.tt | 63 ++++++++++ 4 files changed, 265 insertions(+), 12 deletions(-) create mode 100644 lib/NGCP/Panel/Form/Reseller/Branding.pm diff --git a/lib/NGCP/Panel/Controller/Reseller.pm b/lib/NGCP/Panel/Controller/Reseller.pm index 5394942650..8bcd6d09e9 100644 --- a/lib/NGCP/Panel/Controller/Reseller.pm +++ b/lib/NGCP/Panel/Controller/Reseller.pm @@ -4,13 +4,15 @@ use namespace::sweep; BEGIN { extends 'Catalyst::Controller'; } use DateTime qw(); use HTTP::Status qw(HTTP_SEE_OTHER); +use File::Type; use NGCP::Panel::Form::Reseller; +use NGCP::Panel::Form::Reseller::Branding; use NGCP::Panel::Utils::Contract; use NGCP::Panel::Utils::DateTime; use NGCP::Panel::Utils::Message; use NGCP::Panel::Utils::Navigation; -sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { +sub auto { my ($self, $c) = @_; $c->log->debug(__PACKAGE__ . '::auto'); NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c); @@ -45,11 +47,11 @@ sub list_reseller :Chained('/') :PathPart('reseller') :CaptureArgs(0) { ]); } -sub root :Chained('list_reseller') :PathPart('') :Args(0) { +sub root :Chained('list_reseller') :PathPart('') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; } -sub ajax :Chained('list_reseller') :PathPart('ajax') :Args(0) { +sub ajax :Chained('list_reseller') :PathPart('ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; my $resellers = $c->stash->{resellers}; NGCP::Panel::Utils::Datatables::process($c, $resellers, $c->stash->{reseller_dt_columns}); @@ -57,7 +59,7 @@ sub ajax :Chained('list_reseller') :PathPart('ajax') :Args(0) { return; } -sub create :Chained('list_reseller') :PathPart('create') :Args(0) { +sub create :Chained('list_reseller') :PathPart('create') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; $c->detach('/denied_page') @@ -116,6 +118,9 @@ sub base :Chained('list_reseller') :PathPart('') :CaptureArgs(1) { $c->response->redirect($c->uri_for()); return; } + $c->detach('/denied_page') + if($c->user->roles eq "reseller" && $c->user->reseller_id != $reseller_id); + $c->stash->{contact_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ { name => "id", search => 1, title => $c->loc('#') }, { name => "firstname", search => 1, title => $c->loc('First Name') }, @@ -159,9 +164,12 @@ sub base :Chained('list_reseller') :PathPart('') :CaptureArgs(1) { ); NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/reseller')); } + + $c->stash->{branding} = $c->stash->{reseller}->first->branding; + } -sub reseller_contacts :Chained('base') :PathPart('contacts/ajax') :Args(0) { +sub reseller_contacts :Chained('base') :PathPart('contacts/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; my $rs = $c->stash->{reseller}->first->contract->search_related_rs('contact'); NGCP::Panel::Utils::Datatables::process($c, $rs, $c->stash->{contact_dt_columns}); @@ -169,7 +177,7 @@ sub reseller_contacts :Chained('base') :PathPart('contacts/ajax') :Args(0) { return; } -sub reseller_single :Chained('base') :PathPart('single/ajax') :Args(0) { +sub reseller_single :Chained('base') :PathPart('single/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; NGCP::Panel::Utils::Datatables::process($c, $c->stash->{reseller}, $c->stash->{reseller_dt_columns}); @@ -177,7 +185,7 @@ sub reseller_single :Chained('base') :PathPart('single/ajax') :Args(0) { return; } -sub reseller_admin :Chained('base') :PathPart('admins/ajax') :Args(0) { +sub reseller_admin :Chained('base') :PathPart('admins/ajax') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; my $rs = $c->stash->{reseller}->first->search_related_rs('admins'); NGCP::Panel::Utils::Datatables::process($c, $rs, $c->stash->{admin_dt_columns}); @@ -185,7 +193,7 @@ sub reseller_admin :Chained('base') :PathPart('admins/ajax') :Args(0) { return; } -sub edit :Chained('base') :PathPart('edit') :Args(0) { +sub edit :Chained('base') :PathPart('edit') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; $c->detach('/denied_page') @@ -247,7 +255,7 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { return; } -sub terminate :Chained('base') :PathPart('terminate') :Args(0) { +sub terminate :Chained('base') :PathPart('terminate') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; my $reseller = $c->stash->{reseller}->first; @@ -305,13 +313,13 @@ sub _handle_reseller_status_change { } } -sub details :Chained('base') :PathPart('details') :Args(0) { +sub details :Chained('base') :PathPart('details') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; $c->stash(template => 'reseller/details.tt'); return; } -sub ajax_contract :Chained('list_reseller') :PathPart('ajax_contract') :Args(0) { +sub ajax_contract :Chained('list_reseller') :PathPart('ajax_contract') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; my $edit_contract_id = $c->session->{edit_contract_id}; @@ -334,7 +342,7 @@ sub ajax_contract :Chained('list_reseller') :PathPart('ajax_contract') :Args(0) $c->detach( $c->view("JSON") ); } -sub create_defaults :Path('create_defaults') :Args(0) { +sub create_defaults :Path('create_defaults') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) { my ($self, $c) = @_; $c->detach('/denied_page') unless $c->request->method eq 'POST'; $c->detach('/denied_page') @@ -412,6 +420,128 @@ sub create_defaults :Path('create_defaults') :Args(0) { return; } +sub edit_branding_css :Chained('base') :PathPart('css/edit') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) { + my ($self, $c) = @_; + + $c->detach('/denied_page') + if($c->user->read_only); + $c->stash(template => 'reseller/details.tt'); + + my $reseller = $c->stash->{reseller}->first; + my $branding = $reseller->branding; + + my $posted = $c->request->method eq 'POST'; + my $form = NGCP::Panel::Form::Reseller::Branding->new; + + if($posted) { + $c->req->params->{logo} = $c->req->upload('logo'); + } + + my $params = $branding ? { $branding->get_inflated_columns } : {}; + $form->process( + posted => $posted, + params => $c->request->params, + item => $params, + ); + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, + back_uri => $c->uri_for('/reseller/details', $c->req->captures), + ); + + if($posted && $form->validated) { + try { + $c->model('DB')->txn_do(sub { + if($c->user->roles eq "admin") { + $form->params->{reseller_id} = $reseller->id; + } elsif($c->user->roles eq "reseller") { + $form->params->{reseller_id} = $c->user->reseller_id; + } + delete $form->params->{reseller}; + delete $form->params->{back}; + + my $ft = File::Type->new(); + if($form->params->{logo}) { + my $logo = delete $form->params->{logo}; + $form->params->{logo} = $logo->slurp; + $form->params->{logo_image_type} = $ft->mime_type($form->params->{logo}); + } else { + delete $form->params->{logo}; + } + + unless(defined $branding) { + $c->model('DB')->resultset('reseller_brandings')->create($form->params); + } else { + $branding->update($form->params); + } + }); + + $c->flash(messages => [{type => 'success', text => $c->loc('Reseller branding successfully updated')}]); + } catch($e) { + NGCP::Panel::Utils::Message->error( + c => $c, + error => $e, + desc => $c->loc('Failed to update reseller branding'), + ); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/reseller/details', $c->req->captures)); + } + + $c->stash(close_target => $c->uri_for()); + $c->stash(branding_form => $form); + $c->stash(branding_edit_flag => 1); + $c->stash(close_target => $c->uri_for_action('/reseller/details', $c->req->captures)); + + return; +} + +sub get_branding_logo :Chained('base') :PathPart('css/logo/download') :Args(0) { + my ($self, $c) = @_; + + + my $reseller = $c->stash->{reseller}->first; + my $branding = $reseller->branding; + + unless($branding || $branding->logo) { + $c->response->body($c->loc('404 - No branding logo available for this reseller')); + $c->response->status(404); + return; + } + $c->response->content_type($branding->logo_image_type); + $c->response->body($branding->logo); +} + +sub delete_branding_logo :Chained('base') :PathPart('css/logo/delete') :Args(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) { + my ($self, $c) = @_; + + + my $reseller = $c->stash->{reseller}->first; + my $branding = $reseller->branding; + + if($branding) { + $branding->update({ logo => undef, logo_image_type => undef }); + } + + $c->response->redirect($c->uri_for_action('/reseller/details', $c->req->captures)); +} + +sub get_branding_css :Chained('base') :PathPart('css/download') :Args(0) { + my ($self, $c) = @_; + + + my $reseller = $c->stash->{reseller}->first; + my $branding = $reseller->branding; + + unless($branding || $branding->css) { + $c->response->body($c->loc('404 - No branding css available for this reseller')); + $c->response->status(404); + return; + } + $c->response->content_type('text/css'); + $c->response->body($branding->css); +} + __PACKAGE__->meta->make_immutable; __END__ diff --git a/lib/NGCP/Panel/Form/Reseller/Branding.pm b/lib/NGCP/Panel/Form/Reseller/Branding.pm new file mode 100644 index 0000000000..9381dfc187 --- /dev/null +++ b/lib/NGCP/Panel/Form/Reseller/Branding.pm @@ -0,0 +1,51 @@ +package NGCP::Panel::Form::Reseller::Branding; + +use HTML::FormHandler::Moose; +extends 'HTML::FormHandler'; +use Moose::Util::TypeConstraints; + +use HTML::FormHandler::Widget::Block::Bootstrap; + +has '+widget_wrapper' => ( default => 'Bootstrap' ); +has '+enctype' => ( default => 'multipart/form-data'); +has_field 'submitid' => ( type => 'Hidden' ); +sub build_render_list {[qw/submitid fields actions/]} +sub build_form_element_class {[qw(form-horizontal)]} + +has_field 'logo' => ( + type => 'Upload', + required => 0, + label => 'Logo', + max_size => '67108864', # 64MB +); + +has_field 'css' => ( + type => 'TextArea', + label => 'CSS', + cols => 200, + rows => 10, + maxlength => '67108864', # 64MB + element_class => [qw/ngcp-autoconf-area/], +); + +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/logo css/], +); + +has_block 'actions' => ( + tag => 'div', + class => [qw/modal-footer/], + render_list => [qw/save/], +); + +1; +# vim: set tabstop=4 expandtab: diff --git a/share/layout/html.tt b/share/layout/html.tt index bef3465ee9..a81714998a 100644 --- a/share/layout/html.tt +++ b/share/layout/html.tt @@ -34,6 +34,15 @@ + + [% IF c.user -%] + [% IF c.user.roles == "reseller" && c.user.reseller.branding.css -%] + + [% ELSIF c.user.roles != "admin" && c.user.contract.contact.reseller.branding.css -%] + + [% END -%] + [% END -%] + [% content %] diff --git a/share/templates/reseller/details.tt b/share/templates/reseller/details.tt index ac626ed524..050adfbc92 100644 --- a/share/templates/reseller/details.tt +++ b/share/templates/reseller/details.tt @@ -220,5 +220,68 @@ +
+ +
+
+ + [% UNLESS c.user.read_only -%] + + Edit Branding + [% IF branding.logo -%] + Delete Logo + [% END -%] + +
+ [% END -%] + + [% IF branding.defined -%] + [% IF branding.logo.defined -%] +

Custom Logo

+ +

+ [% c.loc("You can use the logo by adding the following CSS to the Custom CSS below:") %] +

+#header .brand {
+    background: url([% c.uri_for_action('/reseller/get_branding_logo', c.req.captures) %]) no-repeat 0 0;
+    background-size: 280px 32px;
+}
+
+

+ [% ELSE -%] + No logo uploaded. + [% END -%] + + +

Custom CSS

+

+

+[% branding.css %]
+                
+

+ [% ELSE -%] + No branding specified, using standard branding. + [% END -%] + +
+
+
+ +[% IF branding_edit_flag == 1 -%] +[% + IF form.has_for_js; + form.render_repeatable_js; + END; + PROCESS "helpers/modal.tt"; + modal_header(m.edit_flag = branding_edit_flag, + m.name = "Reseller Branding"); + translate_form(branding_form).render; + modal_footer(); + modal_script(m.close_target = close_target); +-%] +[% END -%] + [% # vim: set tabstop=4 syntax=html expandtab: -%] From 45a42b9b61012513935a7582443aa614eda9cf30 Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Mon, 31 Mar 2014 15:23:08 +0200 Subject: [PATCH 04/13] MT#6479 API: Allow resellers to access some funcs. --- lib/NGCP/Panel/Controller/API/BillingFees.pm | 2 +- lib/NGCP/Panel/Controller/API/BillingFeesItem.pm | 2 +- lib/NGCP/Panel/Controller/API/BillingProfiles.pm | 2 +- lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm | 2 +- lib/NGCP/Panel/Controller/API/BillingZones.pm | 2 +- lib/NGCP/Panel/Controller/API/BillingZonesItem.pm | 2 +- lib/NGCP/Panel/Controller/API/CustomerContacts.pm | 2 +- lib/NGCP/Panel/Controller/API/CustomerContactsItem.pm | 2 +- lib/NGCP/Panel/Controller/API/Customers.pm | 2 +- lib/NGCP/Panel/Controller/API/CustomersItem.pm | 2 +- lib/NGCP/Panel/Controller/API/DomainPreferenceDefs.pm | 2 +- lib/NGCP/Panel/Controller/API/DomainPreferences.pm | 2 +- lib/NGCP/Panel/Controller/API/DomainPreferencesItem.pm | 2 +- lib/NGCP/Panel/Controller/API/DomainsItem.pm | 2 +- lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm | 2 +- lib/NGCP/Panel/Controller/API/RewriteRuleSetsItem.pm | 2 +- lib/NGCP/Panel/Controller/API/RewriteRules.pm | 2 +- lib/NGCP/Panel/Controller/API/RewriteRulesItem.pm | 2 +- lib/NGCP/Panel/Controller/API/SubscriberPreferenceDefs.pm | 2 +- lib/NGCP/Panel/Controller/API/SubscriberPreferences.pm | 2 +- lib/NGCP/Panel/Controller/API/SubscriberPreferencesItem.pm | 2 +- lib/NGCP/Panel/Controller/API/Subscribers.pm | 2 +- lib/NGCP/Panel/Controller/API/SubscribersItem.pm | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/BillingFees.pm b/lib/NGCP/Panel/Controller/API/BillingFees.pm index af00d40c7d..b7382ff513 100644 --- a/lib/NGCP/Panel/Controller/API/BillingFees.pm +++ b/lib/NGCP/Panel/Controller/API/BillingFees.pm @@ -50,7 +50,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/BillingFeesItem.pm b/lib/NGCP/Panel/Controller/API/BillingFeesItem.pm index df302bfaed..a1def77309 100644 --- a/lib/NGCP/Panel/Controller/API/BillingFeesItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingFeesItem.pm @@ -23,7 +23,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/BillingProfiles.pm b/lib/NGCP/Panel/Controller/API/BillingProfiles.pm index da5979ef64..e94ebfeb9d 100644 --- a/lib/NGCP/Panel/Controller/API/BillingProfiles.pm +++ b/lib/NGCP/Panel/Controller/API/BillingProfiles.pm @@ -32,7 +32,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm b/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm index 010e8966ac..529a8138b7 100644 --- a/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingProfilesItem.pm @@ -23,7 +23,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/BillingZones.pm b/lib/NGCP/Panel/Controller/API/BillingZones.pm index 2d8f5a71bf..46d1f8ef9b 100644 --- a/lib/NGCP/Panel/Controller/API/BillingZones.pm +++ b/lib/NGCP/Panel/Controller/API/BillingZones.pm @@ -50,7 +50,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/BillingZonesItem.pm b/lib/NGCP/Panel/Controller/API/BillingZonesItem.pm index 7b54601445..a4cc688c5f 100644 --- a/lib/NGCP/Panel/Controller/API/BillingZonesItem.pm +++ b/lib/NGCP/Panel/Controller/API/BillingZonesItem.pm @@ -23,7 +23,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/CustomerContacts.pm b/lib/NGCP/Panel/Controller/API/CustomerContacts.pm index 05f704cf20..6ddbaaff4f 100644 --- a/lib/NGCP/Panel/Controller/API/CustomerContacts.pm +++ b/lib/NGCP/Panel/Controller/API/CustomerContacts.pm @@ -33,7 +33,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/CustomerContactsItem.pm b/lib/NGCP/Panel/Controller/API/CustomerContactsItem.pm index 2f10b09676..8102aa5abc 100644 --- a/lib/NGCP/Panel/Controller/API/CustomerContactsItem.pm +++ b/lib/NGCP/Panel/Controller/API/CustomerContactsItem.pm @@ -23,7 +23,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/Customers.pm b/lib/NGCP/Panel/Controller/API/Customers.pm index abbc4d3b02..f774f58385 100644 --- a/lib/NGCP/Panel/Controller/API/Customers.pm +++ b/lib/NGCP/Panel/Controller/API/Customers.pm @@ -33,7 +33,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/CustomersItem.pm b/lib/NGCP/Panel/Controller/API/CustomersItem.pm index 91abdce42d..243787faab 100644 --- a/lib/NGCP/Panel/Controller/API/CustomersItem.pm +++ b/lib/NGCP/Panel/Controller/API/CustomersItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/DomainPreferenceDefs.pm b/lib/NGCP/Panel/Controller/API/DomainPreferenceDefs.pm index d9effa7d16..a0b9e4a86a 100644 --- a/lib/NGCP/Panel/Controller/API/DomainPreferenceDefs.pm +++ b/lib/NGCP/Panel/Controller/API/DomainPreferenceDefs.pm @@ -27,7 +27,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/DomainPreferences.pm b/lib/NGCP/Panel/Controller/API/DomainPreferences.pm index 13195a53e2..43e6168983 100644 --- a/lib/NGCP/Panel/Controller/API/DomainPreferences.pm +++ b/lib/NGCP/Panel/Controller/API/DomainPreferences.pm @@ -33,7 +33,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/DomainPreferencesItem.pm b/lib/NGCP/Panel/Controller/API/DomainPreferencesItem.pm index b4ac89511d..c3e3400577 100644 --- a/lib/NGCP/Panel/Controller/API/DomainPreferencesItem.pm +++ b/lib/NGCP/Panel/Controller/API/DomainPreferencesItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/DomainsItem.pm b/lib/NGCP/Panel/Controller/API/DomainsItem.pm index 9258916fcb..30a45b424e 100644 --- a/lib/NGCP/Panel/Controller/API/DomainsItem.pm +++ b/lib/NGCP/Panel/Controller/API/DomainsItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm b/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm index ed1278114d..8ae455c4a7 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm @@ -73,7 +73,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/RewriteRuleSetsItem.pm b/lib/NGCP/Panel/Controller/API/RewriteRuleSetsItem.pm index 9f8d0aebfc..6677e9b17a 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRuleSetsItem.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRuleSetsItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/RewriteRules.pm b/lib/NGCP/Panel/Controller/API/RewriteRules.pm index 8b6b1a584d..27aef716e3 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRules.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRules.pm @@ -60,7 +60,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/RewriteRulesItem.pm b/lib/NGCP/Panel/Controller/API/RewriteRulesItem.pm index 1992450cf0..6b505f7243 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRulesItem.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRulesItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/SubscriberPreferenceDefs.pm b/lib/NGCP/Panel/Controller/API/SubscriberPreferenceDefs.pm index a047ad03e6..6b06080bef 100644 --- a/lib/NGCP/Panel/Controller/API/SubscriberPreferenceDefs.pm +++ b/lib/NGCP/Panel/Controller/API/SubscriberPreferenceDefs.pm @@ -27,7 +27,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/SubscriberPreferences.pm b/lib/NGCP/Panel/Controller/API/SubscriberPreferences.pm index b7d52e12c4..42dc05eef7 100644 --- a/lib/NGCP/Panel/Controller/API/SubscriberPreferences.pm +++ b/lib/NGCP/Panel/Controller/API/SubscriberPreferences.pm @@ -33,7 +33,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/SubscriberPreferencesItem.pm b/lib/NGCP/Panel/Controller/API/SubscriberPreferencesItem.pm index 4a1efd32fc..fa5bb75eda 100644 --- a/lib/NGCP/Panel/Controller/API/SubscriberPreferencesItem.pm +++ b/lib/NGCP/Panel/Controller/API/SubscriberPreferencesItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/Subscribers.pm b/lib/NGCP/Panel/Controller/API/Subscribers.pm index 8413901560..ef536b90f9 100644 --- a/lib/NGCP/Panel/Controller/API/Subscribers.pm +++ b/lib/NGCP/Panel/Controller/API/Subscribers.pm @@ -68,7 +68,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 0, Does => [qw(ACL CheckTrailingSlash RequireSSL)], Method => $_, diff --git a/lib/NGCP/Panel/Controller/API/SubscribersItem.pm b/lib/NGCP/Panel/Controller/API/SubscribersItem.pm index c422d90e14..20b7e60695 100644 --- a/lib/NGCP/Panel/Controller/API/SubscribersItem.pm +++ b/lib/NGCP/Panel/Controller/API/SubscribersItem.pm @@ -26,7 +26,7 @@ __PACKAGE__->config( action => { map { $_ => { ACLDetachTo => '/api/root/invalid_user', - AllowedRole => 'admin', + AllowedRole => [qw/admin reseller/], Args => 1, Does => [qw(ACL RequireSSL)], Method => $_, From 861e38b649512781d1066a34e5c446e2db95769b Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Mon, 31 Mar 2014 16:40:23 +0200 Subject: [PATCH 05/13] MT#6283 Add more query params to existing colls --- .../Panel/Controller/API/BillingProfiles.pm | 18 +++++++++++ lib/NGCP/Panel/Controller/API/Contracts.pm | 29 +++++++++++++++++ .../Panel/Controller/API/CustomerContacts.pm | 29 +++++++++++++++++ lib/NGCP/Panel/Controller/API/Customers.pm | 31 +++++++++++++++++++ lib/NGCP/Panel/Controller/API/Domains.pm | 31 +++++++++++++++++++ lib/NGCP/Panel/Controller/API/Resellers.pm | 18 +++++++++++ lib/NGCP/Panel/Controller/API/RewriteRules.pm | 13 ++++---- .../Panel/Controller/API/SystemContacts.pm | 18 +++++++++++ lib/NGCP/Panel/Role/API.pm | 2 -- 9 files changed, 181 insertions(+), 8 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/BillingProfiles.pm b/lib/NGCP/Panel/Controller/API/BillingProfiles.pm index e94ebfeb9d..8ec94b1eba 100644 --- a/lib/NGCP/Panel/Controller/API/BillingProfiles.pm +++ b/lib/NGCP/Panel/Controller/API/BillingProfiles.pm @@ -22,6 +22,24 @@ class_has 'api_description' => ( 'Defines a collection of Billing Fees and Billing Zones and can be assigned to Customers and System Contracts.' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'reseller_id', + description => 'Filter for billing profiles belonging to a specific reseller', + query => { + first => sub { + my $q = shift; + { reseller_id => $q }; + }, + second => sub {}, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::BillingProfiles'; class_has('resource_name', is => 'ro', default => 'billingprofiles'); diff --git a/lib/NGCP/Panel/Controller/API/Contracts.pm b/lib/NGCP/Panel/Controller/API/Contracts.pm index ccacc96313..416c4bdb14 100644 --- a/lib/NGCP/Panel/Controller/API/Contracts.pm +++ b/lib/NGCP/Panel/Controller/API/Contracts.pm @@ -23,6 +23,35 @@ class_has 'api_description' => ( 'Defines a billing container for peerings and resellers. A Billing Profile is assigned to a contract, and it has Contract Balances indicating the saldo of the contract for current and past billing intervals.' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'contact_id', + description => 'Filter for contracts with a specific contact id', + query => { + first => sub { + my $q = shift; + { contact_id => $q }; + }, + second => sub {}, + }, + }, + { + param => 'status', + description => 'Filter for contracts with a specific status (except "terminated")', + query => { + first => sub { + my $q = shift; + { status => $q }; + }, + second => sub {}, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::Contracts'; class_has('resource_name', is => 'ro', default => 'contracts'); diff --git a/lib/NGCP/Panel/Controller/API/CustomerContacts.pm b/lib/NGCP/Panel/Controller/API/CustomerContacts.pm index 6ddbaaff4f..9a8fd40b08 100644 --- a/lib/NGCP/Panel/Controller/API/CustomerContacts.pm +++ b/lib/NGCP/Panel/Controller/API/CustomerContacts.pm @@ -23,6 +23,35 @@ class_has 'api_description' => ( 'Defines a physical or legal person\'s address (postal and/or email) to be used to identify Customers.' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'email', + description => 'Filter for contacts matching an email pattern', + query => { + first => sub { + my $q = shift; + { email => { like => $q } }; + }, + second => sub {}, + }, + }, + { + param => 'reseller_id', + description => 'Filter for contacts belonging to a specific reseller', + query => { + first => sub { + my $q = shift; + { reseller_id => $q }; + }, + second => sub {}, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::CustomerContacts'; class_has('resource_name', is => 'ro', default => 'customercontacts'); diff --git a/lib/NGCP/Panel/Controller/API/Customers.pm b/lib/NGCP/Panel/Controller/API/Customers.pm index f774f58385..4b4efaeb03 100644 --- a/lib/NGCP/Panel/Controller/API/Customers.pm +++ b/lib/NGCP/Panel/Controller/API/Customers.pm @@ -23,6 +23,37 @@ class_has 'api_description' => ( 'Defines a billing container for end customers. Customers usually have one or more Subscribers. A Billing Profile is assigned to a customer, and it has Contract Balances indicating the saldo of the customer for current and past billing intervals.' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'reseller_id', + description => 'Filter for customers belonging to a specific reseller', + query => { + first => sub { + my $q = shift; + { 'contact.reseller_id' => $q }; + }, + second => sub { + { join => 'contact' }; + }, + }, + }, + { + param => 'contact_id', + description => 'Filter for customers belonging to a specific contact', + query => { + first => sub { + my $q = shift; + { contact_id => $q }; + }, + second => sub { }, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::Customers'; class_has('resource_name', is => 'ro', default => 'customers'); diff --git a/lib/NGCP/Panel/Controller/API/Domains.pm b/lib/NGCP/Panel/Controller/API/Domains.pm index 2474ebc189..dca1357222 100644 --- a/lib/NGCP/Panel/Controller/API/Domains.pm +++ b/lib/NGCP/Panel/Controller/API/Domains.pm @@ -23,6 +23,37 @@ class_has 'api_description' => ( 'Specifies a SIP Domain to be used as host part for SIP Subscribers. You need a domain before you can create a subscriber. Multiple domains can be created. A domain could also be an IPv4 or IPv6 address (whereas the latter needs to be enclosed in square brackets, e.g. [::1]).' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'reseller_id', + description => 'Filter for domains belonging to a specific reseller', + query => { + first => sub { + my $q = shift; + { 'domain_resellers.reseller_id' => $q }; + }, + second => sub { + { join => 'domain_resellers' }; + }, + }, + }, + { + param => 'domain', + description => 'Filter for domains matching the given pattern', + query => { + first => sub { + my $q = shift; + { domain => { like => $q } }; + }, + second => sub { }, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::Domains'; class_has('resource_name', is => 'ro', default => 'domains'); diff --git a/lib/NGCP/Panel/Controller/API/Resellers.pm b/lib/NGCP/Panel/Controller/API/Resellers.pm index 4026684afe..e412bc36cc 100644 --- a/lib/NGCP/Panel/Controller/API/Resellers.pm +++ b/lib/NGCP/Panel/Controller/API/Resellers.pm @@ -22,6 +22,24 @@ class_has 'api_description' => ( 'Defines a reseller on the system. A reseller can manage his own Domains and Customers.' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'name', + description => 'Filter for resellers matching the given name pattern', + query => { + first => sub { + my $q = shift; + { name => { like => $q } }; + }, + second => sub {}, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::Resellers'; class_has('resource_name', is => 'ro', default => 'resellers'); diff --git a/lib/NGCP/Panel/Controller/API/RewriteRules.pm b/lib/NGCP/Panel/Controller/API/RewriteRules.pm index 27aef716e3..8697cbed53 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRules.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRules.pm @@ -21,12 +21,6 @@ class_has 'api_description' => ( 'Defines a set of Rewrite Rules which are grouped in Rewrite Rule Sets. They can be used to alter incoming and outgoing numbers.', ); -with 'NGCP::Panel::Role::API::RewriteRules'; - -class_has('resource_name', is => 'ro', default => 'rewriterules'); -class_has('dispatch_path', is => 'ro', default => '/api/rewriterules/'); -class_has('relation', is => 'ro', default => 'http://purl.org/sipwise/ngcp-api/#rel-rewriterules'); - class_has 'query_params' => ( is => 'ro', isa => 'ArrayRef', @@ -56,6 +50,13 @@ class_has 'query_params' => ( ]}, ); + +with 'NGCP::Panel::Role::API::RewriteRules'; + +class_has('resource_name', is => 'ro', default => 'rewriterules'); +class_has('dispatch_path', is => 'ro', default => '/api/rewriterules/'); +class_has('relation', is => 'ro', default => 'http://purl.org/sipwise/ngcp-api/#rel-rewriterules'); + __PACKAGE__->config( action => { map { $_ => { diff --git a/lib/NGCP/Panel/Controller/API/SystemContacts.pm b/lib/NGCP/Panel/Controller/API/SystemContacts.pm index fc1e3713a1..6a8d3e12d3 100644 --- a/lib/NGCP/Panel/Controller/API/SystemContacts.pm +++ b/lib/NGCP/Panel/Controller/API/SystemContacts.pm @@ -23,6 +23,24 @@ class_has 'api_description' => ( 'Defines a physical or legal person\'s address (postal and/or email) to be used in System Contracts (contracts for peerings and resellers).' ); +class_has 'query_params' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub {[ + { + param => 'email', + description => 'Filter for contacts matching an email pattern', + query => { + first => sub { + my $q = shift; + { email => { like => $q } }; + }, + second => sub {}, + }, + }, + ]}, +); + with 'NGCP::Panel::Role::API::SystemContacts'; class_has('resource_name', is => 'ro', default => 'systemcontacts'); diff --git a/lib/NGCP/Panel/Role/API.pm b/lib/NGCP/Panel/Role/API.pm index fc1b09ddda..c82b5d3b6a 100644 --- a/lib/NGCP/Panel/Role/API.pm +++ b/lib/NGCP/Panel/Role/API.pm @@ -82,7 +82,6 @@ sub validate_form { # move {xxx_id} into {xxx}{id} for FormHandler foreach my $key(keys %{ $resource } ) { if($key =~ /^(.+)_id$/ && $key ne "external_id") { - $c->log->debug("++++++++++++ moving key $key with value " . ($resource->{$key} // '') . " to $1/id"); push @normalized, $1; $resource->{$1}{id} = delete $resource->{$key}; } @@ -92,7 +91,6 @@ sub validate_form { my %fields = map { $_->name => undef } $form->fields; for my $k (keys %{ $resource }) { unless(exists $fields{$k}) { - $c->log->debug("+++++++++ deleting unknown key '$k' from message"); # TODO: user, message trace, ... delete $resource->{$k}; } From 21a5d7ee3740c4532b4026fec7df3c1544125968 Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Tue, 1 Apr 2014 13:19:17 +0200 Subject: [PATCH 06/13] MT#6195 API rwr: Give proper reseller access see also MT#6479 --- lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm | 12 +++++++++--- lib/NGCP/Panel/Controller/API/RewriteRules.pm | 11 ++++++++++- lib/NGCP/Panel/Role/API/RewriteRuleSets.pm | 9 +++++++-- lib/NGCP/Panel/Role/API/RewriteRules.pm | 8 ++++++-- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm b/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm index 8ae455c4a7..e4dac768c6 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRuleSets.pm @@ -173,11 +173,17 @@ sub POST :Allow { ); last unless $resource; - unless(defined $resource->{reseller_id}) { + my $reseller_id; + if($c->user->roles eq "admin") { try { - $resource->{reseller_id} = $c->user->contract->contact->reseller_id; - } + $reseller_id = $resource->{reseller_id} + || $c->user->contract->contact->reseller_id; + } + } elsif($c->user->roles eq "reseller") { + $reseller_id = $c->user->reseller_id; } + $resource->{reseller_id} = $reseller_id; + my $reseller = $c->model('DB')->resultset('resellers')->find($resource->{reseller_id}); unless($reseller) { $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'reseller_id', doesn't exist."); diff --git a/lib/NGCP/Panel/Controller/API/RewriteRules.pm b/lib/NGCP/Panel/Controller/API/RewriteRules.pm index 8697cbed53..8e7cf65847 100644 --- a/lib/NGCP/Panel/Controller/API/RewriteRules.pm +++ b/lib/NGCP/Panel/Controller/API/RewriteRules.pm @@ -177,7 +177,16 @@ sub POST :Allow { $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Required: 'set_id'"); last; } - my $ruleset = $schema->resultset('voip_rewrite_rule_sets')->find($set_id); + + my $reseller_id; + if($c->user->roles eq "reseller") { + $reseller_id = $c->user->reseller_id; + } + + my $ruleset = $schema->resultset('voip_rewrite_rule_sets')->find({ + id => $set_id, + ($reseller_id ? (reseller_id => $reseller_id) : ()), + }); unless($ruleset) { $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'set_id'."); last; diff --git a/lib/NGCP/Panel/Role/API/RewriteRuleSets.pm b/lib/NGCP/Panel/Role/API/RewriteRuleSets.pm index 751cd186c5..d0a6efda7b 100644 --- a/lib/NGCP/Panel/Role/API/RewriteRuleSets.pm +++ b/lib/NGCP/Panel/Role/API/RewriteRuleSets.pm @@ -82,8 +82,9 @@ sub item_rs { if($type eq "rulesets") { if($c->user->roles eq "admin") { $item_rs = $c->model('DB')->resultset('voip_rewrite_rule_sets'); - } else { - return; + } elsif($c->user->roles eq "reseller") { + $item_rs = $c->model('DB')->resultset('voip_rewrite_rule_sets') + ->search_rs({reseller_id => $c->user->reseller_id}); } } else { die "You should not reach this"; @@ -103,6 +104,10 @@ sub update_item { delete $resource->{id}; + if($c->user->roles eq "reseller") { + $resource->{reseller_id} = $old_resource->{reseller_id}; # prohibit change + } + if($old_resource->{reseller_id} != $resource->{reseller_id}) { my $reseller = $c->model('DB')->resultset('resellers') ->find($resource->{reseller_id}); diff --git a/lib/NGCP/Panel/Role/API/RewriteRules.pm b/lib/NGCP/Panel/Role/API/RewriteRules.pm index ccf99b9fb1..0bcbc6e0aa 100644 --- a/lib/NGCP/Panel/Role/API/RewriteRules.pm +++ b/lib/NGCP/Panel/Role/API/RewriteRules.pm @@ -62,8 +62,12 @@ sub item_rs { if($type eq "rules") { if($c->user->roles eq "admin") { $item_rs = $c->model('DB')->resultset('voip_rewrite_rules'); - } else { - return; + } elsif ($c->user->roles eq "reseller") { + $item_rs = $c->model('DB')->resultset('voip_rewrite_rules')->search_rs({ + 'ruleset.reseller_id' => $c->user->reseller_id, + },{ + join => 'ruleset' + }); } } else { die "You should not reach this"; From 9398c1083fbaddfee27e35a0e7140c4eb43cde6f Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Tue, 1 Apr 2014 13:30:01 +0200 Subject: [PATCH 07/13] MT#6493 Start years selection in 2014 --- lib/NGCP/Panel/Form/TimeSet.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/NGCP/Panel/Form/TimeSet.pm b/lib/NGCP/Panel/Form/TimeSet.pm index ada786844d..0a61a00214 100644 --- a/lib/NGCP/Panel/Form/TimeSet.pm +++ b/lib/NGCP/Panel/Form/TimeSet.pm @@ -53,12 +53,14 @@ has_field 'period.row.year' => ( ); has_field 'period.row.year.from' => ( type => 'Year', + range_start => '2014', label => 'Year', empty_select => '', wrapper_class => [qw/hfh-rep-field ngcp-timeset-field/], ); has_field 'period.row.year.to' => ( type => 'Year', + range_start => '2014', label => 'through', empty_select => '', wrapper_class => [qw/hfh-rep-field ngcp-timeset-field/], From 31b114a30008a753a345284c87c9964057b6d07b Mon Sep 17 00:00:00 2001 From: Michael Prokop Date: Wed, 2 Apr 2014 13:17:27 +0200 Subject: [PATCH 08/13] MT#6511 Bump Standards-Version to 3.9.5 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index ebab45046a..4c6df94e70 100644 --- a/debian/control +++ b/debian/control @@ -61,7 +61,7 @@ Build-Depends: debhelper (>= 8), libxml-mini-perl, ngcp-schema, openssl -Standards-Version: 3.9.4 +Standards-Version: 3.9.5 Homepage: http://sipwise.com/ Package: ngcp-panel From c1c6c3a9eef96f399ea36180a670a43d09168acb Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Thu, 3 Apr 2014 07:27:15 +0200 Subject: [PATCH 09/13] MT#6513 remove old Replaces/Breaks. Not needed any longer. --- debian/control | 5 ----- 1 file changed, 5 deletions(-) diff --git a/debian/control b/debian/control index 4c6df94e70..e0df9d419b 100644 --- a/debian/control +++ b/debian/control @@ -67,11 +67,6 @@ Homepage: http://sipwise.com/ Package: ngcp-panel Architecture: all Pre-Depends: nginx-common -# only for trunk installations, remove it -Replaces: ngcp-panel-common (<= 1.0.15), - ngcp-panel-nginx (<= 1.0.15) -Breaks: ngcp-panel-common (<= 1.0.15), - ngcp-panel-nginx (<= 1.0.15) Depends: gettext, gnutls-bin, libautodie-perl (>= 2.21~), From 5a7caa4f0461d5ce7e54b82eee0f1c697331eabf Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Fri, 4 Apr 2014 11:14:16 +0200 Subject: [PATCH 10/13] MT#6551 Cleanup Build script - remove action test_tap - only start server on "--run-server" - make "--webdriver" optional - remove Sipwise::Base from configure-requirements --- Build.PL | 63 ++++++++++++++++++-------------- inc/Local/Module/Build.pm | 75 ++++++++++++++++++++------------------- 2 files changed, 74 insertions(+), 64 deletions(-) diff --git a/Build.PL b/Build.PL index fbbe35442b..632ab6ab16 100644 --- a/Build.PL +++ b/Build.PL @@ -1,10 +1,11 @@ use lib 'inc'; -use Local::Module::Build qw(); +use Local::Module::Build; my $builder = Local::Module::Build->new( module_name => 'NGCP::Panel', - license => 'restrictive', + license => 'perl', dist_version_from => 'lib/NGCP/Panel.pm', + dist_abstract => 'Sipwise Configuration Panel', tap_harness_args => { timer => 1, formatter_class => 'TAP::Formatter::JUnit', @@ -14,7 +15,6 @@ my $builder = Local::Module::Build->new( 'lib' => 0, 'Module::Build' => '0.4004', 'Moose' => 2, - 'Sipwise::Base' => 0, }, requires => { 'base' => 0, @@ -81,6 +81,7 @@ my $builder = Local::Module::Build->new( 'Scalar::Util' => 0, 'Sereal::Decoder' => 0, 'Sereal::Encoder' => 0, + 'Sipwise::Base' => 0, 'strict' => 0, 'Template' => 0, 'Text::CSV_XS' => 0, @@ -145,38 +146,43 @@ Build.PL - NGCP-Panel build system including test fixtures ./Build test --webdriver=selenium-rc # from CPAN distro Alien-SeleniumRC ./Build test --webdriver=external --wd-server=127.0.0.1:5555 - ./Build test_tap --webdriver=external # outputs tap to tap/ folder - ./Build testcover --webdriver='phantomjs --webdriver=4444' + ./Build test_api + ./Build test_api --schema-base-dir=path/to/schema --server=https://1.2.3.4:1443 =head2 Options - --webdriver (required) external webdriver command - --wd-server HOST:PORT of an external webdriver to connect to - --server URI for socket test server - --schema-base-dir directory of NGCP::Schema if its not yet installed --mysqld-port port where the mysqld should be started --mysql-dump one or more mysql dumps to be imported to our mysqld --no-junit don't output junit but normal TAP, for manual testing + --run-server panel should be started by build script + --schema-base-dir directory of NGCP::Schema if its not yet installed + --server URI for socket test server + --webdriver Command to be run as Webdriver + --wd-server HOST:PORT of an external webdriver to connect to --help brief help message --man full documentation =head1 OPTIONS -=head2 C<--webdriver> +=head2 C<--mysqld-port> -(required) command to launch a webdriver -external if the webdriver is launched externally +If this option and C<--mysqld-dir> are supplied, a mysqld will be started +at the specified port and be used for the tests. mysqld will be stopped +and the temporary data deleted when this script finishes. -=head2 C<--wd-server> +=head2 C<--mysql-dump> -Host:Port of the webdriver to which the tests should connect. -Default is set by Test::WebDriver to localhost:4444 +If this option and C<--mysqld-port> are supplied, a mysqld will be started +and be used for the tests. It will import all dumps supplied with this option. +This option can be set multiple times. In this case all specified files will +be dumped into the database. -=head2 C<--server> +=head2 C<--run-server> -URI for the HTTP::Server::PSGI socket server run for testing, -default C +Does not take an argument. Indicates the ./Build script should start a +server running the panel by itself on the Address given by the --server +argument. =head2 C<--schema-base-dir> @@ -184,18 +190,21 @@ If the NGCP::Schema is not installed to a known path to perl, this option can specify the base directory of its development location. It will then be included via blib, so we have access to its lib and share. -=head2 C<--mysqld-port> +=head2 C<--server> -If this option and C<--mysqld-dir> are supplied, a mysqld will be started -at the specified port and be used for the tests. mysqld will be stopped -and the temporary data deleted when this script finishes. +URI for the HTTP::Server::PSGI socket server run for testing, +default C -=head2 C<--mysql-dump> +=head2 C<--webdriver> -If this option and C<--mysqld-port> are supplied, a mysqld will be started -and be used for the tests. It will import all dumps supplied with this option. -This option can be set multiple times. In this case all specified files will -be dumped into the database. +command to launch a webdriver +external if the webdriver is launched externally +this command is no longer required + +=head2 C<--wd-server> + +Host:Port of the webdriver to which the tests should connect. +Default is set by Test::WebDriver to localhost:4444 =head2 C<--help> diff --git a/inc/Local/Module/Build.pm b/inc/Local/Module/Build.pm index 85ed527d2a..f3b8cb6ee4 100644 --- a/inc/Local/Module/Build.pm +++ b/inc/Local/Module/Build.pm @@ -1,8 +1,7 @@ package Local::Module::Build; -use Sipwise::Base; -use Moose qw(around); +use Moose qw(around extends); use Child qw(child); -use Capture::Tiny qw(capture); +use Capture::Tiny; use TryCatch; use MooseX::Method::Signatures; use LWP::UserAgent; @@ -10,7 +9,7 @@ extends 'Module::Build'; our ($plackup, $webdriver, @cover_opt, $mysqld); -method wait_socket($host, $port) { +method wait_socket($host, $port, $timeout=90) { require IO::Socket::IP; my $timer = 0; while (1) { @@ -22,8 +21,8 @@ method wait_socket($host, $port) { last if $sock; sleep 1; $timer++; - die sprintf('socket %s:%s is not accessible within 30 seconds after start', $host, $port) - if $timer > 90; + die sprintf('socket %s:%s is not accessible within %d seconds after start', $host, $port, $timeout) + if $timer > $timeout; }; } @@ -40,14 +39,14 @@ sub _test_preconditions { my ($self) = @_; require Getopt::Long; - my %opt = (server => 'http://localhost:5000'); - Getopt::Long::GetOptions(\%opt, 'webdriver=s', 'server:s', 'help|?', 'man', 'wd-server=s', 'schema-base-dir=s', 'mysqld-port=s', 'mysql-dump=s@', 'no-junit') + my %opt = (server => 'http://localhost:5000', webdriver => 'external'); + Getopt::Long::GetOptions(\%opt, 'webdriver=s', 'server:s', 'help|?', 'man', 'wd-server=s', + 'schema-base-dir=s', 'mysqld-port=s', 'mysql-dump=s@', 'no-junit', 'run-server') or die 'could not process command-line options'; require Pod::Usage; Pod::Usage::pod2usage(-exitval => 1, -input => 'Build.PL') if $opt{help}; Pod::Usage::pod2usage(-exitval => 0, -input => 'Build.PL', -verbose => 2) if $opt{man}; - Pod::Usage::pod2usage("$0: --webdriver option required.\nRun `perldoc Build.PL`") unless $opt{webdriver}; if ($opt{'no-junit'}) { delete $self->tap_harness_args->{formatter_class}; @@ -86,29 +85,37 @@ sub _test_preconditions { } require URI; + unless ($opt{server} =~ m|^https?://|) { + die "Wrong format of server argument, should start with 'http(s)'."; + } my $uri = URI->new($opt{server}); - require File::Which; - $ENV{ NGCP_PANEL_CONFIG_LOCAL_SUFFIX } = "testing"; - $plackup = child { - my $out_fh = IO::File->new("panel_debug_stdout", "w+"); - my $err_fh = IO::File->new("panel_debug_stderr", "w+"); - $out_fh->autoflush(1); - $err_fh->autoflush(1); - local $| = 1; - capture { - exec $^X, - '-Ilib', - exists $opt{'schema-base-dir'} ? "-Mblib=$opt{'schema-base-dir'}" : (), - @cover_opt, - scalar File::Which::which('plackup'), - sprintf('--listen=%s:%s', $uri->host, $uri->port), - 'ngcp_panel.psgi'; - } stdout => $out_fh, stderr => $err_fh; - }; - - $self->wait_socket($uri->host, $uri->port); + if( $opt{'run-server'} ) { + require File::Which; + $ENV{ NGCP_PANEL_CONFIG_LOCAL_SUFFIX } = "testing"; + $plackup = child { + my $out_fh = IO::File->new("panel_debug_stdout", "w+"); + my $err_fh = IO::File->new("panel_debug_stderr", "w+"); + $out_fh->autoflush(1); + $err_fh->autoflush(1); + local $| = 1; + Capture::Tiny::capture { + exec $^X, + '-Ilib', + exists $opt{'schema-base-dir'} ? "-Mblib=$opt{'schema-base-dir'}" : (), + @cover_opt, + scalar File::Which::which('plackup'), + sprintf('--listen=%s:%s', $uri->host, $uri->port), + 'ngcp_panel.psgi'; + } stdout => $out_fh, stderr => $err_fh; + }; + $self->wait_socket($uri->host, $uri->port); + } + $ENV{CATALYST_SERVER} = $opt{server}; + if ($self->verbose) { + print("Server is: ".$opt{server}."\n"); + } } sub _download_certs { @@ -167,14 +174,6 @@ method ACTION_testcover { $self->do_system(qw(cover)); } -method ACTION_test_tap { - $self->depends_on('code'); - $self->_test_preconditions; - system( "mkdir -p tap" ); - $ENV{PERL_TEST_HARNESS_DUMP_TAP} = "tap/"; - $self->generic_test(type => 'default'); -} - method ACTION_test_servers { $self->depends_on('code'); $self->_test_preconditions; @@ -205,3 +204,5 @@ method ACTION_readme { } END { shutdown_servers } + +1; From d190d8e7cd97e04d012d9120635b1c5fdb5ae0cb Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Fri, 4 Apr 2014 11:36:20 +0200 Subject: [PATCH 11/13] MT#6551 Getopt allow unknown options to pass through to Module::Build, for example "--verbose" --- inc/Local/Module/Build.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/Local/Module/Build.pm b/inc/Local/Module/Build.pm index f3b8cb6ee4..f29dbe1d6f 100644 --- a/inc/Local/Module/Build.pm +++ b/inc/Local/Module/Build.pm @@ -39,6 +39,7 @@ sub _test_preconditions { my ($self) = @_; require Getopt::Long; + Getopt::Long::Configure('pass_through'); my %opt = (server => 'http://localhost:5000', webdriver => 'external'); Getopt::Long::GetOptions(\%opt, 'webdriver=s', 'server:s', 'help|?', 'man', 'wd-server=s', 'schema-base-dir=s', 'mysqld-port=s', 'mysql-dump=s@', 'no-junit', 'run-server') @@ -136,6 +137,7 @@ sub _download_certs { $res = $ua->post($uri.'/administrator/1/api_key', {'ca.download' => 'foo'}, 'Referer' => $uri.'/dashboard', ':content_file' => $tmp_apica_filename); $ENV{API_SSL_CLIENT_CERT} = $tmp_apiclient_filename; $ENV{API_SSL_CA_CERT} = $tmp_apica_filename; + print "Client cert: $tmp_apiclient_filename - CA cert: $tmp_apica_filename\n" if $self->verbose; } around('ACTION_test', sub { From c6b6391e289e8b0d8ead7eb847d66f40c403a8f6 Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Fri, 4 Apr 2014 11:56:39 +0200 Subject: [PATCH 12/13] MT#6551 Add empty MANIFEST file so perl Build.PL does not complain about that and skip everything in MANIFEST.SKIP --- .gitignore | 1 - MANIFEST | 0 MANIFEST.SKIP | 2 ++ 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 MANIFEST diff --git a/.gitignore b/.gitignore index 3e236d8cf0..05c572d25e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ _darcs Descrip.MMS DESCRIP.MMS descrip.mms -MANIFEST MANIFEST.bak Makefile blib diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000000..e69de29bb2 diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index 4a53dea74c..6ea0f5f5b1 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -59,3 +59,5 @@ ^MYMETA\. ^NGCP-Panel- + +.* From dfa5a2d1de667eb3abcd06b9ab8565094e227200 Mon Sep 17 00:00:00 2001 From: Gerhard Jungwirth Date: Fri, 4 Apr 2014 12:52:26 +0200 Subject: [PATCH 13/13] MT#6559 remove usage of CLASS so in a future step we can remove this from Sipwise::Base --- lib/NGCP/Panel/Controller/Administrator.pm | 2 +- lib/NGCP/Panel/Controller/Billing.pm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/NGCP/Panel/Controller/Administrator.pm b/lib/NGCP/Panel/Controller/Administrator.pm index a49c65d3b2..26473b842a 100644 --- a/lib/NGCP/Panel/Controller/Administrator.pm +++ b/lib/NGCP/Panel/Controller/Administrator.pm @@ -290,7 +290,7 @@ sub api_key :Chained('base') :PathPart('api_key') :Args(0) { ); } -$CLASS->meta->make_immutable; +__PACKAGE__->meta->make_immutable; __END__ diff --git a/lib/NGCP/Panel/Controller/Billing.pm b/lib/NGCP/Panel/Controller/Billing.pm index 6818130fdb..0ae909efb1 100644 --- a/lib/NGCP/Panel/Controller/Billing.pm +++ b/lib/NGCP/Panel/Controller/Billing.pm @@ -786,7 +786,7 @@ sub peaktime_specials_create :Chained('peaktimes_list') :PathPart('date/create') $c->stash(peaktimes_special_createflag => 1); } -$CLASS->meta->make_immutable; +__PACKAGE__->meta->make_immutable; 1;