diff --git a/lib/NGCP/Panel/Controller/API/Subscribers.pm b/lib/NGCP/Panel/Controller/API/Subscribers.pm index 0332fb6388..17a0477a60 100644 --- a/lib/NGCP/Panel/Controller/API/Subscribers.pm +++ b/lib/NGCP/Panel/Controller/API/Subscribers.pm @@ -219,7 +219,6 @@ sub POST :Allow { last unless($r); my $subscriber; my $customer = $r->{customer}; - my $admin = $r->{admin}; my $alias_numbers = $r->{alias_numbers}; my $preferences = $r->{preferences}; $resource = $r->{resource}; @@ -234,8 +233,8 @@ sub POST :Allow { schema => $schema, contract => $r->{customer}, params => $resource, - admin_default => $admin, preferences => $preferences, + admin_default => 0, ); NGCP::Panel::Utils::Subscriber::update_subscriber_numbers( @@ -250,7 +249,7 @@ sub POST :Allow { } catch(DBIx::Class::Exception $e where { /Duplicate entry '([^']+)' for key 'number_idx'/ }) { $e =~ /Duplicate entry '([^']+)' for key 'number_idx'/; - $c->log->error("failed to create subscribere, number $1 already exists"); # TODO: user, message, trace, ... + $c->log->error("failed to create subscriber, number $1 already exists"); # TODO: user, message, trace, ... $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number '$1' already exists."); last; } catch($e) { diff --git a/lib/NGCP/Panel/Controller/Customer.pm b/lib/NGCP/Panel/Controller/Customer.pm index a82d4e20d4..26c71b7c4f 100644 --- a/lib/NGCP/Panel/Controller/Customer.pm +++ b/lib/NGCP/Panel/Controller/Customer.pm @@ -339,17 +339,6 @@ sub base :Chained('list_customer') :PathPart('') :CaptureArgs(1) { sub edit :Chained('base') :PathPart('edit') :Args(0) { my ($self, $c) = @_; - #$fooo = breakme; - # We now optionally get email templates via the form for subscriber creation - # and for password reset. Change DB schema to store those ids, and if they are - # not null, hide webpassword field and let user change pass on first login, and - # also provide a way to reset a lost password. - # - # also provide config option for password policy - # - # also provide option whether or not passwords are completely hidden (at least - # from subscriber(admin)) and let them be generated automatically - my $contract = $c->stash->{contract}; my $billing_mapping = $c->stash->{billing_mapping}; my $posted = ($c->request->method eq 'POST'); @@ -540,10 +529,9 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { $pbx = 1 if $c->stash->{product}->class eq 'pbxaccount'; my $form; my $posted = ($c->request->method eq 'POST'); - my $admin_subscribers = $c->stash->{subscribers}->search({ - 'provisioning_voip_subscriber.admin' => 1, - }); - $c->stash->{admin_subscriber} = $admin_subscribers->first; + $c->stash->{pilot} = $c->stash->{subscribers}->search({ + 'provisioning_voip_subscriber.is_pbx_pilot' => 1, + })->first; my $params = {}; @@ -551,7 +539,7 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { if($c->config->{features}->{cloudpbx} && $pbx) { $c->stash(customer_id => $c->stash->{contract}->id); # we need to create an admin subscriber first - unless($c->stash->{admin_subscriber}) { + unless($c->stash->{pilot}) { $pbxadmin = 1; $form = NGCP::Panel::Form::Customer::PbxAdminSubscriber->new(ctx => $c); } else { @@ -562,7 +550,7 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { } NGCP::Panel::Utils::Subscriber::prepare_alias_select( c => $c, - subscriber => $c->stash->{admin_subscriber}, + subscriber => $c->stash->{pilot}, params => $params, unselect => 1, # no numbers assigned yet, keep selection list empty ); @@ -598,12 +586,12 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { $schema->txn_do(sub { my $preferences = {}; if($pbx && !$pbxadmin) { - my $admin = $c->stash->{admin_subscriber}; - $form->params->{domain}{id} = $admin->domain_id; + my $pilot = $c->stash->{pilot}; + $form->params->{domain}{id} = $pilot->domain_id; # TODO: make DT selection multi-select capable $form->params->{pbx_group_id} = $form->params->{group}{id}; delete $form->params->{group}; - my $base_number = $admin->primary_number; + my $base_number = $pilot->primary_number; if($base_number) { $preferences->{cloud_pbx_base_cli} = $base_number->cc . $base_number->ac . $base_number->sn; if($form->params->{pbx_extension}) { @@ -614,6 +602,7 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { } } if($pbx) { + $form->params->{is_pbx_pilot} = 1; $preferences->{cloud_pbx} = 1; if($pbxadmin && $form->params->{e164}{cc} && $form->params->{e164}{sn}) { $preferences->{cloud_pbx_base_cli} = $form->params->{e164}{cc} . @@ -621,8 +610,8 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { $form->params->{e164}{sn}; } - if($c->stash->{admin_subscriber}) { - my $profile_set = $c->stash->{admin_subscriber}->provisioning_voip_subscriber->voip_subscriber_profile_set; + if($c->stash->{pilot}) { + my $profile_set = $c->stash->{pilot}->provisioning_voip_subscriber->voip_subscriber_profile_set; if($profile_set) { $form->params->{profile_set}{id} = $profile_set->id; } @@ -649,7 +638,7 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { schema => $schema, contract => $c->stash->{contract}, params => $form->params, - admin_default => $pbxadmin, + admin_default => 0, preferences => $preferences, ); @@ -668,7 +657,7 @@ sub subscriber_create :Chained('base') :PathPart('subscriber/create') :Args(0) { subscriber => $billing_subscriber, contract_id => $billing_subscriber->contract_id, alias_selected => decode_json($form->value->{alias_select}), - sadmin => $c->stash->{admin_subscriber}, + sadmin => $c->stash->{pilot}, ); } @@ -838,15 +827,14 @@ sub pbx_group_create :Chained('base') :PathPart('pbx/group/create') :Args(0) { } my $posted = ($c->request->method eq 'POST'); - my $admin_subscribers = $c->stash->{subscribers}->search({ - 'provisioning_voip_subscriber.admin' => 1, - }); - $c->stash->{admin_subscriber} = $admin_subscribers->first; - unless($c->stash->{admin_subscriber}) { + $c->stash->{pilot} = $c->stash->{subscribers}->search({ + 'provisioning_voip_subscriber.is_pbx_pilot' => 1, + })->first; + unless($c->stash->{pilot}) { NGCP::Panel::Utils::Message->error( c => $c, - error => 'cannot create pbx group without having an admin subscriber', - desc => $c->loc("Can't create a PBX group without having an administrative subscriber."), + error => 'cannot create pbx group without having a pilot subscriber', + desc => $c->loc("Can't create a PBX group without having a pilot subscriber."), ); NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/customer/details', $c->req->captures)); } @@ -870,9 +858,9 @@ sub pbx_group_create :Chained('base') :PathPart('pbx/group/create') :Args(0) { my $schema = $c->model('DB'); $schema->txn_do( sub { my $preferences = {}; - my $admin = $c->stash->{admin_subscriber}; + my $pilot = $c->stash->{pilot}; - my $base_number = $admin->primary_number; + my $base_number = $pilot->primary_number; if($base_number) { $preferences->{cloud_pbx_base_cli} = $base_number->cc . $base_number->ac . $base_number->sn; if($form->params->{pbx_extension}) { @@ -882,8 +870,9 @@ sub pbx_group_create :Chained('base') :PathPart('pbx/group/create') :Args(0) { } } + $form->params->{is_pbx_pilot} = 0; $form->params->{is_pbx_group} = 1; - $form->params->{domain}{id} = $admin->domain_id; + $form->params->{domain}{id} = $pilot->domain_id; $form->params->{status} = 'active'; $preferences->{cloud_pbx} = 1; $preferences->{cloud_pbx_hunt_policy} = $form->params->{pbx_hunt_policy}; diff --git a/lib/NGCP/Panel/Controller/Subscriber.pm b/lib/NGCP/Panel/Controller/Subscriber.pm index 975c4ac7c2..919b622bae 100644 --- a/lib/NGCP/Panel/Controller/Subscriber.pm +++ b/lib/NGCP/Panel/Controller/Subscriber.pm @@ -238,10 +238,9 @@ sub base :Chained('sub_list') :PathPart('') :CaptureArgs(1) { join => 'provisioning_voip_subscriber', }); - my $admin_subscribers = $c->stash->{subscribers}->search({ - 'provisioning_voip_subscriber.admin' => 1, - }); - $c->stash->{admin_subscriber} = $admin_subscribers->first; + $c->stash->{pilot} = $c->stash->{subscribers}->search({ + 'provisioning_voip_subscriber.is_pbx_pilot' => 1, + })->first; $c->stash->{sd_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ { name => "id", search => 1, title => $c->loc('#') }, @@ -1931,7 +1930,7 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet if($c->stash->{billing_mapping}->product->class eq "pbxaccount") { $c->stash(customer_id => $subscriber->contract->id); - if($subscriber->provisioning_voip_subscriber->admin) { + if($subscriber->provisioning_voip_subscriber->is_pbx_pilot) { if($c->user->roles eq 'subscriberadmin') { $subadmin_pbx = 1; $form = NGCP::Panel::Form::Customer::PbxExtensionSubscriberEditSubadminNoGroup->new(ctx => $c); @@ -1940,7 +1939,7 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet $form = NGCP::Panel::Form::Customer::PbxSubscriberEdit->new(ctx => $c); } } else { - $base_number = $c->stash->{admin_subscriber}->primary_number; + $base_number = $c->stash->{pilot}->primary_number; if($c->user->roles eq 'subscriberadmin') { $subadmin_pbx = 1; @@ -2178,13 +2177,13 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet $form->values->{lock} ||= 0; # update lock below } - if(exists $form->params->{alias_select} && $c->stash->{admin_subscriber}) { + if(exists $form->params->{alias_select} && $c->stash->{pilot}) { NGCP::Panel::Utils::Subscriber::update_subadmin_sub_aliases( schema => $schema, subscriber => $subscriber, contract_id => $subscriber->contract_id, alias_selected => decode_json($form->values->{alias_select}), - sadmin => $c->stash->{admin_subscriber}, + sadmin => $c->stash->{pilot}, ); } diff --git a/lib/NGCP/Panel/Form/Customer/PbxAdminSubscriber.pm b/lib/NGCP/Panel/Form/Customer/PbxAdminSubscriber.pm index d92ffde360..78247437ea 100644 --- a/lib/NGCP/Panel/Form/Customer/PbxAdminSubscriber.pm +++ b/lib/NGCP/Panel/Form/Customer/PbxAdminSubscriber.pm @@ -40,7 +40,7 @@ has_field 'domain' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/domain e164 e164range e164range_add display_name email webusername webpassword username password status external_id profile_set/ ], + render_list => [qw/domain e164 e164range e164range_add display_name email webusername webpassword username password administrative status external_id profile_set/ ], ); 1; diff --git a/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriber.pm b/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriber.pm index 10d6cbc291..e0f6ed9f4e 100644 --- a/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriber.pm +++ b/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriber.pm @@ -23,7 +23,7 @@ has_field 'pbx_extension' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/group alias_select pbx_extension display_name email webusername webpassword username password status external_id profile_set profile/ ], + render_list => [qw/group alias_select pbx_extension display_name email webusername webpassword username password administrative status external_id profile_set profile/ ], ); override 'field_list' => sub { @@ -62,10 +62,9 @@ override 'field_list' => sub { ); } } - } elsif($c->stash->{admin_subscriber}) { - my $profile_set = $c->stash->{admin_subscriber}->provisioning_voip_subscriber->voip_subscriber_profile_set; + } elsif($c->stash->{pilot}) { + my $profile_set = $c->stash->{pilot}->provisioning_voip_subscriber->voip_subscriber_profile_set; if($profile_set && $self->field('profile')) { - print ">>>>>>>>>>>>>> setting profile, url=" . $c->uri_for_action('/subscriberprofile/profile_ajax', [$profile_set->id]) . "\n"; $self->field('profile')->field('id')->ajax_src( $c->uri_for_action('/subscriberprofile/profile_ajax', [$profile_set->id])->as_string ); diff --git a/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriberSubadmin.pm b/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriberSubadmin.pm index 047861a3ac..a56609c73c 100644 --- a/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriberSubadmin.pm +++ b/lib/NGCP/Panel/Form/Customer/PbxExtensionSubscriberSubadmin.pm @@ -36,7 +36,7 @@ sub field_list { $c->uri_for_action('/customer/pbx_group_ajax', [$c->stash->{customer_id}])->as_string ); - my $profile_set = $c->stash->{admin_subscriber}->provisioning_voip_subscriber->voip_subscriber_profile_set; + my $profile_set = $c->stash->{pilot}->provisioning_voip_subscriber->voip_subscriber_profile_set; if($profile_set) { $self->field('profile')->field('id')->ajax_src( $c->uri_for_action('/subscriberprofile/profile_ajax', [$profile_set->id])->as_string diff --git a/lib/NGCP/Panel/Form/Customer/PbxSubscriber.pm b/lib/NGCP/Panel/Form/Customer/PbxSubscriber.pm index 1e47d9a2d1..faf773db89 100644 --- a/lib/NGCP/Panel/Form/Customer/PbxSubscriber.pm +++ b/lib/NGCP/Panel/Form/Customer/PbxSubscriber.pm @@ -102,6 +102,16 @@ has_field 'password' => ( }, ); +has_field 'administrative' => ( + type => 'Boolean', + label => 'Administrative', + required => 0, + element_attr => { + rel => ['tooltip'], + title => ['Whether the subscriber can configure other subscribers within his Customer account.'] + }, +); + has_field 'status' => ( type => '+NGCP::Panel::Field::SubscriberStatusSelect', label => 'Status', @@ -150,7 +160,7 @@ has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], #render_list => [qw/display_name webusername webpassword username password status external_id profile_set profile/ ], - render_list => [qw/e164 display_name email webusername webpassword username password status profile_set profile/ ], + render_list => [qw/e164 display_name email webusername webpassword username password administrative status profile_set profile/ ], ); has_block 'actions' => ( @@ -168,8 +178,8 @@ sub field_list { if($self->field('alias_select')) { my $sub; - if($c->stash->{admin_subscriber}) { - $sub = $c->stash->{admin_subscriber}; + if($c->stash->{pilot}) { + $sub = $c->stash->{pilot}; } elsif($c->stash->{subscriber} && $c->stash->{subscriber}->provisioning_voip_subscriber->admin) { $sub = $c->stash->{subscriber}; } diff --git a/lib/NGCP/Panel/Form/Subscriber/SubscriberAPI.pm b/lib/NGCP/Panel/Form/Subscriber/SubscriberAPI.pm index 1b8ae7fa8f..10a7230253 100644 --- a/lib/NGCP/Panel/Form/Subscriber/SubscriberAPI.pm +++ b/lib/NGCP/Panel/Form/Subscriber/SubscriberAPI.pm @@ -49,6 +49,16 @@ has_field 'lock' => ( }, ); +has_field 'is_pbx_pilot' => ( + type => 'Boolean', + label => 'Is PBX Pilot?', + default => 0, + element_attr => { + rel => ['tooltip'], + title => ['Whether this subscriber is used as PBX pilot subscriber.'], + }, +); + has_field 'pbx_extension' => ( type => 'Text', label => 'PBX Extension', @@ -119,7 +129,7 @@ has_field 'save' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/customer domain pbx_extension e164 alias_numbers email webusername webpassword username password status lock external_id administrative is_pbx_group pbx_group display_name profile_set profile/ ], + render_list => [qw/customer domain pbx_extension e164 alias_numbers email webusername webpassword username password status lock external_id administrative is_pbx_group pbx_group is_pbx_pilot display_name profile_set profile/ ], ); has_block 'actions' => ( diff --git a/lib/NGCP/Panel/Role/API/Subscribers.pm b/lib/NGCP/Panel/Role/API/Subscribers.pm index e3ff3e09a5..d7e79b0082 100644 --- a/lib/NGCP/Panel/Role/API/Subscribers.pm +++ b/lib/NGCP/Panel/Role/API/Subscribers.pm @@ -222,6 +222,7 @@ sub prepare_resource { $resource->{e164} = delete $resource->{primary_number}; $resource->{status} //= 'active'; $resource->{administrative} //= 0; + $resource->{is_pbx_pilot} //= 0; $resource->{profile_set}{id} = delete $resource->{profile_set_id}; $resource->{profile}{id} = delete $resource->{profile_id}; @@ -259,10 +260,31 @@ sub prepare_resource { return; } + my $pilot; + if($customer->get_column('product_class') eq 'pbxaccount') { + $pilot = $customer->voip_subscribers->search({ + 'provisioning_voip_subscriber.is_pbx_pilot' => 1, + },{ + join => 'provisioning_voip_subscriber', + })->first; + + if($pilot && $resource->{is_pbx_pilot}) { + $c->log->error("failed to create subscriber, contract_id " . $customer->id . " already has pbx pilot subscriber"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Customer already has a pbx pilot subscriber."); + return; + } + elsif(!$pilot && !$resource->{is_pbx_pilot}) { + $c->log->error("failed to create subscriber, contract_id " . $customer->id . " has no pbx pilot subscriber and is_pbx_pilot is set"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Customer has no pbx pilot subscriber yet and is_pbx_pilot is not set."); + return; + } + } + + my $preferences = {}; my $admin = 0; unless($customer->get_column('product_class') eq 'pbxaccount') { - for my $pref(qw/is_pbx_group pbx_group_id pbx_extension pbx_hunt_policy pbx_hunt_timeout/) { + for my $pref(qw/is_pbx_group pbx_group_id pbx_extension pbx_hunt_policy pbx_hunt_timeout is_pbx_pilot/) { delete $resource->{$pref}; } $admin = $resource->{admin} // 0; @@ -274,25 +296,15 @@ sub prepare_resource { }, { join => 'provisioning_voip_subscriber', }); - my $admin_subscribers = $subs->search({ - 'provisioning_voip_subscriber.admin' => 1, - }); - my $admin_subscriber = $admin_subscribers->first; - - unless($admin_subscriber) { - $admin = $resource->{admin} // 1; - } else { - $admin = $resource->{admin} // 0; - } - if($admin_subscriber) { + if($pilot) { unless($resource->{pbx_extension}) { $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "A pbx_extension is required if customer is PBX and pilot subscriber exists."); return; } - $resource->{e164}->{cc} = $admin_subscriber->primary_number->cc; - $resource->{e164}->{ac} = $admin_subscriber->primary_number->ac // ''; - $resource->{e164}->{sn} = $admin_subscriber->primary_number->sn . $resource->{pbx_extension}; + $resource->{e164}->{cc} = $pilot->primary_number->cc; + $resource->{e164}->{ac} = $pilot->primary_number->ac // ''; + $resource->{e164}->{sn} = $pilot->primary_number->sn . $resource->{pbx_extension}; unless($resource->{is_pbx_group}) { unless($resource->{pbx_group_id}) { @@ -323,7 +335,7 @@ sub prepare_resource { $preferences->{contract_sound_set} = $default_sound_set->id; } - my $base_number = $admin_subscriber ? $admin_subscriber->primary_number : undef; + my $base_number = $pilot ? $pilot->primary_number : undef; if($base_number) { $preferences->{cloud_pbx_base_cli} = $base_number->cc . ($base_number->ac // '') . $base_number->sn; } @@ -376,17 +388,11 @@ sub prepare_resource { return; } - # TODO: handle pbx subscribers: - # extension - # is group - # default sound set - # TODO: handle status != active my $r = { resource => $resource, customer => $customer, - admin => $admin, alias_numbers => $alias_numbers, preferences => $preferences, }; @@ -399,10 +405,16 @@ sub update_item { my $subscriber = $item; my $customer = $full_resource->{customer}; - my $admin = $full_resource->{admin}; my $alias_numbers = $full_resource->{alias_numbers}; my $preferences = $full_resource->{preferences}; + + if($subscriber->provisioning_voip_subscriber->is_pbx_pilot && !$resource->{is_pbx_pilot}) { + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Cannot revoke is_pbx_pilot status from a subscriber."); + return; + } + + if($subscriber->status ne $resource->{status}) { if($resource->{status} eq 'locked') { $resource->{lock} = 4; @@ -521,7 +533,8 @@ sub update_item { password => $resource->{password}, webusername => $resource->{webusername}, webpassword => $resource->{webpassword}, - admin => $resource->{administrative}, + admin => $resource->{administrative} // 0, + is_pbx_pilot => $resource->{is_pbx_pilot} // 0, is_pbx_group => $resource->{is_pbx_group} // 0, pbx_group_id => $resource->{pbx_group_id}, modify_timestamp => NGCP::Panel::Utils::DateTime::current_local, diff --git a/lib/NGCP/Panel/Utils/Subscriber.pm b/lib/NGCP/Panel/Utils/Subscriber.pm index 4ab3dc3397..a985624907 100644 --- a/lib/NGCP/Panel/Utils/Subscriber.pm +++ b/lib/NGCP/Panel/Utils/Subscriber.pm @@ -237,6 +237,7 @@ sub create_subscriber { admin => $params->{administrative} // $administrative, account_id => $contract->id, domain_id => $prov_domain->id, + is_pbx_pilot => $params->{is_pbx_pilot} // 0, is_pbx_group => $params->{is_pbx_group} // 0, pbx_group_id => $params->{pbx_group_id}, pbx_extension => $params->{pbx_extension},