You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/lib/NGCP/Panel/Utils/Preferences.pm

2952 lines
118 KiB

package NGCP::Panel::Utils::Preferences;
use Sipwise::Base;
use Data::Validate::IP qw/is_ipv4 is_ipv6/;
use NGCP::Panel::Form::Preferences;
use NGCP::Panel::Utils::Generic qw(:all);
use NGCP::Panel::Utils::I18N qw//;
use NGCP::Panel::Utils::Sems;
use JSON qw();
use HTTP::Status qw(:constants);
use File::Type;
use Readonly;
use MIME::Base64 qw(decode_base64);
use List::Util qw(first);
use constant _DYNAMIC_PREFERENCE_PREFIX => '__';
our $TYPE_PREF_MAP = {
'domains' => 'dom',
'profiles' => 'prof',
'subscribers' => 'usr',
'peerings' => 'peer',
'resellers' => 'reseller',
'pbxdevicemodels' => 'dev',
'pbxdeviceprofiles' => 'devprof',
'pbxdevices' => 'fielddev',
'contracts' => 'contract',
};
my $API_TRANSFORM_OUT;
my $API_TRANSFORM_IN;
my $CODE_SUFFIX_FNAME = '_code';
Readonly my $blob_short_value_size => 4096;
sub validate_ipnet {
my ($field) = @_;
if ( !$field->value ) {
$field->add_error("Invalid IPv4 or IPv6 address, must be valid address with optional /net suffix.");
return;
}
return _validate_ipnet(undef, $field->value, sub {
my ($code, $msg) = @_;
$field->add_error($msg);
});
}
sub _validate_ipnet {
my ($pref, $ipnet, $err_code) = @_;
if (!defined $err_code || ref $err_code ne 'CODE') {
$err_code = sub { };
}
my ($ip, $net) = split /\//, $ipnet;
if(is_ipv4($ip)) {
return 1 unless(defined $net);
unless(is_int($net) && $net >= 0 && $net <= 32) {
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid IPv4 network portion in $pref entry '$ipnet', must be 0 <= net <= 32") if $pref;
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid IPv4 network portion, must be 0 <= net <= 32") unless $pref;
return;
}
} elsif(is_ipv6($ip)) {
return 1 unless(defined $net);
unless(is_int($net) && $net >= 0 && $net <= 128) {
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid IPv6 network portion in $pref entry '$ipnet', must be 0 <= net <= 128") if $pref;
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid IPv6 network portion, must be 0 <= net <= 128") unless $pref;
return;
}
} else {
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid IPv4 or IPv6 address in $pref entry '$ipnet', must be valid address with optional /net suffix") if $pref;
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid IPv4 or IPv6 address, must be valid address with optional /net suffix") unless $pref;
return;
}
return 1;
}
sub prepare_resource {
my %params = @_;
my ($c,
$schema,
$item,
$type) = @params{qw/
c
schema
item
type
/};
my $prefs;
my $blob_rs;
my %profile_attrs = (); # for filtering profiles based list
my %profile_allowed_attrs; # for filtering subscriber attrs on its profile
my $has_profile = 0;
my $attr = 0;
if ($type eq "active") {
my $sub_prefs = $item->provisioning_voip_subscriber->voip_usr_preferences->search(undef,{
columns => [ 'value', 'attribute_id'],
});
my $profile = $item->provisioning_voip_subscriber->voip_subscriber_profile;
if ($profile) {
$has_profile = 1;
%profile_allowed_attrs = map { $_ => 1 } $profile->profile_attributes->get_column('attribute_id')->all;
}
my $dom_prefs = $item->domain->provisioning_voip_domain->voip_dom_preferences->search(undef,{
columns => ['value', 'attribute_id'],
result_class => $sub_prefs->result_class,
});
#search for location if IP is provided
my $location_id;
if ($c->request->param('location_ip')) {
my $location = $schema->resultset('voip_contract_locations')->search({
'voip_contract_location_blocks.ip' => $c->request->param('location_ip')
},{
join => 'voip_contract_location_blocks'
})->first;
$location_id = $location->id if ($location);
}
my $ct_prefs = $item->contract->voip_contract_preferences->search({
location_id => $location_id || undef
},{
columns => ['value', 'attribute_id'],
result_class => $sub_prefs->result_class,
});
$prefs = $sub_prefs->union($ct_prefs->search({attribute_id => {-not_in => [map {$_->get_column('attribute_id')} $sub_prefs->all]}}));
$prefs = $prefs->union($dom_prefs->search({attribute_id => {-not_in => [map {$_->get_column('attribute_id')} $prefs->all]}}));
$prefs = $prefs->search({
}, {
prefetch => 'attribute',
});
} else {
if($type eq "subscribers") {
$prefs = $item->provisioning_voip_subscriber->voip_usr_preferences;
$blob_rs = $c->model('DB')->resultset('voip_usr_preferences_blob');
my $profile = $item->provisioning_voip_subscriber->voip_subscriber_profile;
if ($profile) {
$has_profile = 1;
%profile_allowed_attrs = map { $_ => 1 } $profile->profile_attributes->get_column('attribute_id')->all;
}
} elsif($type eq "profiles") {
$attr = 1;
%profile_attrs = map { $_ => 1 } $item->profile_attributes->get_column('attribute_id')->all;
$prefs = $item->voip_prof_preferences;
} elsif($type eq "domains") {
$prefs = $item->provisioning_voip_domain->voip_dom_preferences;
$blob_rs = $c->model('DB')->resultset('voip_dom_preferences_blob');
} elsif($type eq "peerings") {
$prefs = $item->voip_peer_preferences;
$blob_rs = $c->model('DB')->resultset('voip_peer_preferences_blob');
} elsif($type eq "resellers") {
$prefs = $item->reseller_preferences;
} elsif($type eq "contracts") {
$prefs = $item->voip_contract_preferences->search(
{ location_id => $c->request->param('location_id') || undef },
undef);
$blob_rs = $c->model('DB')->resultset('voip_contract_preferences_blob');
} elsif($type eq "pbxdevicemodels") {
$prefs = $item->voip_dev_preferences;
} elsif($type eq "pbxdeviceprofiles") {
$prefs = $item->voip_devprof_preferences;
} elsif($type eq "pbxdevices") {
$prefs = $item->voip_fielddev_preferences;
}
$prefs = $prefs->search({
}, {
prefetch => 'attribute',
order_by => { '-asc' => 'me.id' },
});
}
my $resource;
foreach my $pref($prefs->all) {
my $value;
my $processed = 0;
if ($c->user->roles eq 'subscriberadmin' || $c->user->roles eq 'subscriber') {
my $attrname = $pref->attribute->attribute;
unless ( $pref->attribute->expose_to_customer ) {
$c->log->debug("skipping attribute $attrname, not exposing to customer");
next;
}
if ($has_profile && !$profile_allowed_attrs{$pref->attribute_id}) {
$c->log->debug("skipping attribute $attrname, not in profile");
next;
}
}
SWITCH: for ($pref->attribute->attribute) {
/^rewrite_calle[re]_(in|out)_dpid$/ && do {
if(exists $resource->{rewrite_rule_set}) {
$processed = 1;
last SWITCH;
}
do { $processed = 1; last SWITCH; }
if($attr && !_check_profile($c, 'rewrite_rule_set', \%profile_attrs));
my $col = $pref->attribute->attribute;
$col =~ s/^rewrite_//;
my $rwr_set = $schema->resultset('voip_rewrite_rule_sets')->find({
$col => $pref->value,
});
if($rwr_set) {
$resource->{rewrite_rule_set} = $rwr_set->name;
} else {
$c->log->error("no rewrite rule set for '".$pref->attribute->attribute."' with value '".$pref->value."' found, although it's stored in preference id ".$pref->id);
# let it slip through
}
$processed = 1;
last SWITCH;
};
/^cdr_export_sclidui_rwrs_id$/ && do {
my $pref_name = $pref->attribute->attribute;
$pref_name =~ s/_id$//;
my $rwr_set = $schema->resultset('voip_rewrite_rule_sets')->find({
id => $pref->value,
});
if($rwr_set) {
$resource->{$pref_name} = $rwr_set->name;
} else {
$c->log->error("no rewrite rule set for '".$pref->attribute->attribute."' with value '".$pref->value."' found, although it's stored in preference id ".$pref->id);
# let it slip through
}
$processed = 1;
last SWITCH;
};
/^(adm_)?(cf_)?ncos_id$/ && do {
my $pref_name = $pref->attribute->attribute;
$pref_name =~ s/_id$//;
do { $processed = 1; last SWITCH; }
if($attr && !_check_profile($c, $pref_name, \%profile_attrs));
my $ncos = $schema->resultset('ncos_levels')->find({
id => $pref->value,
});
if($ncos) {
$resource->{$pref_name} = $ncos->level;
} else {
$c->log->error("no ncos level for '".$pref->attribute->attribute."' with value '".$pref->value."' found, although it's stored in preference id ".$pref->id);
# let it slip through
}
$processed = 1;
last SWITCH;
};
/^emergency_mapping_container_id$/ && do {
my $pref_name = $pref->attribute->attribute;
$pref_name =~ s/_id$//;
do { $processed = 1; last SWITCH; }
if($attr && !_check_profile($c, $pref_name, \%profile_attrs));
my $container = $schema->resultset('emergency_containers')->find({
id => $pref->value,
});
if($container) {
$resource->{$pref_name} = $container->name;
} else {
$c->log->error("no emergency mapping container for '".$pref->attribute->attribute."' with value '".$pref->value."' found, although it's stored in preference id ".$pref->id);
# let it slip through
}
$processed = 1;
last SWITCH;
};
/^(contract_)?sound_set$/ && do {
# TODO: not applicable for domains, but for subs, check for contract_id!
do { $processed = 1; last SWITCH; }
if($attr && !_check_profile($c, $_, \%profile_attrs));
my $set = $schema->resultset('voip_sound_sets')->find({
id => $pref->value,
});
if($set) {
$resource->{$pref->attribute->attribute} = $set->name;
} else {
$c->log->error("no sound set for '".$pref->attribute->attribute."' with value '".$pref->value."' found, although it's stored in preference id ".$pref->id);
# let it slip through
}
$processed = 1;
last SWITCH;
};
/^(man_)?allowed_ips_grp$/ && do {
my $pref_name = $pref->attribute->attribute;
$pref_name =~ s/_grp$//;
do { $processed = 1; last SWITCH; }
if($attr && !_check_profile($c, $pref_name, \%profile_attrs));
my $sets = $schema->resultset('voip_allowed_ip_groups')->search({
group_id => $pref->value,
}, {
order_by => { -asc => 'id' },
});
foreach my $set($sets->all) {
$resource->{$pref_name} = []
unless exists($resource->{$pref_name});
push @{ $resource->{$pref_name} }, $set->ipnet;
}
$processed = 1;
last SWITCH;
};
/^header_rule_set$/ && do {
my $hrs = $schema->resultset('voip_header_rule_sets')->find({
id => $pref->value,
});
if($hrs) {
$resource->{$pref->attribute->attribute} = $hrs->name;
} else {
$c->log->error("no header rule set for '".$pref->attribute->attribute."' with value '".$pref->value."' found, although it's stored in preference id ".$pref->id);
# let it slip through
}
$processed = 1;
last SWITCH;
};
# default
if($attr && !$profile_attrs{$pref->attribute->id}) {
$processed = 1; last SWITCH;
}
if($pref->attribute->internal != 0) {
$processed = 1;
last SWITCH;
}
} # SWITCH
next if $processed;
SWITCH: for ($pref->attribute->data_type) {
/^int$/ && do {
$value = int($pref->value) if(is_int($pref->value));
last SWITCH;
};
/^boolean$/ && do {
if (defined $pref->value) {
$value = ($pref->value ? JSON::true : JSON::false);
}
last SWITCH;
};
/^blob$/ && do {
if (defined $pref->value) {
my $blob = $blob_rs->search({ preference_id => $pref->id });
my $attribute = $pref->attribute->attribute;
if ($c->req->param('preference') && $c->req->param('preference') eq $attribute) {
my $data = $blob->first->value;
my $ft = File::Type->new();
$c->response->header('Content-Disposition' => 'attachment; filename="' . $blob->first->id . '-' . $attribute . '"');
$c->response->content_type($ft->mime_type($blob->first->value) || $blob->first->content_type);
$c->response->body($data);
$c->detach();
return 1;
}
$value = {
content_type => $blob->first->content_type,
data => $blob->first->value ? '#blob' : undef
};
}
last SWITCH;
};
# default
$value = $pref->value;
} # SWITCH
eval {
$value = _api_transform_out($c, $pref->attribute, $value);
};
if ($@) {
$c->log->error("Failed to transform pref value - $@");
# let it slip through
}
if($pref->attribute->max_occur != 1) {
$resource->{$pref->attribute->attribute} = []
unless(exists $resource->{$pref->attribute->attribute});
push @{ $resource->{$pref->attribute->attribute} }, $value;
} else {
$resource->{$pref->attribute->attribute} = $value;
}
}
if($type eq "domains") {
$resource->{domain_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "subscribers") {
$resource->{subscriber_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "profiles") {
$resource->{profile_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "peerings") {
$resource->{peering_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "resellers") {
$resource->{reseller_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "pbxdevicemodels") {
$resource->{device_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "pbxdeviceprofiles") {
$resource->{profile_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "pbxdevices") {
$resource->{device_id} = int($item->id);
$resource->{id} = int($item->id);
} elsif($type eq "contracts") {
$resource->{customer_id} = int($item->id);
$resource->{id} = int($item->id);
$prefs->first ? $resource->{location_id} = $prefs->first->location_id
: undef;
}
return $resource;
}
sub update_preferences {
my %params = @_;
my ($c,
$schema,
$item,
$old_resource,
$resource,
$type,
$replace,
$err_code) = @params{qw/
c
schema
item
old_resource
resource
type
replace
err_code
/};
if (!defined $err_code || ref $err_code ne 'CODE') {
$err_code = sub { };
}
delete $resource->{id};
my $accessor;
my $elem;
my $pref_type;
my $reseller_id;
my $full_rs;
my $old_auth_prefs = {};
if($type eq "domains") {
delete $resource->{domain_id};
delete $resource->{domainpreferences_id};
delete $old_resource->{domain_id};
delete $old_resource->{domainpreferences_id};
$accessor = $item->domain;
$elem = $item->provisioning_voip_domain;
$full_rs = $elem->voip_dom_preferences;
$pref_type = 'dom_pref';
$reseller_id = $item->reseller_id;
} elsif($type eq "profiles") {
delete $resource->{profile_id};
delete $resource->{profilepreferences_id};
delete $old_resource->{profile_id};
delete $old_resource->{profilepreferences_id};
$accessor = $item->id;
$elem = $item;
$full_rs = $elem->voip_prof_preferences;
$pref_type = 'prof_pref';
$reseller_id = $item->profile_set->reseller_id;
} elsif($type eq "subscribers") {
delete $resource->{subscriber_id};
delete $resource->{subscriberpreferences_id};
delete $old_resource->{subscriber_id};
delete $old_resource->{subscriberpreferences_id};
$accessor = $item->username . '@' . $item->domain->domain;
$elem = $item->provisioning_voip_subscriber;
$full_rs = $elem->voip_usr_preferences;
if ($c->user->roles eq 'subscriberadmin' || $c->user->roles eq 'subscriber') {
$full_rs = $full_rs->search_rs({
'attribute.expose_to_customer' => 1,
},{
join => 'attribute',
});
if ($elem && $elem->voip_subscriber_profile) {
my @allowed_attr_ids = $elem->voip_subscriber_profile->profile_attributes
->get_column('attribute_id')->all;
$full_rs = $full_rs->search_rs({
'attribute.id' => { '-in' => \@allowed_attr_ids },
});
}
}
$pref_type = 'usr_pref';
$reseller_id = $item->contract->contact->reseller_id;
} elsif($type eq "peerings") {
delete $resource->{peer_id};
delete $resource->{peerpreferences_id};
delete $old_resource->{peer_id};
delete $old_resource->{peerpreferences_id};
$accessor = $item->name;
$elem = $item;
$full_rs = $elem->voip_peer_preferences;
$pref_type = 'peer_pref';
$reseller_id = 1;
} elsif($type eq "resellers") {
delete $resource->{reseller_id};
delete $resource->{resellerpreferences_id};
delete $old_resource->{reseller_id};
delete $old_resource->{resellerpreferences_id};
$accessor = $item->name;
$elem = $item;
$full_rs = $elem->reseller_preferences;
$pref_type = 'reseller_pref';
$reseller_id = $item->id;
} elsif($type eq "contracts") {
delete $resource->{customer_id};
delete $old_resource->{customer_id};
delete $resource->{location_id};
delete $old_resource->{location_id};
$accessor = $item->id;
$elem = $item;
$full_rs = $elem->voip_contract_preferences->search_rs(
{ location_id => $c->request->param('location_id') || undef },
undef);
$pref_type = 'contract_pref';
$reseller_id = $item->contact->reseller_id;
} elsif($type eq "pbxdevicemodels") {
delete $resource->{device_id};
delete $old_resource->{device_id};
delete $resource->{pbxdevicepreferences_id};
delete $old_resource->{pbxdevicepreferences_id};
$accessor = $item->id;
$elem = $item;
$full_rs = $elem->voip_dev_preferences->search_rs();
$pref_type = 'dev_pref';
$reseller_id = $item->reseller_id;
} elsif($type eq "pbxdeviceprofiles") {
delete $resource->{profile_id};
delete $old_resource->{profile_id};
delete $resource->{pbxdeviceprofilepreferences_id};
delete $old_resource->{pbxdeviceprofilepreferences_id};
$accessor = $item->id;
$elem = $item;
$full_rs = $elem->voip_devprof_preferences->search_rs();
$pref_type = 'devprof_pref';
$reseller_id = $item->config->device->reseller_id;
} elsif($type eq "pbxdevices") {
delete $resource->{device_id};
delete $old_resource->{device_id};
delete $resource->{pbxfielddevicepreferences_id};
delete $old_resource->{pbxfielddevicepreferences_id};
$accessor = $item->id;
$elem = $item;
$full_rs = $elem->voip_fielddev_preferences->search_rs();
$pref_type = 'fielddev_pref';
$reseller_id = $item->profile->config->device->reseller_id;
} else {
return;
}
if ($type eq "subscribers" && grep {/^peer_auth_/} keys %{ $resource }) {
$c->log->debug("Fetching old peer_auth_params for future comparison");
get_peer_auth_params(
$c, $elem, $old_auth_prefs);
};
# make sure to not clear any internal prefs, except for those defined
# in extra:
my $extra = [qw/
rewrite_caller_in_dpid rewrite_caller_out_dpid
rewrite_callee_in_dpid rewrite_callee_out_dpid
rewrite_caller_lnp_dpid rewrite_callee_lnp_dpid
cdr_export_sclidui_rwrs_id
ncos_id adm_ncos_id adm_cf_ncos_id
emergency_mapping_container_id
sound_set contract_sound_set
allowed_ips_grp man_allowed_ips_grp
header_rule_set
/];
$full_rs = $full_rs->search({
-or => [
'attribute.internal' => 0,
'attribute.attribute' => { 'in' => $extra },
]
},{
join => 'attribute',
});
if($replace) {
# in case of PUT, we remove all old entries
try {
$full_rs->delete_all;
} catch($e) {
$c->log->error("failed to clear preferences for '$accessor': $e");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error.");
return;
};
} else {
# in case of PATCH, we remove only those entries marked for removal in the patch
try {
foreach my $k(keys %{ $old_resource }) {
SWITCH: for ($k) {
# no special treatment for *_sound_set deletion, as id is stored in right name
/^rewrite_rule_set$/ && do {
unless(exists $resource->{$k}) {
foreach my $p(qw/
caller_in_dpid callee_in_dpid
caller_out_dpid callee_out_dpid
caller_lnp_dpid callee_lnp_dpid/) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, 'rewrite_' . $p);
next unless $rs; # unknown resource, just ignore
$rs->delete;
}
}
last SWITCH;
};
/^cdr_export_sclidui_rwrs/ && do {
unless(exists $resource->{$k}) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $k . '_id');
last SWITCH unless $rs; # unknown resource, just ignore
$rs->delete;
}
last SWITCH;
};
/^(adm_)?(cf_)?ncos$/ && do {
unless(exists $resource->{$k}) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $k . '_id');
last SWITCH unless $rs; # unknown resource, just ignore
$rs->delete;
}
last SWITCH;
};
/^emergency_mapping_container$/ && do {
unless(exists $resource->{$k}) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $k . '_id');
last SWITCH unless $rs; # unknown resource, just ignore
$rs->delete;
}
last SWITCH;
};
/^(man_)?allowed_ips$/ && do {
unless(exists $resource->{$k}) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $k . '_grp');
last SWITCH unless $rs; # unknown resource, just ignore
if($rs->first) {
$c->model('DB')->resultset('voip_allowed_ip_groups')->search({
group_id => $rs->first->value,
})->delete;
}
$rs->delete;
}
last SWITCH;
};
# default
unless(exists $resource->{$k}) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $k);
last SWITCH unless $rs; # unknown resource, just ignore
$rs->delete;
if ($type eq "subscribers" && ($k eq 'voicemail_echo_number' || $k eq 'cli')) {
NGCP::Panel::Utils::Subscriber::update_voicemail_number(
schema => $c->model('DB'), subscriber => $item);
}
}
} # SWITCH
}
} catch($e) {
$c->log->error("failed to clear preference for '$accessor': $e");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error.");
return;
};
}
my %nullable = (
lock => 1,
);
foreach my $pref(keys %{ $resource }) {
next if (not defined $resource->{$pref} and not $nullable{$pref});
my $pref_rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref);
unless($pref_rs) {
$c->log->debug("removing unknown preference '$pref' from update");
next;
}
$pref_rs = $pref_rs->search(undef, {
order_by => { '-asc' => 'id' },
});
# TODO: can't we get this via $pref_rs->search_related or $pref_rs->related_resultset?
my $meta = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $pref, $pref_type => 1,
});
unless($meta) {
$c->log->error("failed to get voip_preference entry for '$pref'");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error.");
return;
}
try {
my $vtype = ref $resource->{$pref};
my $maxlen = 128;
if($vtype eq "") {
if(defined $resource->{$pref} and length($resource->{$pref}) > $maxlen) {
$c->log->error("preference '$pref' exceeds maximum length of $maxlen characters");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Preference '$pref' exceeds maximum length of $maxlen characters");
return;
}
} elsif($vtype eq "ARRAY") {
foreach my $a(@{ $resource->{$pref} }) {
if(defined $a and length($a) > $maxlen) {
$c->log->error("element in preference '$pref' exceeds maximum length of $maxlen characters");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Element in preference '$pref' exceeds maximum length of $maxlen characters");
return;
}
}
}
if (($meta->data_type eq "boolean" or _exists_api_transform_in($c, $pref)) and JSON::is_bool($resource->{$pref})) {
$vtype = "";
}
if($meta->max_occur == 1 && $vtype ne "" && $meta->data_type ne "blob") {
$c->log->error("preference '$pref' has max_occur '".$meta->max_occur."', but value got passed in as '$vtype', expected flat value");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid data type '$vtype' for preference '$pref', expected flat value");
return;
} elsif($meta->max_occur != 1 && $vtype ne "ARRAY") {
$c->log->error("preference '$pref' has max_occur '".$meta->max_occur."', but value got passed in as '$vtype', expected ARRAY");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid data type '$vtype' for preference '$pref', expected ARRAY");
return;
}
SWITCH: for ($pref) {
/^rewrite_rule_set$/ && do {
my $rwr_set = $c->model('DB')->resultset('voip_rewrite_rule_sets')->find({
name => $resource->{$pref},
$pref_type ne 'peer_pref' ? (reseller_id => $reseller_id) : (),
});
unless($rwr_set) {
$c->log->error("no rewrite rule set '".$resource->{$pref}."' for reseller id $reseller_id found");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Unknown rewrite_rule_set '".$resource->{$pref}."'");
return;
}
foreach my $k(qw/
caller_in_dpid callee_in_dpid
caller_out_dpid callee_out_dpid
caller_lnp_dpid callee_lnp_dpid/) {
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, 'rewrite_'.$k);
if($rs->first) {
$rs->first->update({ value => $rwr_set->$k });
} else {
$rs->create({ value => $rwr_set->$k });
}
}
last SWITCH;
};
/^cdr_export_sclidui_rwrs$/ && do {
my $pref_name = $pref . "_id";
my $rwr_set = $c->model('DB')->resultset('voip_rewrite_rule_sets')->find({
name => $resource->{$pref},
reseller_id => $reseller_id,
});
unless($rwr_set) {
$c->log->error("no rewrite rule set '".$resource->{$pref}."' for reseller id $reseller_id found");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Unknown rewrite_rule_set '".$resource->{$pref}."'");
return;
}
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref_name);
if($rs->first) {
$rs->first->update({ value => $rwr_set->id });
} else {
$rs->create({ value => $rwr_set->id });
}
last SWITCH;
};
/^header_rule_set$/ && do {
my $hdr_set = $c->model('DB')->resultset('voip_header_rule_sets')->find({
name => $resource->{$pref},
$pref_type ne 'peer_pref' ? (reseller_id => $reseller_id) : (),
});
unless ($hdr_set) {
$c->log->error("no header rule set '".$resource->{$pref}."' for reseller id $reseller_id found");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Unknown header_rule_set '".$resource->{$pref}."'");
return;
}
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref);
if ($rs->first) {
$rs->first->update({ value => $hdr_set->id });
} else {
$rs->create({ value => $hdr_set->id });
}
last SWITCH;
};
/^(adm_)?(cf_)?ncos$/ && do {
my $pref_name = $pref . "_id";
my $ncos = $c->model('DB')->resultset('ncos_levels')->find({
level => $resource->{$pref},
reseller_id => $reseller_id,
});
unless($ncos) {
$c->log->error("no ncos level '".$resource->{$pref}."' for reseller id $reseller_id found");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Unknown ncos_level '".$resource->{$pref}."'");
return;
}
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref_name);
if($rs->first) {
$rs->first->update({ value => $ncos->id });
} else {
$rs->create({ value => $ncos->id });
}
last SWITCH;
};
/^emergency_mapping_container$/ && do {
my $pref_name = $pref . "_id";
my $container = $c->model('DB')->resultset('emergency_containers')->find({
name => $resource->{$pref},
reseller_id => $reseller_id,
});
unless($container) {
$c->log->error("no emergency mapping container '".$resource->{$pref}."' for reseller id $reseller_id found");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Unknown emergency mapping container '".$resource->{$pref}."'");
return;
}
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref_name);
if($rs->first) {
$rs->first->update({ value => $container->id });
} else {
$rs->create({ value => $container->id });
}
last SWITCH;
};
/^(contract_)?sound_set$/ && do {
# TODO: not applicable for domains, but for subs, check for contract_id!
my $set = $c->model('DB')->resultset('voip_sound_sets')->find({
name => $resource->{$pref},
$pref_type ne 'peer_pref' ? (reseller_id => $reseller_id) : (),
});
unless($set) {
$c->log->error("no $pref '".$resource->{$pref}."' for reseller id $reseller_id found");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Unknown $pref '".$resource->{$pref}."'");
return;
}
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref);
if($rs->first) {
$rs->first->update({ value => $set->id });
} else {
$rs->create({ value => $set->id });
}
last SWITCH;
};
/^(man_)?allowed_ips$/ && do {
my $pref_name = $pref . "_grp";
my $aig_rs;
my $aig_group_id;
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref_name);
if($rs->first) {
$aig_group_id = $rs->first->value;
$aig_rs = $c->model('DB')->resultset('voip_allowed_ip_groups')->search({
group_id => $aig_group_id
});
$aig_rs->delete;
} else {
my $new_group = $c->model('DB')->resultset('voip_aig_sequence')->create({});
$aig_group_id = $new_group->id;
$aig_rs = $c->model('DB')->resultset('voip_allowed_ip_groups')->search({
group_id => $aig_group_id
});
$c->model('DB')->resultset('voip_aig_sequence')->search_rs({
id => { '<' => $aig_group_id },
})->delete_all;
}
foreach my $ip(@{ $resource->{$pref} }) {
unless(_validate_ipnet($pref, $ip, $err_code)) {
$c->log->error("invalid $pref entry '$ip'");
return;
}
$aig_rs->create({ ipnet => $ip });
}
unless($rs->first) {
$rs->create({ value => $aig_group_id });
}
# in contrast to panel, it does not drop the allowed_ips_grp pref, if empty ipnets.
last SWITCH;
};
/^lock$/ && do {
my $v = $resource->{$pref};
return unless _check_pref_value($c, $meta, $v, $pref_type, $err_code);
NGCP::Panel::Utils::Subscriber::lock_provisoning_voip_subscriber(
c => $c,
prov_subscriber => $elem,
level => $v, # || 0
);
last SWITCH;
};
/^allowed_clis$/ && do {
my $old_seen = {};
unless ($replace) {
#in case of PATCH, check duplicates only for new values, since there could already be duplicates in some systems
($old_seen) = array_to_map($old_resource->{$pref},undef,undef,'first');
}
my $seen = {};
foreach my $allowed_cli (@{$resource->{$pref} // []}) {
next if exists $old_seen->{$allowed_cli};
if (exists $seen->{$allowed_cli}) {
$c->log->error("Duplicate $pref value: ".$allowed_cli);
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Duplicate $pref value: ".$allowed_cli);
return;
} else {
$seen->{$allowed_cli} = 1;
}
}
};
if ($meta->data_type eq 'blob') {
if ($resource->{$pref}->{data} ne '#blob'){
my $file = decode_base64($resource->{$pref}->{data});
my $rs = get_preference_rs($c, $TYPE_PREF_MAP->{$type}, $elem, $pref);
my $blob_rs = $c->model('DB')->resultset("voip_$TYPE_PREF_MAP->{$type}_preferences_blob");
if ($rs->first) {
my $blob = $blob_rs->search({ preference_id => $rs->first->id });
if ($blob->first) {
$blob->update({
preference_id => $rs->first->id,
$file ? (value => $file) : (),
$resource->{$pref}->{content_type} ? (content_type => $resource->{$pref}->{content_type}) : (),
});
} else {
$blob_rs->create({
preference_id => $rs->first->id,
value => ($file ? $file : undef),
content_type => $resource->{$pref}->{content_type},
});
}
} else {
$rs->create({ value => 0 });
$blob_rs->create({
preference_id => $rs->first->id,
value => ($file ? $file : undef),
content_type => $resource->{$pref}->{content_type},
});
}
}
} elsif($meta->max_occur != 1) { #default
$pref_rs->delete;
foreach my $v(@{ $resource->{$pref} }) {
return unless _check_pref_value($c, $meta, $v, $pref_type, $err_code);
eval {
$v = _api_transform_in($c, $meta, $v);
};
if ($@) {
$c->log->error("Failed to transform pref value - $@");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error."); # TODO?
return;
}
if(JSON::is_bool($v)){
$v = $v ? 1 : 0 ;
}
$pref_rs->create({ value => $v });
}
} elsif($pref_rs->first) {
return unless _check_pref_value($c, $meta, $resource->{$pref}, $pref_type, $err_code);
eval {
$resource->{$pref} = _api_transform_in($c, $meta, $resource->{$pref});
};
if ($@) {
$c->log->error("Failed to transform pref value - $@");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error."); # TODO?
return;
}
if(JSON::is_bool($resource->{$pref})){
$resource->{$pref} = $resource->{$pref} ? 1 : 0 ;
}
$pref_rs->first->update({ value => $resource->{$pref} });
} else {
return unless _check_pref_value($c, $meta, $resource->{$pref}, $pref_type, $err_code);
eval {
$resource->{$pref} = _api_transform_in($c, $meta, $resource->{$pref});
};
if ($@) {
$c->log->error("Failed to transform pref value - $@");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error."); # TODO?
return;
}
if(JSON::is_bool($resource->{$pref})){
$resource->{$pref} = $resource->{$pref} ? 1 : 0 ;
}
$pref_rs->create({ value => $resource->{$pref} });
}
} # SWITCH
if ($type eq "subscribers" && ($pref eq 'voicemail_echo_number' || $pref eq 'cli')) {
NGCP::Panel::Utils::Subscriber::update_voicemail_number(
schema => $c->model('DB'), subscriber => $item);
}
} catch($e) {
$c->log->error("failed to update preference for '$accessor': $e");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error.");
return;
}
}
if($type eq "subscribers") {
if(keys %{ $old_auth_prefs }) {
my $new_auth_prefs = {};
my $prov_subscriber = $elem;
get_peer_auth_params(
$c, $prov_subscriber, $new_auth_prefs);
unless(compare($old_auth_prefs, $new_auth_prefs)) {
$c->log->debug("peer_auth_params changed. Updating sems.");
my $type = 'subscriber';
try {
update_sems_peer_auth(
$c, $prov_subscriber, $type, $old_auth_prefs, $new_auth_prefs);
} catch($e) {
$c->log->error("Failed to set peer registration: $e");
&$err_code(HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error."); # TODO?
return;
}
}
}
}
return $item;
}
sub _init_transform {
my ($transform,$conf) = @_;
unless (defined $transform) {
$transform = {};
if (defined $conf) {
foreach my $p (keys %$conf) {
$transform->{$p} = {};
foreach my $v (keys %{$conf->{$p}}) {
if ($v =~ /^([a-z0-9_]+)$CODE_SUFFIX_FNAME$/) {
## no critic (BuiltinFunctions::ProhibitStringyEval)
$transform->{$p}->{$1} = eval($conf->{$p}->{$v});
die("$p '$v': " . $@) if $@;
} else {
$transform->{$p}->{$v} = $conf->{$p}->{$v};
}
}
}
}
}
return $transform;
}
sub _exists_api_transform_in {
my ($c, $pref) = @_;
if ($c->request and $c->request->path =~/^api\//i) {
$API_TRANSFORM_IN = _init_transform($API_TRANSFORM_IN,$c->config->{preference_in_transformations});
if (exists $API_TRANSFORM_IN->{$pref}) {
return 1;
}
}
return 0;
}
sub _api_transform_in {
my ($c, $meta, $value) = @_;
if ($c->request and $c->request->path =~/^api\//i) {
$API_TRANSFORM_IN = _init_transform($API_TRANSFORM_IN,$c->config->{preference_in_transformations});
if (exists $API_TRANSFORM_IN->{$meta->attribute}) {
if (defined $value) {
my $v = $value;
if (JSON::is_bool($v)) {
$v = $v ? 1 : 0 ;
}
if (exists $API_TRANSFORM_IN->{$meta->attribute}->{$v}) {
$value = $API_TRANSFORM_IN->{$meta->attribute}->{$v};
if ('CODE' eq ref $value) {
eval {
$value = $value->($meta,$value);
};
if ($@) {
die($meta->attribute . ": " . $@);
}
}
}
}
}
}
return $value;
}
sub _api_transform_out {
my ($c, $meta, $value) = @_;
if ($c->request and $c->request->path =~/^api\//i) {
$API_TRANSFORM_OUT = _init_transform($API_TRANSFORM_OUT,$c->config->{preference_out_transformations});
if (exists $API_TRANSFORM_OUT->{$meta->attribute}) {
if (defined $value) {
my $v = $value;
if (JSON::is_bool($v)) {
$v = $v ? 1 : 0 ;
}
if (exists $API_TRANSFORM_OUT->{$meta->attribute}->{$v}) {
$value = $API_TRANSFORM_OUT->{$meta->attribute}->{$v};
if ('CODE' eq ref $value) {
eval {
$value = $value->($meta,$value);
};
if ($@) {
die($meta->attribute . ": " . $@);
}
}
}
}
}
}
return $value;
}
sub _check_pref_value {
my ($c, $meta, $value, $pref_type, $err_code) = @_;
return 1 if _exists_api_transform_in($c,$meta->attribute);
if (!defined $err_code || ref $err_code ne 'CODE') {
$err_code = sub { };
}
my $err;
my $vtype = ref $value;
if (($meta->data_type eq "boolean" and JSON::is_bool($value)) or $meta->data_type eq "blob") {
$vtype = "";
}
unless($vtype eq "") {
$c->log->error("preference '".$meta->attribute."' has invalid value data structure, expected plain value");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid data structure as value for element in preference '".$meta->attribute."', expected plain value");
return;
}
SWITCH: for ($meta->data_type) {
/^int$/ && do {
$err = 1 unless is_int($value);
last SWITCH;
};
/^boolean$/ && do {
unless (JSON::is_bool($value)
or (is_int($value) and ($value == 0 or $value == 1))) {
$err = 1;
}
last SWITCH;
};
# default
} # SWITCH
if($err) {
$c->log->error("preference '".$meta->attribute."' has invalid value data type, expected '".$meta->data_type."'");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid data type for element in preference '".$meta->attribute."', expected '".$meta->data_type."'");
return;
}
if($meta->data_type eq "enum") {
my $enum = $c->model('DB')->resultset('voip_preferences_enum')->find({
preference_id => $meta->id,
$pref_type => 1,
value => $value,
});
unless($enum) {
$c->log->error("preference '".$meta->attribute."' has invalid enum value '".$value."'");
&$err_code(HTTP_UNPROCESSABLE_ENTITY, "Invalid enum value in preference '".$meta->attribute."'");
return;
}
}
return 1;
}
sub load_preference_list {
my %params = @_;
my $c = $params{c};
my $pref_values = $params{pref_values};
my $peer_pref = $params{peer_pref};
my $reseller_pref = $params{reseller_pref};
my $dom_pref = $params{dom_pref};
my $dev_pref = $params{dev_pref};
my $devprof_pref = $params{devprof_pref};
my $fielddev_pref = $params{fielddev_pref};
my $prof_pref = $params{prof_pref};
my $usr_pref = $params{usr_pref};
my $contract_pref = $params{contract_pref};
my $contract_location_pref = $params{contract_location_pref};
my $profile = $params{sub_profile};
my $customer_view = $params{customer_view} // 0;
my $cloudpbx_enabled = $c->config->{features}{cloudpbx};
my $search_conditions = $params{search_conditions};
my $pref_rs = $c->model('DB')
->resultset('voip_preference_groups')
->search({ 'voip_preferences.internal' => { '<=' => 0 },
$contract_pref ? ('voip_preferences.contract_pref' => 1,
-or => ['voip_preferences_enums.contract_pref' => 1,
'voip_preferences_enums.contract_pref' => undef]) : (),
$contract_location_pref ? ('voip_preferences.contract_location_pref' => 1,
-or => ['voip_preferences_enums.contract_location_pref' => 1,
'voip_preferences_enums.contract_location_pref' => undef]) : (),
$peer_pref ? ('voip_preferences.peer_pref' => 1,
-or => ['voip_preferences_enums.peer_pref' => 1,
'voip_preferences_enums.peer_pref' => undef]) : (),
$reseller_pref ? ('voip_preferences.reseller_pref' => 1,
-or => ['voip_preferences_enums.reseller_pref' => 1,
'voip_preferences_enums.reseller_pref' => undef]) : (),
$dom_pref ? ('voip_preferences.dom_pref' => 1,
-or => ['voip_preferences_enums.dom_pref' => 1,
'voip_preferences_enums.dom_pref' => undef]) : (),
$dev_pref ? ('voip_preferences.dev_pref' => 1,
-or => ['voip_preferences_enums.dev_pref' => 1,
'voip_preferences_enums.dev_pref' => undef]) : (),
$devprof_pref ? ('voip_preferences.devprof_pref' => 1,
-or => ['voip_preferences_enums.devprof_pref' => 1,
'voip_preferences_enums.devprof_pref' => undef]) : (),
$fielddev_pref ? ('voip_preferences.fielddev_pref' => 1,
-or => ['voip_preferences_enums.fielddev_pref' => 1,
'voip_preferences_enums.fielddev_pref' => undef]) : (),
$prof_pref ? ('voip_preferences.prof_pref' => 1,
-or => ['voip_preferences_enums.prof_pref' => 1,
'voip_preferences_enums.prof_pref' => undef]) : (),
$usr_pref ? ('voip_preferences.usr_pref' => 1,
-or => ['voip_preferences_enums.usr_pref' => 1,
'voip_preferences_enums.usr_pref' => undef]) : (),
$customer_view ? ('voip_preferences.expose_to_customer' => 1) : (),
$cloudpbx_enabled ? () : ('me.name' => { '!=' => 'Cloud PBX'}),
}, {
prefetch => {'voip_preferences' => 'voip_preferences_enums'},
});
if($prof_pref) {
my @prof_attributes = $profile->profile_attributes->get_column('attribute_id')->all;
$pref_rs = $pref_rs->search({
'voip_preferences.id' => { in => \@prof_attributes }
});
}
if($search_conditions) {
if('ARRAY' eq ref $search_conditions){
$pref_rs = $pref_rs->search(@$search_conditions);
}else{
$pref_rs = $pref_rs->search($search_conditions);
}
}
my @pref_groups = $pref_rs->all;
foreach my $group(@pref_groups) {
my @group_prefs = $group->voip_preferences->all;
foreach my $pref(@group_prefs) {
my @values = @{
exists $pref_values->{$pref->attribute}
? $pref_values->{$pref->attribute}
: []
};
if($pref->attribute eq "rewrite_rule_set") {
my $tmp;
$pref->{rwrs_id} = $pref_values->{rewrite_caller_in_dpid} &&
($tmp = $c->stash->{rwr_sets_rs}->search({
caller_in_dpid => $pref_values->{rewrite_caller_in_dpid}
})->first) ?
$tmp->id
: undef;
} elsif($pref->attribute eq "cdr_export_sclidui_rwrs") {
my $tmp;
$pref->{rwrs_id} = $pref_values->{$pref->attribute . '_id'} &&
($tmp = $c->stash->{rwr_sets_rs}->search({
id => $pref_values->{$pref->attribute . '_id'}
})->first) ?
$tmp->id
: undef;
} elsif($pref->attribute eq "ncos") {
if ($pref_values->{ncos_id} &&
(my $tmp = $c->stash->{ncos_levels_rs}
->find($pref_values->{ncos_id}) )) {
$pref->{ncos_id} = $tmp->id;
}
} elsif($pref->attribute eq "adm_ncos") {
if ($pref_values->{adm_ncos_id} &&
(my $tmp = $c->stash->{ncos_levels_rs}
->find($pref_values->{adm_ncos_id}) )) {
$pref->{adm_ncos_id} = $tmp->id;
}
} elsif($pref->attribute eq "adm_cf_ncos") {
if ($pref_values->{adm_cf_ncos_id} &&
(my $tmp = $c->stash->{ncos_levels_rs}
->find($pref_values->{adm_cf_ncos_id}) )) {
$pref->{adm_cf_ncos_id} = $tmp->id;
}
} elsif($pref->attribute eq "emergency_mapping_container") {
if ($pref_values->{emergency_mapping_container_id} &&
(my $tmp = $c->stash->{emergency_mapping_containers_rs}
->find($pref_values->{emergency_mapping_container_id}) )) {
$pref->{emergency_mapping_container_id} = $tmp->id;
}
} elsif($pref->attribute eq "allowed_ips") {
$pref->{allowed_ips_group_id} = $pref_values->{allowed_ips_grp};
$pref->{allowed_ips_rs} = $c->model('DB')->resultset('voip_allowed_ip_groups')
->search_rs({ group_id => $pref_values->{allowed_ips_grp} });
} elsif($pref->attribute eq "man_allowed_ips") {
$pref->{man_allowed_ips_group_id} = $pref_values->{man_allowed_ips_grp};
$pref->{man_allowed_ips_rs} = $c->model('DB')->resultset('voip_allowed_ip_groups')
->search_rs({ group_id => $pref_values->{man_allowed_ips_grp} });
} elsif($c->stash->{subscriber} &&
($pref->attribute eq "block_in_list" || $pref->attribute eq "block_out_list")) {
foreach my $v(@values) {
my $prefix = "";
if($v =~ /^\#/) {
$v =~ s/^\#//;
$prefix = "#";
}
if($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
$v = NGCP::Panel::Utils::Subscriber::apply_rewrite(
c => $c, subscriber => $c->stash->{subscriber}, number => $v, direction => 'caller_out'
);
}
$v = $prefix . $v;
}
}
if($pref->data_type eq "enum") {
$pref->{enums} = [];
my @enums = $pref->voip_preferences_enums->all;
push @{ $pref->{enums} }, @enums;
}
if($pref->max_occur != 1) {
$pref->{value} = \@values;
} else {
$pref->{value} = $values[0];
}
}
$group->{prefs} = \@group_prefs;
}
$c->stash(pref_groups => \@pref_groups);
}
sub create_preference_form {
my %params = @_;
my $c = $params{c};
my $pref_rs = $params{pref_rs};
my $base_uri = $params{base_uri};
my $edit_uri = $params{edit_uri};
my $enums = $params{enums};
my $blob_rs = $params{blob_rs};
my $aip_grp_rs;
my $aip_group_id;
my $man_aip_grp_rs;
my $man_aip_group_id;
my $delete_param = $c->request->params->{delete};
my $deactivate_param = $c->request->params->{deactivate};
my $activate_param = $c->request->params->{activate};
my $param_id = $delete_param || $deactivate_param || $activate_param;
# only one parameter is processed at a time (?)
if($param_id) {
my $rs = $pref_rs->find($param_id);
if($rs) {
if($rs->attribute_id != $c->stash->{preference_meta}->id) {
# Invalid param (dom_pref does not belong to current pref)
} elsif($delete_param) {
$rs->delete();
} elsif ($deactivate_param) {
$rs->update({value => "#".$rs->value});
} elsif ($activate_param) {
my $new_value = $rs->value;
$new_value =~ s/^#//;
$rs->update({value => $new_value});
}
}
}
my $preselected_value = undef;
if ($c->stash->{preference_meta}->attribute eq "rewrite_rule_set") {
my $rewrite_caller_in_dpid = $pref_rs->search({
'attribute.attribute' => 'rewrite_caller_in_dpid'
},{
join => 'attribute'
})->first;
if (defined $rewrite_caller_in_dpid && (
my $tmp = $preselected_value = $c->stash->{rwr_sets_rs}->search({
caller_in_dpid => $rewrite_caller_in_dpid->value,
})->first
)) {
$preselected_value = $tmp->id;
}
} elsif ($c->stash->{preference_meta}->attribute eq "cdr_export_sclidui_rwrs") {
my $rwrs_id_pref = $pref_rs->search({
'attribute.attribute' => $c->stash->{preference_meta}->attribute . '_id'
},{
join => 'attribute'
})->first;
if (defined $rwrs_id_pref && (
my $tmp = $preselected_value = $c->stash->{rwr_sets_rs}->search({
id => $rwrs_id_pref->value,
})->first
)) {
$preselected_value = $tmp->id;
}
} elsif ($c->stash->{preference_meta}->attribute eq "ncos") {
my $ncos_id_preference = $pref_rs->search({
'attribute.attribute' => 'ncos_id'
},{
join => 'attribute'
})->first;
if (defined $ncos_id_preference) {
$preselected_value = $ncos_id_preference->value;
}
} elsif ($c->stash->{preference_meta}->attribute eq "adm_ncos") {
my $ncos_id_preference = $pref_rs->search({
'attribute.attribute' => 'adm_ncos_id'
},{
join => 'attribute'
})->first;
if (defined $ncos_id_preference) {
$preselected_value = $ncos_id_preference->value;
}
} elsif ($c->stash->{preference_meta}->attribute eq "adm_cf_ncos") {
my $ncos_id_preference = $pref_rs->search({
'attribute.attribute' => 'adm_cf_ncos_id'
},{
join => 'attribute'
})->first;
if (defined $ncos_id_preference) {
$preselected_value = $ncos_id_preference->value;
}
} elsif ($c->stash->{preference_meta}->attribute eq "emergency_mapping_container") {
my $container_id_preference = $pref_rs->search({
'attribute.attribute' => 'emergency_mapping_container_id'
},{
join => 'attribute'
})->first;
if (defined $container_id_preference) {
$preselected_value = $container_id_preference->value;
}
} elsif ($c->stash->{preference_meta}->attribute eq "allowed_ips") {
my $allowed_ips_grp = $pref_rs->search({
'attribute.attribute' => 'allowed_ips_grp'
},{
join => 'attribute'
})->first;
if (defined $allowed_ips_grp) {
$aip_group_id = $allowed_ips_grp->value;
$aip_grp_rs = $c->model('DB')->resultset('voip_allowed_ip_groups')
->search({ group_id => $aip_group_id });
}
my $delete_aig_param = $c->request->params->{delete_aig};
if($delete_aig_param) {
my $result = $aip_grp_rs->find($delete_aig_param);
if($result) {
$result->delete;
unless ($aip_grp_rs->first) { #its empty
my $allowed_ips_grp_preference = $pref_rs->search({
'attribute.attribute' => 'allowed_ips_grp'
},{
join => 'attribute'
})->first;
$allowed_ips_grp_preference->delete
if (defined $allowed_ips_grp_preference);
}
}
}
} elsif ($c->stash->{preference_meta}->attribute eq "man_allowed_ips") {
my $man_allowed_ips_grp = $pref_rs->search({
'attribute.attribute' => 'man_allowed_ips_grp'
},{
join => 'attribute'
})->first;
if (defined $man_allowed_ips_grp) {
$man_aip_group_id = $man_allowed_ips_grp->value;
$man_aip_grp_rs = $c->model('DB')->resultset('voip_allowed_ip_groups')
->search({ group_id => $man_aip_group_id });
}
my $delete_man_aig_param = $c->request->params->{delete_man_aig};
if($delete_man_aig_param) {
my $result = $man_aip_grp_rs->find($delete_man_aig_param);
if($result) {
$result->delete;
unless ($man_aip_grp_rs->first) { #its empty
my $man_allowed_ips_grp_preference = $pref_rs->search({
'attribute.attribute' => 'man_allowed_ips_grp'
},{
join => 'attribute'
})->first;
$man_allowed_ips_grp_preference->delete
if (defined $man_allowed_ips_grp_preference);
}
}
}
} elsif ($c->stash->{preference_meta}->data_type eq 'enum') {
if ($c->stash->{preference}->first) {
$preselected_value = $c->stash->{preference}->first->value unless ($c->stash->{preference_meta}->data_type eq 'blob');
} else {
my $default_val = first { $_->default_val; } @{ $enums };
$preselected_value = $default_val ? $default_val->value : undef;
}
} elsif ($c->stash->{preference_meta}->max_occur == 1) {
if ($c->stash->{preference}->first) {
$preselected_value = $c->stash->{preference}->first->value unless ($c->stash->{preference_meta}->data_type eq 'blob');
}
}
# this form is somewhat special, treat it without caching
my $form = NGCP::Panel::Form::Preferences->new({
ctx => $c,
fields_data => [{
meta => $c->stash->{preference_meta},
enums => $enums,
rwrs_rs => $c->stash->{rwr_sets_rs},
hdrs_rs => $c->stash->{hdr_sets_rs},
ncos_rs => $c->stash->{ncos_levels_rs},
emergency_mapping_containers_rs => $c->stash->{emergency_mapping_containers_rs},
sound_rs => $c->stash->{sound_sets_rs},
contract_sound_rs => $c->stash->{contract_sound_sets_rs},
}],
});
$form->create_structure([$c->stash->{preference_meta}->attribute]);
# we have to translate this form separately since it bypasses caching in NGCP::Panel::Form
if ( $c->stash->{preference_meta}->attribute !~ '(ncos|sound_set|emergency_mapping_container)$' ) {
NGCP::Panel::Utils::I18N->translate_form($c, $form);
}
my $posted = ($c->request->method eq 'POST');
if($posted && $c->stash->{preference_meta}->data_type eq 'blob') {
# construct the form field name for blob data types,
# since we need to pass the Catalyst::Upload object to req params
my $field_name = $c->stash->{preference_meta}->attribute . '.file';
$c->req->params->{$field_name} = $c->req->upload($field_name) if ($c->req->upload($field_name));
}
$form->process(
posted => $posted,
params => $c->request->params,
item => { $c->stash->{preference_meta}->attribute => $preselected_value },
);
NGCP::Panel::Utils::Navigation::check_form_buttons(
c => $c,
form => $form,
fields => {},
back_uri => $c->req->uri,
);
# logging
my %log_data = %{$c->request->params};
# subscriber prefs
if ($c->stash->{subscriber}) {
%log_data = ( %log_data,
type => 'subscriber',
subscriber_id => $c->stash->{subscriber}->id,
uuid => $c->stash->{subscriber}->uuid,
);
# domain prefs
} elsif ($c->stash->{domain}) {
%log_data = ( %log_data,
type => 'domain',
domain_id => $c->stash->{domain}{id},
domain => $c->stash->{domain}{domain},
);
# customer prefs
} elsif ($c->stash->{contract}) {
%log_data = ( %log_data,
type => 'customer',
customer_id => $c->stash->{contract}->id,
reseller_id => $c->stash->{contract}->contact->reseller_id,
);
# peering prefs
} elsif ($c->stash->{group} && $c->stash->{server}) {
%log_data = ( %log_data,
type => 'peer',
peer_group_id => $c->stash->{group}{id},
peer_group_name => $c->stash->{group}{name},
peer_host_id => $c->stash->{server}{id},
peer_host_name => $c->stash->{server}{name},
);
} elsif ($c->stash->{reseller}) {
%log_data = ( %log_data,
type => 'reseller',
reseller_id => $c->stash->{reseller}->id,
);
} elsif ($c->stash->{devmod}) {
%log_data = ( %log_data,
type => 'dev',
device_id => $c->stash->{devmod}->{id},
device_vendor => $c->stash->{devmod}->{vendor},
device_model => $c->stash->{devmod}->{model},
reseller_id => $c->stash->{devmod}->{reseller_id},
);
} elsif ($c->stash->{devprof}) {
%log_data = ( %log_data,
type => 'devprof',
device_id => $c->stash->{devprof}->{id},
device_vendor => $c->stash->{devprof}->{config_id},
device_model => $c->stash->{devprof}->{name},
);
} elsif ($c->stash->{pbx_device}) {
%log_data = ( %log_data,
type => 'fielddev',
device_id => $c->stash->{pbx_device}->{id},
device_vendor => $c->stash->{pbx_device}->{profile_id},
device_model => $c->stash->{pbx_device}->{identifier},
);
}
if($posted && $form->validated) {
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) {
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;
NGCP::Panel::Utils::Message::info(
c => $c,
type => 'internal',
data => \%log_data,
desc => $c->loc('ip group sequence successfully generated'),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('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,
});
NGCP::Panel::Utils::Message::info(
c => $c,
type => 'internal',
data => \%log_data,
desc => $c->loc('allowed_ip_grp successfully created'),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to create allowed_ip_grp'),
);
$c->response->redirect($base_uri);
return 1;
}
} elsif ($attribute eq "man_allowed_ips") {
unless(validate_ipnet($form->field($attribute))) {
goto OUT;
}
unless (defined $man_aip_group_id) {
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;
NGCP::Panel::Utils::Message::info(
c => $c,
type => 'internal',
data => \%log_data,
desc => $c->loc('Manual ip group sequence successfully generated'),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('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,
});
NGCP::Panel::Utils::Message::info(
c => $c,
type => 'internal',
data => \%log_data,
desc => $c->loc('man_allowed_ip_grp successfully created'),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to create man_allowed_ip_grp'),
);
$c->response->redirect($base_uri);
return 1;
}
} elsif ($attribute eq "allowed_clis") {
my $v = $form->field($attribute)->value;
my $existing_cli = $pref_rs->search({
attribute_id => $c->stash->{preference_meta}->id,
value => $v
});
if ($existing_cli->first) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $c->loc('Duplicate preference [_1]', $attribute),
data => \%log_data,
desc => $c->loc('Duplicate preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
else {
$pref_rs->create({
attribute_id => $c->stash->{preference_meta}->id,
value => $form->values->{$c->stash->{preference_meta}->attribute},
});
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully created', $attribute),
);
}
} elsif ($c->stash->{preference_meta}->max_occur != 1) {
if($c->stash->{subscriber} &&
($c->stash->{preference_meta}->attribute eq "block_in_list" || $c->stash->{preference_meta}->attribute eq "block_out_list")) {
my $v = $form->values->{$c->stash->{preference_meta}->attribute};
if($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") {
$v =~ s/^(.+?)([*\[].*$)/$1/; # strip any trailing shell pattern stuff
my $suffix = $2 // "";
$form->values->{$c->stash->{preference_meta}->attribute} = NGCP::Panel::Utils::Subscriber::apply_rewrite(
c => $c, subscriber => $c->stash->{subscriber}, number => $v, direction => 'callee_in'
);
# rewrite it back for immediate display
$v = $form->values->{$c->stash->{preference_meta}->attribute};
$v = NGCP::Panel::Utils::Subscriber::apply_rewrite(
c => $c, subscriber => $c->stash->{subscriber}, number => $v, direction => 'caller_out'
);
# restore stripped shell pattern stuff
$form->values->{$c->stash->{preference_meta}->attribute} .= $suffix;
$v .= $suffix;
}
}
try {
$pref_rs->create({
attribute_id => $c->stash->{preference_meta}->id,
value => $form->values->{$c->stash->{preference_meta}->attribute},
});
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully created', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to create preference [_1]', $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
);
set_rewrite_preferences(
c => $c,
rwrs_result => $selected_rwrs,
pref_rs => $pref_rs,
);
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
$c->response->redirect($base_uri);
return 1;
} elsif ($attribute eq "cdr_export_sclidui_rwrs") {
my $selected_rwrs = $c->stash->{rwr_sets_rs}->find(
$form->field($attribute)->value
);
set_rewrite_id_preference(
c => $c,
rwrs_result => $selected_rwrs,
pref_rs => $pref_rs,
rwrs_pref_attribute => $attribute,
);
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
$c->response->redirect($base_uri);
return 1;
} elsif ($attribute eq "ncos" || $attribute eq "adm_ncos" || $attribute eq "adm_cf_ncos") {
my $selected_level = $c->stash->{ncos_levels_rs}->find(
$form->field($attribute)->value
);
my $attribute_id = $c->model('DB')->resultset('voip_preferences')
->find({attribute => $attribute."_id"})->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 });
}
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
$c->response->redirect($base_uri);
return 1;
} elsif ($attribute eq "emergency_mapping_container") {
my $selected_container = $c->stash->{emergency_mapping_containers_rs}->find(
$form->field($attribute)->value
);
my $attribute_id = $c->model('DB')->resultset('voip_preferences')
->find({attribute => $attribute."_id"})->id;
try {
my $preference = $pref_rs->search({ attribute_id => $attribute_id });
if(!defined $selected_container) {
$preference->first->delete if $preference->first;
} elsif($preference->first) {
$preference->first->update({ value => $selected_container->id });
} else {
$preference->create({ value => $selected_container->id });
}
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
$c->response->redirect($base_uri);
return 1;
} elsif ($attribute eq "sound_set") {
my $selected_set = $c->stash->{sound_sets_rs}->find(
$form->field($attribute)->value
);
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 });
}
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
$c->response->redirect($base_uri);
return 1;
} elsif ($attribute eq "contract_sound_set") {
my $selected_set = $c->stash->{contract_sound_sets_rs}->find(
$form->field($attribute)->value
);
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 });
}
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
$c->response->redirect($base_uri);
return 1;
} elsif ($attribute eq "lock") {
my $v = $form->field($attribute)->value;
#undef $v if (defined $v && $v eq '');
try {
NGCP::Panel::Utils::Subscriber::lock_provisoning_voip_subscriber(
c => $c,
prov_subscriber => $c->stash->{subscriber}->provisioning_voip_subscriber,
level => $v,
);
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
$c->response->redirect($base_uri);
return 1;
} else {
if( ($c->stash->{preference_meta}->data_type ne 'enum' &&
(!defined $form->field($attribute)->value || $form->field($attribute)->value eq '')) ||
($c->stash->{preference_meta}->data_type eq 'enum' &&
! defined $form->field($attribute)->value)
) {
try {
my $preference = $pref_rs->find($preference_id);
$preference->delete if $preference;
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully deleted', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to delete preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
} elsif($c->stash->{preference_meta}->data_type eq 'boolean' &&
$form->field($attribute)->value == 0) {
try {
my $preference = $pref_rs->find($preference_id);
$preference->delete if $preference;
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully deleted', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to delete preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
} elsif($c->stash->{preference_meta}->data_type eq 'blob') {
try {
my $preference = $pref_rs->search({ attribute_id => $c->stash->{preference_meta}->id });
my $file = $form->field("$attribute.file")->value;
my $content_type = $form->field("$attribute.content_type")->value;
if ($c->req->body_parameters->{"$attribute.delete"}) {
$preference->delete if $preference;
} elsif ($c->req->body_parameters->{"$attribute.download"}) {
my $blob = $blob_rs->search({ preference_id => $preference->first->id });
my $data = $blob->first->value;
my $ft = File::Type->new();
$c->response->header('Content-Disposition' => 'attachment; filename="' . $blob->first->id . '-' . $attribute . '"');
$c->response->content_type($ft->mime_type($blob->first->value) || $blob->first->content_type);
$c->response->body($data);
return 1;
} elsif ($preference->first) {
my $blob = $blob_rs->search({ preference_id => $preference->first->id });
if ($blob->first) {
$blob->update({
preference_id => $preference->first->id,
$file ? (value => $file->slurp) : (),
$content_type ? (content_type => $content_type) : (),
});
} else {
$blob_rs->create({
preference_id => $preference->first->id,
value => ($file ? $file->slurp : undef),
content_type => $content_type,
});
}
} else {
$preference->create({ value => 0 });
$blob_rs->create({
preference_id => $preference->first->id,
value => ($file ? $file->slurp : undef),
content_type => $content_type,
});
}
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
} else {
try {
$pref_rs->update_or_create({
id => $preference_id,
attribute_id => $c->stash->{preference_meta}->id,
value => $form->field($attribute)->value,
});
NGCP::Panel::Utils::Message::info(
c => $c,
data => \%log_data,
desc => $c->loc('Preference [_1] successfully updated', $attribute),
);
} catch($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $e,
data => \%log_data,
desc => $c->loc('Failed to update preference [_1]', $attribute),
);
$c->response->redirect($base_uri);
return 1;
}
}
$c->response->redirect($base_uri);
return 1;
}
}
OUT:
my $preference_values = [];
foreach my $p ( $c->stash->{preference}->all ) {
my $v = $p->value;
$v =~ s/^\#//;
if( ($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") &&
$c->stash->{subscriber} &&
( $c->stash->{preference_meta}->attribute eq "block_in_list" ||
$c->stash->{preference_meta}->attribute eq "block_out_list" )
) {
$v = NGCP::Panel::Utils::Subscriber::apply_rewrite(
c => $c, subscriber => $c->stash->{subscriber}, number => $v, direction => 'caller_out',
);
}
push @{ $preference_values }, {
id => $p->id,
value => $v,
disabled => !!($p->value =~ m/^\#/),
};
}
$form->process if ($posted && $form->validated);
$c->stash(form => $form,
aip_grp_rs => $aip_grp_rs,
man_aip_grp_rs => $man_aip_grp_rs,
preference_values => $preference_values);
return 1;
}
sub _check_profile {
my ($c, $pref_name, $attr) = @_;
my $shown = $c->model('DB')->resultset('voip_preferences')->find({
'attribute' => $pref_name
});
return unless($shown && $attr->{$shown->id});
return 1;
}
sub set_rewrite_preferences {
my %params = @_;
my $c = $params{c};
my $rwrs_result = $params{rwrs_result};
my $pref_rs = $params{pref_rs};
for my $dprules(qw/
callee_in_dpid caller_in_dpid
callee_out_dpid caller_out_dpid
callee_lnp_dpid caller_lnp_dpid/) {
my $attribute_id = $c->model('DB')->resultset('voip_preferences')
->find({attribute => "rewrite_$dprules"})->id;
my $preference = $pref_rs->search({
attribute_id => $attribute_id,
});
if(!defined $rwrs_result) {
$preference->first->delete if $preference->first;
} elsif($preference->first) {
$preference->first->update({ value => $rwrs_result->$dprules });
} else {
$preference->create({ value => $rwrs_result->$dprules });
}
}
}
sub set_rewrite_id_preference {
my %params = @_;
my $c = $params{c};
my $rwrs_result = $params{rwrs_result};
my $pref_rs = $params{pref_rs};
my $rwrs_pref_attribute = $params{rwrs_pref_attribute};
my $attribute_id = $c->model('DB')->resultset('voip_preferences')
->find({attribute => $rwrs_pref_attribute . '_id'})->id;
my $preference = $pref_rs->search({
attribute_id => $attribute_id,
});
if(!defined $rwrs_result) {
$preference->first->delete if $preference->first;
} elsif($preference->first) {
$preference->first->update({ value => $rwrs_result->id });
} else {
$preference->create({ value => $rwrs_result->id });
}
}
sub get_usr_preferences_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $prov_subscriber = $params{prov_subscriber};
my $schema = $params{schema} // $c->model('DB');
my $get_rows = $params{get_rows};
my $pref_rs = $schema->resultset('voip_usr_preferences')->search({
'attribute.usr_pref' => 1,
$attribute ? ( 'attribute.attribute' => (('ARRAY' eq ref $attribute) ? { '-in' => $attribute } : $attribute ) ) : () ,
$prov_subscriber ? ('me.subscriber_id' => $prov_subscriber->id) : (),
},{
'+select' => ['attribute.attribute'],
'+as' => ['attribute'],
'join' => 'attribute',
});
return $pref_rs;
}
sub get_preferences_rs {
my %params = @_;
my $c = $params{c};
my $preferences_type = $params{type};
my $attribute = $params{attribute};
my $item_id = $params{id};
my $schema = $params{schema} // $c->model('DB');
my %config = (
'usr' => [qw/voip_usr_preferences usr_pref subscriber_id/],
'dom' => [qw/voip_dom_preferences dom_pref domain_id/],
'prof' => [qw/voip_prof_preferences prof_pref profile_id/],
'peer' => [qw/voip_peer_preferences peer_pref peer_host_id/],
'reseller' => [qw/reseller_preferences reseller_pref reseller_id/],
'dev' => [qw/voip_dev_preferences dev_pref device_id/],
'devprof' => [qw/voip_devprof_preferences devprof_pref profile_id/],
'fielddev' => [qw/voip_fielddev_preferences fielddev_pref device_id/],
'contract' => [qw/voip_contract_preferences contract_pref contract_id/],
'contract_location' => [qw/voip_contract_preferences contract_location_pref location_id/],
);
my $pref_rs = $schema->resultset($config{$preferences_type}->[0])->search({
'attribute.'.$config{$preferences_type}->[1] => 1, ## no critic (ProhibitCommaSeparatedStatements)
$attribute ? ( 'attribute.attribute' => (('ARRAY' eq ref $attribute) ? { '-in' => $attribute } : $attribute ) ) : () ,
$item_id ? ('me.'.$config{$preferences_type}->[2] => $item_id) : (),
},{
'+select' => ['attribute.attribute'],
'+as' => ['attribute'],
'join' => 'attribute',
});
return $pref_rs;
}
sub get_preference_rs {
my ($c, $type, $elem, $attr, $params) = @_;
my $location_id = $params->{location_id} // undef;
my $subscriberadmin = $params->{subscriberadmin} // ($c->user->roles eq "subscriberadmin" || $c->user->roles eq "subscriber") ? 1 : 0;
my $rs;
if($type eq "dom") {
$rs = get_dom_preference_rs(
c => $c,
attribute => $attr,
prov_domain => $elem,
);
} elsif($type eq "prof") {
$rs = get_prof_preference_rs(
c => $c,
attribute => $attr,
profile => $elem,
);
} elsif($type eq "usr") {
$rs = get_usr_preference_rs(
c => $c,
attribute => $attr,
prov_subscriber => $elem,
$subscriberadmin ? (subscriberadmin => 1) : (),
);
} elsif($type eq "peer") {
$rs = get_peer_preference_rs(
c => $c,
attribute => $attr,
peer_host => $elem,
);
} elsif($type eq "reseller") {
$rs = get_reseller_preference_rs(
c => $c,
attribute => $attr,
reseller => $elem,
);
} elsif($type eq "dev") {
$rs = get_dev_preference_rs(
c => $c,
attribute => $attr,
device => $elem,
);
} elsif($type eq "devprof") {
$rs = get_devprof_preference_rs(
c => $c,
attribute => $attr,
profile => $elem,
);
} elsif($type eq "fielddev") {
$rs = get_fielddev_preference_rs(
c => $c,
attribute => $attr,
device => $elem,
);
} elsif($type eq "contract") {
$rs = get_contract_preference_rs(
c => $c,
attribute => $attr,
contract => $elem,
location_id => $location_id,
);
}
return $rs;
}
sub get_chained_preference_rs {
my ($c, $attr, $elem, $params) = @_;
my $type_order_default = {
'usr' => [qw/usr prof dom/],
};
my $elem_sub_type_id = {
usr => {
prof => $elem->voip_subscriber_profile,
dom => $elem->domain,
}
};
my $preference = $c->model('DB')
->resultset('voip_preferences')
->find({ attribute => $attr });
my $type_meta = $params->{type} // 'usr';
my $type_order = $params->{order} // $type_order_default->{$type_meta};
my $provisioning_subscriber = $params->{provisioning_subscriber};
my $attribute_value_rs;
my $preference_desc = { $preference->get_columns };
foreach my $preference_type ( grep {$preference_desc->{$_.'_pref'} } @{$type_order} ) {
my ($preference_elem_id, $preference_elem);
if ($preference_type eq $type_meta){
$preference_elem = $elem;
} else {
$preference_elem = $elem_sub_type_id->{$type_meta}->{$preference_type};
}
if ($preference_elem) {
$preference_elem_id = $preference_elem->id;
}
if ($preference_elem_id) {
#$attribute_value_rs = get_preferences_rs(
# c => $c,
# type => $preference_type,
# attribute => $attr,
# id => $preference_elem_id,
#);
$attribute_value_rs = get_preference_rs(
$c,
$preference_type,
$preference_elem,
$attr,
{ exists $params->{subscriberadmin} ? (subscriberadmin => $params->{subscriberadmin} ) : () },
);
if ($attribute_value_rs->first) {
return $attribute_value_rs;
}
}
}
return $attribute_value_rs;
}
sub get_usr_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $prov_subscriber = $params{prov_subscriber};
my $schema = $params{schema} // $c->model('DB');
my $is_subadmin = $params{subscriberadmin};
my $pref_rs = $schema->resultset('voip_preferences')->search_rs({
attribute => $attribute,
usr_pref => 1,
$is_subadmin ? (expose_to_customer => 1) : (),
})->first;
return unless($pref_rs);
my $attribute_id = $pref_rs->id;
# filter by allowed attrs from profile
if ($is_subadmin && $prov_subscriber && $prov_subscriber->voip_subscriber_profile) {
my $found_attr = $prov_subscriber->voip_subscriber_profile
->profile_attributes->search_rs({
attribute_id => $attribute_id,
})->first;
unless ($found_attr) {
$c->log->debug("get_usr_preference_rs skipping attr '$attribute' not in profile");
return;
}
}
$pref_rs = $pref_rs->voip_usr_preferences;
if($prov_subscriber) {
$pref_rs = $pref_rs->search({
subscriber_id => $prov_subscriber->id,
attribute_id => $attribute_id
});
}
return $pref_rs;
}
sub get_prof_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $profile = $params{profile};
my $schema = $params{schema} // $c->model('DB');
my $pref_rs = $schema->resultset('voip_preferences')->find({
attribute => $attribute, 'prof_pref' => 1,
});
return unless($pref_rs);
$pref_rs = $pref_rs->voip_prof_preferences;
if($profile) {
# TODO: if profile is not set, it should return an rs with no entries?
$pref_rs = $pref_rs->search({
profile_id => $profile->id,
});
}
return $pref_rs;
}
sub get_dom_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $prov_domain = $params{prov_domain};
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute, 'dom_pref' => 1,
});
return unless($preference);
return $preference->voip_dom_preferences->search_rs({
domain_id => $prov_domain->id,
});
}
sub get_peer_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $host = $params{peer_host};
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute, 'peer_pref' => 1,
});
return unless($preference);
return $preference->voip_peer_preferences->search_rs({
peer_host_id => $host->id,
});
}
sub get_reseller_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $reseller = $params{reseller};
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute, 'reseller_pref' => 1,
});
return unless($preference);
return $preference->reseller_preferences->search_rs({
reseller_id => $reseller->id,
});
}
sub get_dev_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $device = $params{device};
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute, 'dev_pref' => 1,
});
return unless($preference);
return $preference->voip_dev_preferences->search_rs({
device_id => $device->id,
});
}
sub get_devprof_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $profile = $params{profile};
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute, 'devprof_pref' => 1,
});
return unless($preference);
return $preference->voip_devprof_preferences->search_rs({
profile_id => $profile->id,
});
}
sub get_fielddev_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $device = $params{device};
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute, 'fielddev_pref' => 1,
});
return unless($preference);
return $preference->voip_fielddev_preferences->search_rs({
device_id => $device->id,
});
}
sub get_contract_preference_rs {
my %params = @_;
my $c = $params{c};
my $attribute = $params{attribute};
my $contract = $params{contract};
my $location_id = $params{location_id} || undef;
my $preference = $c->model('DB')->resultset('voip_preferences')->find({
attribute => $attribute,
contract_pref => 1,
contract_location_pref => $location_id ? 1 : 0,
});
return unless($preference);
return $preference->voip_contract_preferences->search_rs({
contract_id => $contract->id,
location_id => $location_id,
});
}
sub update_sems_peer_auth {
my ($c, $prov_object, $type, $old_auth_prefs, $new_auth_prefs) = @_;
# prov_object can be either peering or subscriber
if(!_is_peer_auth_active($c, $old_auth_prefs) &&
_is_peer_auth_active($c, $new_auth_prefs)) {
NGCP::Panel::Utils::Sems::create_peer_registration(
$c, $prov_object, $type, $new_auth_prefs);
} elsif( _is_peer_auth_active($c, $old_auth_prefs) &&
!_is_peer_auth_active($c, $new_auth_prefs)) {
NGCP::Panel::Utils::Sems::delete_peer_registration(
$c, $prov_object, $type, $old_auth_prefs);
} elsif(_is_peer_auth_active($c, $old_auth_prefs) &&
_is_peer_auth_active($c, $new_auth_prefs)){
NGCP::Panel::Utils::Sems::update_peer_registration(
$c, $prov_object, $type, $new_auth_prefs, $old_auth_prefs);
}
return;
}
sub get_peer_auth_params {
my ($c, $prov_subscriber, $prefs) = @_;
foreach my $attribute (qw/peer_auth_user peer_auth_hf_user peer_auth_realm peer_auth_pass peer_auth_register/){
my $rs;
$rs = get_usr_preference_rs(
c => $c,
attribute => $attribute,
prov_subscriber => $prov_subscriber
);
$prefs->{$attribute} = $rs->first ? $rs->first->value : undef;
}
}
sub _is_peer_auth_active {
my ($c, $prefs) = @_;
if(defined $prefs->{peer_auth_register} && $prefs->{peer_auth_register} == 1 &&
defined $prefs->{peer_auth_user} &&
defined $prefs->{peer_auth_realm} &&
defined $prefs->{peer_auth_pass}) {
return 1;
}
return;
}
sub set_provisoning_voip_subscriber_first_int_attr_value {
my %params = @_;
my $c = $params{c};
my $prov_subscriber= $params{prov_subscriber};
my $new_value = $params{value};
if (defined $new_value) {
$new_value =~ s/^\s+|\s+$//g;
undef $new_value if $new_value eq '';
}
my $attribute = $params{attribute};
return unless $prov_subscriber;
my $rs = get_usr_preference_rs(
c => $c,
prov_subscriber => $prov_subscriber,
attribute => $attribute,
);
try {
if($rs->first) {
if(($new_value // 0) == 0) {
$rs->first->delete;
} else {
$rs->first->update({ value => $new_value });
}
} elsif(($new_value // 0) > 0) {
$rs->create({ value => $new_value });
} # nothing to do for level 0, if no lock is set yet
} catch($e) {
$c->log->error("failed to set provisioning_voip_subscriber attribute '$attribute': $e");
$e->rethrow;
}
}
sub get_provisoning_voip_subscriber_first_int_attr_value {
my %params = @_;
my $c = $params{c};
my $prov_subscriber= $params{prov_subscriber};
my $attribute = $params{attribute};
return unless $prov_subscriber;
my $rs = get_usr_preference_rs(
c => $c,
prov_subscriber => $prov_subscriber,
attribute => $attribute,
);
try {
return ($rs->first ? $rs->first->value : undef);
} catch($e) {
$c->log->error("failed to get provisioning_voip_subscriber attribute '$attribute': $e");
$e->rethrow;
}
}
sub api_preferences_defs {
my %params = @_;
my $c = $params{c};
my $schema = $params{schema} // $c->model('DB');
my $preferences_group = $params{preferences_group};
my $is_subadmin = ($c->user->roles eq 'subscriberadmin' || $c->user->roles eq 'subscriber');
my $preferences = $c->model('DB')->resultset('voip_preferences')->search({
internal => { '!=' => 1 }, # also fetch -1 for ncos, rwr
$preferences_group => 1,
$is_subadmin ? (expose_to_customer => 1) : (),
});
my $resource = {};
for my $pref($preferences->all) {
my $fields = { $pref->get_inflated_columns };
# remove internal fields
delete @{$fields}{qw/type attribute expose_to_customer internal peer_pref reseller_pref usr_pref dom_pref contract_pref contract_location_pref prof_pref voip_preference_groups_id id modify_timestamp/};
$fields->{max_occur} = int($fields->{max_occur});
$fields->{read_only} = JSON::Types::bool($fields->{read_only});
if($fields->{data_type} eq "enum") {
my @enums = $pref->voip_preferences_enums->search({
$preferences_group => 1,
})->all;
$fields->{enum_values} = [];
foreach my $enum(@enums) {
my $efields = { $enum->get_inflated_columns };
delete @{$efields}{qw/id preference_id usr_pref prof_pref dom_pref peer_pref reseller_pref contract_pref contract_location_pref/};
$efields->{default_val} = JSON::Types::bool($efields->{default_val});
push @{ $fields->{enum_values} }, $efields;
}
}
if ($pref->attribute =~ m/^(cdr_export_sclidui_rwrs|rewrite_rule_set|ncos|adm_ncos|adm_cf_ncos|emergency_mapping_container|sound_set|contract_sound_set|header_rule_set)$/) {
$fields->{data_type} = 'string';
}
my $preference_group = $pref->voip_preference_group->name =~ s/([\[\]])/~$1/rg;
my $label = $fields->{label} =~ s/([\[\]])/~$1/rg;
my $description = $fields->{description} =~ s/([\[\]])/~$1/rg;
$fields->{preference_group} = $c->loc($preference_group);
$fields->{label} = $c->loc($label);
$fields->{description} = $c->loc($description);
$resource->{$pref->attribute} = $fields;
}
return $resource;
}
sub get_subscriber_allowed_prefs {
my %params = @_;
my $c = $params{c};
my $schema = $params{schema} // $c->model('DB');
my $prov_subs = $params{prov_subscriber};
my $pref_list = $params{pref_list};
my %allowed_prefs = map {$_ => 1} @{ $pref_list };
if ($c->user->roles eq "subscriber" || $c->user->roles eq "subscriberadmin") {
if ($prov_subs && $prov_subs->voip_subscriber_profile) {
my $profile = $prov_subs->voip_subscriber_profile;
my @result = $profile->profile_attributes->search_rs({
'attribute.attribute' => { '-in' => $pref_list },
},{
join => 'attribute'
})->get_column('attribute.attribute')->all;
%allowed_prefs = map {$_ => 1} @result;
}
}
return \%allowed_prefs
}
sub create_dynamic_preference {
my ($c, $resource, %params) = @_;
my $group_name = $params{group_name};
my $relations = {};
$resource->{voip_preference_groups_id} = $c->model('DB')
->resultset('voip_preference_groups')->find({name => $group_name})->id;
$resource->{attribute} = dynamic_pref_attribute_to_db($resource->{attribute});
$resource->{dynamic} = 1;
$resource->{internal} = 0;
$resource->{expose_to_customer} = 1;
$relations->{autoprov_device_id} = delete $resource->{autoprov_device_id};
$relations->{reseller_id} = delete $resource->{reseller_id};
my $enums = delete $resource->{enum};
my $preference = $c->model('DB')->resultset('voip_preferences')->create($resource);
my @flags = grep {$_ =~/^[a-z]+_pref$/} keys %$resource;
if(defined $enums and ref $enums eq 'ARRAY'){
foreach my $enum (@$enums) {
@{$enum}{@flags} = (1) x @flags;
$preference->create_related('voip_preferences_enums', $enum);
}
}
save_dynamic_preference_relations($c, $resource, $preference, $relations);
return $preference;
}
sub update_dynamic_preference {
my ($c, $preference, $resource, %params) = @_;
my $relations = {};
$resource->{attribute} = dynamic_pref_attribute_to_db($resource->{attribute});
$relations->{autoprov_device_id} = delete $resource->{autoprov_device_id};
$relations->{reseller_id} = delete $resource->{reseller_id};
my $enums = delete $resource->{enum};
$preference->update($resource);
my @flags = grep {$_ =~/^[a-z]+_pref$/} keys %$resource;
if(defined $enums and ref $enums eq 'ARRAY'){
my $enums_rs = $preference->voip_preferences_enums;
$enums_rs->search_rs({
id => { -not_in => [ map { $_->{id} } @$enums ] },
})->delete;
foreach my $enum (@$enums) {
my $id = delete $enum->{id};
my $enum_exists = $enums_rs->find($id);
@{$enum}{@flags} = (1) x @flags;
if ($enum_exists) {
$enum_exists->update($enum);
} else {
$preference->create_related('voip_preferences_enums', $enum);
}
}
} else {
$preference->voip_preferences_enums->delete;
}
save_dynamic_preference_relations($c, $resource, $preference, $relations);
return $preference;
}
sub delete_dynamic_preference {
my ($c, $preference) = @_;
$preference->voip_preferences_enums->delete;
$preference->delete;
}
sub save_dynamic_preference_relations {
my ($c, $resource, $preference, $relations) = @_;
if (defined $resource->{dev_pref} && $resource->{dev_pref}) {
if ($relations->{autoprov_device_id}) {
$preference->search_related_rs('voip_preference_relations')->update_or_create({
autoprov_device_id => $relations->{autoprov_device_id},
reseller_id => undef,
});
} elsif ($relations->{reseller_id}) {
$preference->search_related_rs('voip_preference_relations')->update_or_create({
autoprov_device_id => undef,
reseller_id => $relations->{reseller_id},
});
}
}
}
sub dynamic_pref_attribute_to_standard {
my ($attribute) = @_;
$attribute =~s/^_*//;
return $attribute;
}
sub dynamic_pref_attribute_to_db {
my ($attribute) = @_;
$attribute =~s/^_*/_DYNAMIC_PREFERENCE_PREFIX/e;
return $attribute;
}
sub get_blob_short_value_size {
return $blob_short_value_size;
}
1;
=head1 NAME
NGCP::Panel::Utils::Preferences
=head1 DESCRIPTION
Various utils to outsource common tasks in the controllers
regarding voip_preferences.
=head1 METHODS
=head2 load_preference_list
Parameters:
c - set this to $c
pref_values - hashref with all values (from voip_x_preferences)
peer_pref - boolean, only select peer_prefs
dom_pref - boolean, only select dom_prefs
usr_pref - boolean, only select dom_prefs
Load preferences and groups. Fill them with pref_values.
Put them to stash as "pref_groups". This will be used in F<helpers/pref_table.tt>.
Also see "Special case rewrite_rule_set" and "Special case ncos and adm_ncos".
=head2 create_preference_form
Parameters:
c - set this to $c
pref_rs - a resultset for voip_x_preferences with the specific "x" already set
enums - arrayref of all relevant enum rows (already filtered by eg. dom_pref)
base_uri - string, uri of the preferences list
edit_uri - string, uri to show the preferences edit modal
Use preference and preference_meta from stash and create a form. Process that
form in case the request has be POSTed. Also parse the GET params "delete",
"activate" and "deactivate" in order to operate on maxoccur != 1 preferences.
Put the form to stash as "form".
=head3 Special case rewrite_rule_set
In order to display the preference rewrite_rule_set correctly, the calling
controller must put rwr_sets_rs (as DBIx::Class::ResultSet) and rwr_sets
(for rendering in the template) to stash. A html select will then be displayed
with all the rewrite_rule_sets. Also helper.rewrite_rule_sets needs to be
set in the template (to be used by F<helpers/pref_table.tt>).
On update 4 voip_*_preferences will be created with the attributes
rewrite_callee_in_dpid, rewrite_caller_in_dpid, rewrite_callee_out_dpid,
rewrite_caller_out_dpid, rewrite_callee_lnp_dpid, rewrite_caller_lnp_dpid
(using the helper method set_rewrite_preferences).
For compatibility with ossbss and the www_admin panel, no preference with
the attribute rewrite_rule_set is created and caller_in_dpid is used to
check which rewrite_rule_set is currently set.
=head3 Special case ncos and adm_ncos
Very similar to rewrite_rule_set (see above). The stashed variables are
ncos_levels_rs and ncos_levels. In the template helper.ncos_levels needs to
be set.
The updated preferences are called ncos_id and adm_ncos_id.
=head3 Special case emergency_mapping_container
Very similar to ncos (see above). The stashed variables are
emergency_mapping_containers_rs and emergency_mapping_containers. In the template
helper.ncos_levels needs to be set.
The updated preferences are called ncos_id and adm_ncos_id.
=head3 Special case sound_set and contract_sound_set
This is also similar to rewrite_rule_set and ncos. The stashed variables are
(contract_)sound_sets_rs and (contract_)sound_sets. In the template helper.(contract_)sound_sets needs to
be set.
The preference with the attribute (contract_)sound_set will contain the id of a sound set.
=head3 Special case allowed_ips
Also something special here. The table containing data is
provisioning.voip_allowed_ip_groups.
=head2 set_rewrite_preferences
See "Special case rewrite_rule_set".
=head1 AUTHOR
Andreas Granig,
Gerhard Jungwirth
=head1 LICENSE
This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# vim: set tabstop=4 expandtab: