TT#4333 Fix CF issues for subscribers

* Fix syntax errors and internal errors
* Pass set ids back in mappings
* Allow updates of mappings both via name and ids

Change-Id: I26fdfe96d67563c11040a6c1e87f13a835bb793f
changes/09/15609/4
Andreas Granig 8 years ago
parent a0b9e64e9a
commit dc0bd38e73

@ -182,11 +182,10 @@ sub POST :Allow {
my $dset;
if($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
if($c->user->roles eq "subscriberadmin") {
$resource->{subscriber_id} //= $c->user->voip_subscriber->id;
} elsif($c->user->roles eq "subscriber") {
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
} elsif(!defined $resource->{subscriber_id}) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Missing mandatory field 'subscriber_id'");
last;
}
my $b_subscriber = $schema->resultset('voip_subscribers')->find({
@ -196,6 +195,12 @@ sub POST :Allow {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'subscriber_id'.");
last;
}
#if($c->user->roles eq "subscriberadmin" &&
# $b_subscriber->contract_id != $c->user->account_id) {
# $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
# last;
#}
my $subscriber = $b_subscriber->provisioning_voip_subscriber;
unless($subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");

@ -42,7 +42,7 @@ __PACKAGE__->config(
action => {
(map { $_ => {
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller subscriberadmin subscribere/],
AllowedRole => [qw/admin reseller subscriberadmin subscriber/],
Args => 1,
Does => [qw(ACL RequireSSL)],
Method => $_,

@ -148,17 +148,17 @@ sub auto :Private {
$c->log->debug("++++++ checking '".$c->user->domain->domain."' against '$d'");
if ($c->user->domain->domain ne $d) {
$c->user->logout;
$c->log->debug("+++++ invalid api subscriber http login (domain check failed)");
$c->log->warn("invalid api http login from '".$c->req->address."'");
$c->log->debug("+++++ invalid api subscriber http login by '$username' (domain check failed)");
$c->log->warn("invalid api http login from '".$c->req->address."' by '$username'");
my $r = $c->get_auth_realm($realm);
$r->credential->authorization_required_response($c, $r);
return;
}
$c->log->debug("++++++ subscriber '".$c->user->webusername."' authenticated via api_subscriber_http");
$c->log->debug("++++++ subscriber '$username' authenticated via api_subscriber_http");
} else {
$c->user->logout if($c->user);
$c->log->debug("+++++ invalid api subscriber http login");
$c->log->warn("invalid api http login from '".$c->req->address."'");
$c->log->warn("invalid api http login from '".$c->req->address."' by '$username'");
my $r = $c->get_auth_realm($realm);
$r->credential->authorization_required_response($c, $r);
return;
@ -173,7 +173,7 @@ sub auto :Private {
unless($c->user_exists && $c->user->is_active) {
$c->user->logout if($c->user);
$c->log->debug("+++++ invalid api admin http login");
$c->log->warn("invalid api http login from '".$c->req->address."'");
$c->log->warn("invalid api http login from '".$c->req->address."' by '$user'");
my $r = $c->get_auth_realm($realm);
$r->credential->authorization_required_response($c, $r);
return;

@ -0,0 +1,16 @@
package NGCP::Panel::Form::CallForward::CFDestinationSetAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::CallForward::CFDestinationSetSubAPI';
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this destination set belongs to.']
},
);
1;
# vim: set tabstop=4 expandtab:

@ -1,21 +1,11 @@
package NGCP::Panel::Form::CFDestinationSetAPI;
package NGCP::Panel::Form::CallForward::CFDestinationSetSubAPI;
use HTML::FormHandler::Moose;
use HTML::FormHandler::Widget::Block::Bootstrap;
extends 'HTML::FormHandler';
has_field 'id' => (
type => 'Hidden',
);
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this destination set belongs to.']
},
);
has_field 'name' => (
type => 'Text',
label => 'Name',

@ -0,0 +1,16 @@
package NGCP::Panel::Form::CallForward::CFDestinationSetSubadminAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::CallForward::CFDestinationSetSubAPI';
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 0,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this destination set belongs to, or null to set it for own subscriber.']
},
);
1;
# vim: set tabstop=4 expandtab:

@ -1,12 +1,7 @@
package NGCP::Panel::Form::CFMappingsAPI;
package NGCP::Panel::Form::CallForward::CFMappingsAPI;
use HTML::FormHandler::Moose;
use HTML::FormHandler::Widget::Block::Bootstrap;
extends 'HTML::FormHandler';
has '+widget_wrapper' => (default => 'Bootstrap');
sub build_render_list {[qw/fields actions/]}
sub build_form_element_class {[qw(form-horizontal)]}
has_field 'id' => (
type => 'Hidden',
noupdate => 1,
@ -73,7 +68,8 @@ has_field 'cfs' => (
rel => ['tooltip'],
title => ['Call Forward SMS, Number of Objects, each containing the keys ' .
'"destinationset", "timeset" and "sourceset". The values must be the name of ' .
'a corresponding set which belongs to the same subscriber.'],
'a corresponding set which belongs to the same subscriber. Alternatively, ' .
'you can pass destinationset_id, timeset_id and sourceset_id instead of names.'],
},
);
@ -83,100 +79,169 @@ has_field 'cfu.destinationset' => (
do_label => 0,
);
has_field 'cfu.destinationset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfu.timeset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfu.timeset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfu.sourceset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfu.sourceset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfb.destinationset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfb.destinationset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfb.timeset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfb.timeset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfb.sourceset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfb.sourceset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cft.destinationset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cft.destinationset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cft.timeset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cft.timeset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cft.sourceset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cft.sourceset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfna.destinationset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfna.destinationset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfna.timeset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfna.timeset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfna.sourceset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfna.sourceset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfs.destinationset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfs.destinationset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfs.timeset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cfs.timeset_id' => (
type => 'PosInteger',
do_label => 0,
);
has_field 'cfs.sourceset' => (
type => 'Text',
do_wrapper => 1,
do_label => 0,
);
has_field 'cft_ringtimeout' => (
has_field 'cfs.sourceset_id' => (
type => 'PosInteger',
do_wrapper => 1,
do_label => 0,
);
has_block 'fields' => (
tag => 'div',
class => [qw(modal-body)],
render_list => [qw(cfu cfb cft cfna cfs)],
has_field 'cft_ringtimeout' => (
type => 'PosInteger',
do_wrapper => 1,
do_label => 0,
);
1;

@ -0,0 +1,16 @@
package NGCP::Panel::Form::CallForward::CFSourceSetAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::CallForward::CFSourceSetSubAPI';
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this source set belongs to']
},
);
1;
# vim: set tabstop=4 expandtab:

@ -1,25 +1,13 @@
package NGCP::Panel::Form::CFSourceSetAPI;
package NGCP::Panel::Form::CallForward::CFSourceSetSubAPI;
use HTML::FormHandler::Moose;
use HTML::FormHandler::Widget::Block::Bootstrap;
extends 'HTML::FormHandler';
has_field 'id' => (
type => 'Hidden',
);
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this source set belongs to']
},
);
has_field 'name' => (
type => 'Text',
label => 'Name',
wrapper_class => [qw/hfh-rep-field/],
required => 1,
element_attr => {
rel => ['tooltip'],
@ -36,7 +24,7 @@ has_field 'mode' => (
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The source set mode']
title => ['The source set mode. A blacklist forwards everything except numbers in the list, a whitelist only forwards numbers in this list.']
},
);
@ -45,7 +33,7 @@ has_field 'sources' => (
element_attr => {
rel => ['tooltip'],
title => ['An array of sources, each containing the key "source" ' .
'which will be matched against the call\'s anumber to determine ' .
'which will be matched against the calling party number to determine ' .
'whether to apply the callforward or not. ' .
'"source" is the calling party number in E164 format to match. ' .
'Shell patterns like 431* or 49123[1-5]67 are possible. ' .

@ -0,0 +1,16 @@
package NGCP::Panel::Form::CallForward::CFSourceSetSubadminAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::CallForward::CFSourceSetSubAPI';
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 0,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this source set belongs to. Defaults to own subscriber id if not given.']
},
);
1;
# vim: set tabstop=4 expandtab:

@ -0,0 +1,16 @@
package NGCP::Panel::Form::CallForward::CFTimeSetAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::CallForward::CFTimeSetSubAPI';
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this time set belongs to.']
},
);
1;
# vim: set tabstop=4 expandtab:

@ -1,6 +1,5 @@
package NGCP::Panel::Form::CFTimeSetAPI;
package NGCP::Panel::Form::CallForward::CFTimeSetSubAPI;
use HTML::FormHandler::Moose;
use HTML::FormHandler::Widget::Block::Bootstrap;
extends 'HTML::FormHandler';
has_field 'id' => (
@ -13,15 +12,6 @@ has_field 'name' => (
required => 1,
);
has_field 'subscriber_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The subscriber id this time set belongs to.']
},
);
has_field 'times' => (
type => 'Repeatable',
do_wrapper => 1,

@ -12,11 +12,21 @@ use NGCP::Panel::Utils::DataHalLink qw();
use HTTP::Status qw(:constants);
use JSON::Types;
use NGCP::Panel::Utils::Subscriber;
use NGCP::Panel::Form::CFDestinationSetAPI;
use NGCP::Panel::Form::CallForward::CFDestinationSetAPI;
use NGCP::Panel::Form::CallForward::CFDestinationSetSubadminAPI;
use NGCP::Panel::Form::CallForward::CFDestinationSetSubAPI;
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::CFDestinationSetAPI->new;
if($c->user->roles eq "subscriber") {
return NGCP::Panel::Form::CallForward::CFDestinationSetSubAPI->new;
} elsif($c->user->roles eq "subscriberadmin") {
# TODO: allow subadmin to manipulate other subs?
#return NGCP::Panel::Form::CallForward::CFDestinationSetSubadminAPI->new;
return NGCP::Panel::Form::CallForward::CFDestinationSetSubAPI->new;
} else {
return NGCP::Panel::Form::CallForward::CFDestinationSetAPI->new;
}
}
sub hal_from_item {
@ -43,6 +53,7 @@ sub hal_from_item {
my $b_subs_id = $item->subscriber->voip_subscriber->id;
$resource{subscriber_id} = $b_subs_id;
my $adm = $c->user->roles eq "admin" || $c->user->roles eq "reseller";
my $hal = NGCP::Panel::Utils::DataHal->new(
links => [
@ -55,9 +66,8 @@ sub hal_from_item {
NGCP::Panel::Utils::DataHalLink->new(relation => 'collection', href => sprintf("%s", $self->dispatch_path)),
NGCP::Panel::Utils::DataHalLink->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
NGCP::Panel::Utils::DataHalLink->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
NGCP::Panel::Utils::DataHalLink->new(relation => "ngcp:$type", href => sprintf("/api/%s/%d", $type, $item->id)),
NGCP::Panel::Utils::DataHalLink->new(relation => "ngcp:subscribers", href => sprintf("/api/subscribers/%d", $b_subs_id)),
$self->get_journal_relation_link($item->id),
$adm ? $self->get_journal_relation_link($item->id) : (),
],
relation => 'ngcp:'.$self->resource_name,
);
@ -117,6 +127,10 @@ sub update_item {
resource => $resource,
exceptions => [ "subscriber_id" ],
);
if($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
}
if (! exists $resource->{destinations} ) {
$resource->{destinations} = [];

@ -13,11 +13,11 @@ use HTTP::Status qw(:constants);
use JSON::Types;
use NGCP::Panel::Utils::Subscriber;
use NGCP::Panel::Utils::Preferences;
use NGCP::Panel::Form::CFMappingsAPI;
use NGCP::Panel::Form::CallForward::CFMappingsAPI;
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::CFMappingsAPI->new;
return NGCP::Panel::Form::CallForward::CFMappingsAPI->new;
}
sub hal_from_item {
@ -33,16 +33,33 @@ sub hal_from_item {
$ringtimeout_preference = $ringtimeout_preference ? $ringtimeout_preference->value : undef;
for my $mapping ($item->provisioning_voip_subscriber->voip_cf_mappings->all) {
my $dset = $mapping->destination_set ? $mapping->destination_set->name : undef;
my $tset = $mapping->time_set ? $mapping->time_set->name : undef;
my $sset = $mapping->source_set ? $mapping->source_set->name : undef;
push @{ $resource->{$mapping->type} }, {
destinationset => $dset,
timeset => $tset,
sourceset => $sset,
$mapping->destination_set ? (
destinationset => $mapping->destination_set->name,
destinationset_id => $mapping->destination_set->id,
) : (
destinationset => undef,
destinationset_id => undef,
),
$mapping->time_set ? (
timeset => $mapping->time_set->name,
timeset_id => $mapping->time_set->id,
) : (
timeset => undef,
timeset_id => undef,
),
$mapping->source_set ? (
sourceset => $mapping->source_set->name,
sourceset_id => $mapping->source_set->id,
) : (
sourceset => undef,
sourceset_id => undef,
),
};
}
my $adm = $c->user->roles eq "admin" || $c->user->roles eq "reseller";
my $hal = NGCP::Panel::Utils::DataHal->new(
links => [
NGCP::Panel::Utils::DataHalLink->new(
@ -54,9 +71,8 @@ sub hal_from_item {
NGCP::Panel::Utils::DataHalLink->new(relation => 'collection', href => sprintf("%s", $self->dispatch_path)),
NGCP::Panel::Utils::DataHalLink->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
NGCP::Panel::Utils::DataHalLink->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
NGCP::Panel::Utils::DataHalLink->new(relation => "ngcp:$type", href => sprintf("/api/%s/%d", $type, $item->id)),
NGCP::Panel::Utils::DataHalLink->new(relation => "ngcp:subscribers", href => sprintf("/api/subscribers/%d", $b_subs_id)),
$self->get_journal_relation_link($item->id),
$adm ? $self->get_journal_relation_link($item->id) : (),
],
relation => 'ngcp:'.$self->resource_name,
);
@ -69,6 +85,7 @@ sub hal_from_item {
run => 0,
);
$resource->{cft_ringtimeout} = $ringtimeout_preference;
$resource->{id} = int($item->id);
$hal->resource($resource);
return $hal;
}
@ -90,7 +107,7 @@ sub _item_rs {
});
} elsif($c->user->roles eq "subscriber" || $c->user->roles eq "subscriberadmin") {
$item_rs = $item_rs->search({
'uuid' => $c->user->uuid,
'me.uuid' => $c->user->uuid,
});
}
@ -138,31 +155,64 @@ sub update_item {
$cf_preferences{$type} = NGCP::Panel::Utils::Preferences::get_usr_preference_rs(
c => $c, prov_subscriber => $item->provisioning_voip_subscriber, attribute => $type);
for my $mapping (@{ $resource->{$type} }) {
unless ($mapping->{destinationset}) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid field 'destinationset' in '$type'. Must be defined.");
my $dset;
if(defined $mapping->{destinationset_id}) {
$dset = $dsets_rs->find({
subscriber_id => $p_subs_id,
id => $mapping->{destinationset_id},
});
} elsif($mapping->{destinationset}) {
$dset = $dsets_rs->find({
subscriber_id => $p_subs_id,
name => $mapping->{destinationset},
});
} else {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Missing field 'destinationset' or 'destinationset_id' in '$type'.");
return;
}
my $dset = $dsets_rs->find({subscriber_id => $p_subs_id, name => $mapping->{destinationset}, });
unless ($dset) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'destinationset'. Could not be found.");
return;
}
my $tset;
if ($mapping->{timeset}) {
$tset = $tsets_rs->find({subscriber_id => $p_subs_id, name => $mapping->{timeset}, });
unless ($tset) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'timeset'. Could not be found.");
return;
}
my $tset; my $has_tset;
if (defined $mapping->{timeset_id}) {
$tset = $tsets_rs->find({
subscriber_id => $p_subs_id,
id => $mapping->{timeset_id},
});
$has_tset = 1;
} elsif (defined $mapping->{timeset}) {
$tset = $tsets_rs->find({
subscriber_id => $p_subs_id,
name => $mapping->{timeset},
});
$has_tset = 1;
}
my $sset;
if ($mapping->{sourceset}) {
$sset = $ssets_rs->find({subscriber_id => $p_subs_id, name => $mapping->{sourceset}, });
unless ($sset) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'sourceset'. Could not be found.");
return;
}
if($has_tset && !$tset) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'timeset'. Could not be found.");
return;
}
my $sset; my $has_sset;
if (defined $mapping->{sourceset_id}) {
$sset = $ssets_rs->find({
subscriber_id => $p_subs_id,
id => $mapping->{sourceset_id},
});
$has_sset = 1;
} elsif (defined $mapping->{sourceset}) {
$sset = $ssets_rs->find({
subscriber_id => $p_subs_id,
name => $mapping->{sourceset},
});
$has_sset = 1;
}
if($has_sset && !$sset) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'sourceset'. Could not be found.");
return;
}
push @new_mappings, $mappings_rs->new_result({
destination_set_id => $dset->id,
time_set_id => $tset ? $tset->id : undef,

@ -12,11 +12,21 @@ use NGCP::Panel::Utils::DataHalLink qw();
use HTTP::Status qw(:constants);
use JSON::Types;
use NGCP::Panel::Utils::Subscriber;
use NGCP::Panel::Form::CFSourceSetAPI;
use NGCP::Panel::Form::CallForward::CFSourceSetSubAPI;
#use NGCP::Panel::Form::CallForward::CFSourceSetSubadminAPI;
use NGCP::Panel::Form::CallForward::CFSourceSetAPI;
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::CFSourceSetAPI->new;
if($c->user->roles eq "subscriber") {
return NGCP::Panel::Form::CallForward::CFSourceSetSubAPI->new;
} elsif($c->user->roles eq "subscriberadmin") {
#return NGCP::Panel::Form::CallForward::CFSourceSetSubadminAPI->new;
return NGCP::Panel::Form::CallForward::CFSourceSetSubAPI->new;
} else {
return NGCP::Panel::Form::CallForward::CFSourceSetAPI->new;
}
}
sub hal_from_item {
@ -33,6 +43,7 @@ sub hal_from_item {
my $b_subs_id = $item->subscriber->voip_subscriber->id;
$resource{subscriber_id} = $b_subs_id;
my $adm = $c->user->roles eq "admin" || $c->user->roles eq "reseller";
my $hal = NGCP::Panel::Utils::DataHal->new(
links => [
@ -45,9 +56,8 @@ sub hal_from_item {
NGCP::Panel::Utils::DataHalLink->new(relation => 'collection', href => sprintf("%s", $self->dispatch_path)),
NGCP::Panel::Utils::DataHalLink->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
NGCP::Panel::Utils::DataHalLink->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
NGCP::Panel::Utils::DataHalLink->new(relation => "ngcp:$type", href => sprintf("/api/%s/%d", $type, $item->id)),
NGCP::Panel::Utils::DataHalLink->new(relation => "ngcp:subscribers", href => sprintf("/api/subscribers/%d", $b_subs_id)),
$self->get_journal_relation_link($item->id),
$adm ? $self->get_journal_relation_link($item->id) : (),
],
relation => 'ngcp:'.$self->resource_name,
);
@ -78,7 +88,8 @@ sub _item_rs {
} , {
join => {'subscriber' => {'contract' => 'contact'} },
});
} elsif($c->user->role eq "subscriberadmin" || $c->user->roles eq "subscriber") {
# TODO: do we want subscriberadmins to update other subs' entries?
} elsif($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
$item_rs = $c->model('DB')->resultset('voip_cf_source_sets')
->search_rs({
'subscriber_id' => $c->user->id,
@ -116,6 +127,13 @@ sub update_item {
return;
}
if($c->user->roles eq "subscriber" || $c->user->roles eq "subscriberadmin") {
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
}
# elsif($c->user->roles eq "subscriberadmin") {
# $resource->{subscriber_id} //= $c->user->id;
#}
my $b_subscriber = $schema->resultset('voip_subscribers')->find($resource->{subscriber_id});
unless ($b_subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'subscriber_id'.");
@ -126,6 +144,10 @@ sub update_item {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
last;
}
#if($c->user->roles eq "subscriberadmin" && $subscriber->account_id != $c->user->account_id) {
# $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid subscriber.");
# last;
#}
try {
$item->update({

@ -12,11 +12,17 @@ use NGCP::Panel::Utils::DataHalLink qw();
use HTTP::Status qw(:constants);
use JSON::Types;
use NGCP::Panel::Utils::Subscriber;
use NGCP::Panel::Form::CFTimeSetAPI;
use NGCP::Panel::Form::CallForward::CFTimeSetSubAPI;
use NGCP::Panel::Form::CallForward::CFTimeSetAPI;
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::CFTimeSetAPI->new;
if($c->user->roles eq "subscriber" || $c->user->roles eq "subscriberadmin") {
return NGCP::Panel::Form::CallForward::CFTimeSetSubAPI->new;
} else {
return NGCP::Panel::Form::CallForward::CFTimeSetAPI->new;
}
}
sub hal_from_item {
@ -79,7 +85,7 @@ sub _item_rs {
} , {
join => {'subscriber' => {'contract' => 'contact'} },
});
} elsif($c->user->role eq "subscriberadmin" || $c->user->roles eq "subscriber") {
} elsif($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
$item_rs = $c->model('DB')->resultset('voip_cf_time_sets')
->search_rs({
'subscriber_id' => $c->user->id,
@ -117,6 +123,10 @@ sub update_item {
return;
}
if($c->user->roles eq "subscriber" || $c->user->roles eq "subscriberadmin") {
$resource->{subscriber_id} = $c->user->voip_subscriber->id;
}
my $b_subscriber = $schema->resultset('voip_subscribers')->find($resource->{subscriber_id});
unless ($b_subscriber) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'subscriber_id'.");

@ -24,10 +24,8 @@ sub get_form {
my ($self, $c) = @_;
if($c->user->roles eq "admin" || $c->user->roles eq "reseller") {
$c->log->error("++++ admin form");
return NGCP::Panel::Form::Subscriber::SubscriberAPI->new(ctx => $c);
} elsif($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
$c->log->error("++++ subscriber form");
return NGCP::Panel::Form::Subscriber::SubscriberSubAdminAPI->new(ctx => $c);
}
}

@ -0,0 +1,208 @@
#!/usr/bin/perl -w
use strict;
use NGCP::Test;
use Test::More;
use JSON qw/from_json to_json/;
use Data::Dumper;
my $test = NGCP::Test->new(log_debug => 1);
my $t = $test->generate_sid();
my $c = $test->client();
my $ref = $test->reference_data(
client => $c,
use_persistent => 1,
delete_persistent => 0,
depends => [
{
resource => 'subscribers',
name => 'my_seat_subscriber',
hints => [{ name => 'pbx seat subscriber'}]
}
],
);
my $dom = $ref->data('my_seat_subscriber')->{domain};
my $c_sub_ext = $test->client(
role => 'subscriber',
username =>
$ref->data('my_seat_subscriber')->{webusername} . '@' . $dom,
password => $ref->data('my_seat_subscriber')->{webpassword},
);
diag("test destination set as subscriber");
my $cf_dstset = $test->resource(
client => $c_sub_ext,
resource => 'cfdestinationsets',
data => {
name => 'test cf destination set',
destinations => [
# TODO: we have to define all fields here to pass deep testing
{ destination => "sip:12340\@$dom", timeout => 180, priority => 1, announcement_id => undef, simple_destination => '12340' },
{ destination => "sip:12341\@$dom", timeout => 180, priority => 2, announcement_id => undef, simple_destination => '12341' },
{ destination => "sip:12342\@$dom", timeout => 180, priority => 3, announcement_id => undef, simple_destination => '12342' },
],
},
);
$cf_dstset->test_post(
name => 'create destination sets',
expected_result => { 'code' => 201 },
);
my $dstset = $cf_dstset->pop_created_item();
$cf_dstset->test_put(
name => "test update",
item => $dstset,
data_replace => {
field => 'destinations', value => [
{ destination => "sip:22340\@$dom", timeout => 180, priority => 1, announcement_id => undef, simple_destination => '22340' },
{ destination => "sip:22341\@$dom", timeout => 180, priority => 2, announcement_id => undef, simple_destination => '22341' },
{ destination => "sip:22342\@$dom", timeout => 180, priority => 3, announcement_id => undef, simple_destination => '22342' },
],
},
expected_result => { code => 200 },
);
diag("test source set as subscriber");
my $cf_srcset = $test->resource(
client => $c_sub_ext,
resource => 'cfsourcesets',
data => {
name => 'test cf source set',
mode => 'whitelist',
sources => [
{ source => "1235*" },
{ source => "1236" },
{ source => "1237[1-5]" },
],
},
);
$cf_srcset->test_post(
name => 'create source sets',
expected_result => { 'code' => 201 },
);
my $srcset = $cf_srcset->pop_created_item();
$cf_srcset->test_put(
name => "test update",
item => $srcset,
data_replace => {
field => 'mode', value => 'blacklist',
},
expected_result => { code => 200 },
);
diag("test time set as subscriber");
my $cf_timset = $test->resource(
client => $c_sub_ext,
resource => 'cftimesets',
data => {
name => 'test cf time set',
times => [
{ year => "2017", month => undef, mday => undef, wday => undef, hour => undef, minute => undef },
{ year => "2018-2019", month => undef, mday => undef, wday => undef, hour => undef, minute => undef },
{ year => undef, month => undef, mday => "10-20", wday => undef, hour => undef, minute => undef },
],
},
);
$cf_timset->test_post(
name => 'create time sets',
expected_result => { 'code' => 201 },
);
my $timset = $cf_timset->pop_created_item();
$cf_timset->test_put(
name => "test update",
item => $timset,
data_replace => {
field => 'times', value => [
{ year => "2020", month => undef, mday => undef, wday => undef, hour => undef, minute => undef },
]
},
expected_result => { code => 200 },
);
diag("test cf mappings");
my $cf_map = $test->resource(
client => $c_sub_ext,
resource => 'cfmappings',
data => {
cfu => [],
cfb => [],
cft => [],
cfna => [],
cfs => [],
cft_ringtimeout => undef,
}
);
my $mappings = $cf_map->test_get(
name => 'prefetch cf mappings',
expected_links => [qw/
ngcp:subscribers
/],
expected_result => { 'code' => 200 },
);
my $mapping = $mappings->[0]->{_embedded}->{'ngcp:cfmappings'}->[0];
my $cfu = [{
destinationset => $dstset->{name},
destinationset_id => $dstset->{id},
sourceset => $srcset->{name},
sourceset_id => $srcset->{id},
timeset => $timset->{name},
timeset_id => $timset->{id},
}];
$mappings = $cf_map->test_put(
name => "update cfmapping",
item => $mapping,
data_replace => {
field => 'cfu', value => $cfu,
},
expected_result => { code => 200 },
);
ok(@{ $mappings->[0]->{cfu} } > 0, "test size of postfetched cfu mapping");
$test->inc_test_count();
$cf_dstset->test_delete(
name => "test delete",
item => $dstset,
expected_result => { code => 204 },
);
$cf_srcset->test_delete(
name => "test delete",
item => $srcset,
expected_result => { code => 204 },
);
$cf_timset->test_delete(
name => "test delete",
item => $timset,
expected_result => { code => 204 },
);
$cf_map->test_delete(
name => "test delete",
item => $mapping,
expected_result => { code => 404 },
);
$mapping->{cfu} = [];
$mappings = $cf_map->test_get(
name => "refetch cfmapping after delete",
item => $mapping,
expected_links => [qw/
ngcp:subscribers
/],
expected_result => { code => 200 },
);
$test->done();

@ -161,10 +161,15 @@ has 'last_rtt' => (
sub _request {
my ($self, $req) = @_;
my $t0 = [gettimeofday];
$self->_test->debug("content of " . $req->method . " request to " . $req->uri . ":\n");
$self->_test->debug($req->content || "<empty request>");
$self->_test->debug("\n");
my $res = $self->_ua->request($req);
my $rtt = tv_interval($t0);
$self->last_rtt($rtt);
$self->_test->debug($res->decoded_content // '<empty response>');
$self->_test->debug("content of response:\n");
$self->_test->debug($res->decoded_content || "<empty response>");
$self->_test->debug("\n");
return $res;
}

@ -192,7 +192,8 @@ sub _read_depends {
#$self->_test->debug("+++ checking hint field $$hint{field} with expected value $$hint{value} against ".$ref->{data}->{$hint->{field}}."\n");
if(defined $hint->{name} && $hint->{name} eq $ref->{name}) {
$hint_found = 1;
$self->_dependstree->{$d->{name}} = $ref->{data};
$self->_dependstree->{$d->{name}}->{data} = $ref->{data};
$self->_dependstree->{$d->{name}}->{meta}->{type} = $ref->{type};
last;
} elsif(defined $hint->{field} && exists $ref->{data}->{$hint->{field}} &&
"".$hint->{value} eq "".$ref->{data}->{$hint->{field}}) {
@ -200,7 +201,8 @@ sub _read_depends {
#$self->_test->debug("found reference data using hints:\n");
#$self->_test->debug Dumper $ref->{data};
$hint_found = 1;
$self->_dependstree->{$d->{name}} = $ref->{data};
$self->_dependstree->{$d->{name}}->{data} = $ref->{data};
$self->_dependstree->{$d->{name}}->{meta}->{type} = $ref->{type};
last;
}
}
@ -212,7 +214,8 @@ sub _read_depends {
#$self->_test->debug("found reference data:\n");
#$self->_test->debug Dumper $ref->{data};
$resource_found = 1;
$self->_dependstree->{$d->{name}} = $ref->{data};
$self->_dependstree->{$d->{name}}->{data} = $ref->{data};
$self->_dependstree->{$d->{name}}->{meta}->{type} = $ref->{type};
last;
}
}
@ -317,8 +320,26 @@ sub _resolve_deps {
sub data {
my ($self, $name) = @_;
if(exists $self->_dependstree->{$name}) {
return $self->_dependstree->{$name};
my $ref = $self->_dependstree->{$name};
if($ref) {
if($ref->{meta}->{full}) {
return $ref->{data};
} else {
$self->_test->debug("$name not fully fetched yet\n");
my $res = $self->client->_get(
'api/'.$ref->{meta}->{type}.'/'.$ref->{data}->{id}
);
unless($res->is_success) {
die "Failed to fully fetch " .
"$ref->{meta}->{type} #$ref->{data}->{id}: " .
$res->status_line."\n";
}
my $data = from_json($res->decoded_content);
$self->_dependstree->{$name}->{data} = $data;
$self->_test->debug("$name now fully fetched yet\n");
$self->_dependstree->{$name}->{meta}->{full} = 1;
return $data;
}
} else {
die "Failed to find given dependency name '$name' in dependency tree, check name against 'depends' in constructor\n";
}

@ -21,5 +21,29 @@
"customer_id": "${filled pbxaccount customer}",
"status": "active"
}
},
{
"name": "pbx seat subscriber",
"type": "subscribers",
"depends": [
"pbx pilot subscriber",
"filled pbxaccount customer",
"domain"
],
"data": {
"username": "pbx_seat_user_${sid}",
"password": "pbx_seat_pass_${sid}",
"webusername": "pbx_seat_webuser_${sid}",
"webpassword": "pbx_seat_webpass_${sid}",
"display_name": "pbx seat display ${sid}",
"primary_number": {
"cc": "43", "ac": "998", "sn": "${sid}"
},
"administrative": false,
"domain_id": "${domain}",
"customer_id": "${filled pbxaccount customer}",
"status": "active",
"pbx_extension": "101"
}
}
]

@ -238,6 +238,9 @@ sub _test_fields {
my $k = (keys %{ $skip{$field} })[0];
my $refold = delete $refelem->{$k};
my $old = delete $elem->{$k};
$self->_test->debug("compare content of $field\n");
$self->_test->debug("element: " . Dumper $elem);
$self->_test->debug("reference element: " . Dumper $refelem);
is_deeply($elem, $refelem, $name . " - content of $field");
$self->_inc_test_count;
$refelem->{$k} = $refold;
@ -246,6 +249,9 @@ sub _test_fields {
is(@{ $ref->{$field} }, @{ $item->{$field} }, "$name - element count of $field");
$self->_inc_test_count;
} else {
$self->_test->debug("compare content of $field via bag comparison\n");
$self->_test->debug("element: " . Dumper $item->{$field});
$self->_test->debug("reference element: " . Dumper $ref->{$field});
cmp_bag($item->{$field}, $ref->{$field}, $name . " - content of $field");
$self->_inc_test_count;
}
@ -668,6 +674,7 @@ sub test_put {
for(my $i = 0; $i < @data; ++$i) {
my $d = $self->_get_replaced_data($item, $data[$i]);
$self->_test->debug("replaced data: " . Dumper $d);
my $e = $expected[$i];
my $name = "$testname $i";

Loading…
Cancel
Save