From 010baf51977176816911d091df02c21fa5e9ff97 Mon Sep 17 00:00:00 2001 From: Rene Krenn Date: Fri, 14 Aug 2020 16:48:06 +0200 Subject: [PATCH] TT#89200 workaround logic for backward-incompatible prefs 7.5 unfortunately, preference types were changed over time, eg. some boolean prefs were turned into enum prefs. this requires an api client to adopt accordinngly. if this is not an option, this change allows to add simple workarounds in the rest-api directly, by registration of transformation functions for specific preferences. (cherry picked from commit c9bb86aba65e6276ad271410b497d23b43e32b2f) Change-Id: I60e87ae4049d61d14bf688d3f5815a9dfb9717e3 --- lib/NGCP/Panel/Role/API/Preferences.pm | 35 ++++++++++- lib/NGCP/Panel/Utils/Preferences.pm | 87 +++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/lib/NGCP/Panel/Role/API/Preferences.pm b/lib/NGCP/Panel/Role/API/Preferences.pm index 9145d4ce0f..fa613e1ae9 100644 --- a/lib/NGCP/Panel/Role/API/Preferences.pm +++ b/lib/NGCP/Panel/Role/API/Preferences.pm @@ -274,6 +274,13 @@ sub get_resource { # default $value = $pref->value; } # SWITCH + eval { + $value = NGCP::Panel::Utils::Preferences::api_transform_out($c, $pref->attribute, $pref->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}); @@ -754,7 +761,7 @@ sub update_item { } } - if($meta->data_type eq "boolean" && JSON::is_bool($resource->{$pref})) { + if (($meta->data_type eq "boolean" or NGCP::Panel::Utils::Preferences::exists_api_transform_in($c, $pref)) and JSON::is_bool($resource->{$pref})) { $vtype = ""; } if($meta->max_occur == 1 && $vtype ne "") { @@ -935,6 +942,14 @@ sub update_item { $pref_rs->delete; foreach my $v(@{ $resource->{$pref} }) { return unless $self->check_pref_value($c, $meta, $v, $pref_type); + eval { + $v = NGCP::Panel::Utils::Preferences::api_transform_in($c, $meta, $v); + }; + if ($@) { + $c->log->error("Failed to transform pref value - $@"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Internal Server Error."); # TODO? + return; + } if(JSON::is_bool($v)){ $v = $v ? 1 : 0 ; } @@ -942,12 +957,28 @@ sub update_item { } } elsif($pref_rs->first) { return unless $self->check_pref_value($c, $meta, $resource->{$pref}, $pref_type); + eval { + $resource->{$pref} = NGCP::Panel::Utils::Preferences::api_transform_in($c, $meta, $resource->{$pref}); + }; + if ($@) { + $c->log->error("Failed to transform pref value - $@"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "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 $self->check_pref_value($c, $meta, $resource->{$pref}, $pref_type); + eval { + $resource->{$pref} = NGCP::Panel::Utils::Preferences::api_transform_in($c, $meta, $resource->{$pref}); + }; + if ($@) { + $c->log->error("Failed to transform pref value - $@"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Internal Server Error."); # TODO? + return; + } if(JSON::is_bool($resource->{$pref})){ $resource->{$pref} = $resource->{$pref} ? 1 : 0 ; } @@ -992,6 +1023,8 @@ sub check_pref_value { my ($self, $c, $meta, $value, $pref_type) = @_; my $err; + return 1 if NGCP::Panel::Utils::Preferences::exists_api_transform_in($c,$meta->attribute); + my $vtype = ref $value; if($meta->data_type eq "boolean" && JSON::is_bool($value)) { $vtype = ""; diff --git a/lib/NGCP/Panel/Utils/Preferences.pm b/lib/NGCP/Panel/Utils/Preferences.pm index 71fcbb43c9..6a48f405dc 100644 --- a/lib/NGCP/Panel/Utils/Preferences.pm +++ b/lib/NGCP/Panel/Utils/Preferences.pm @@ -10,6 +10,10 @@ use NGCP::Panel::Utils::Sems; use constant _DYNAMIC_PREFERENCE_PREFIX => '__'; +my $API_TRANSFORM_OUT; +my $API_TRANSFORM_IN; +my $CODE_SUFFIX_FNAME = '_code'; + sub validate_ipnet { my ($field) = @_; if ( !$field->value ) { @@ -36,6 +40,87 @@ sub validate_ipnet { return 1; } +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 and exists $API_TRANSFORM_OUT->{$meta->attribute}->{$value}) { + $value = $API_TRANSFORM_OUT->{$meta->attribute}->{$value}; + if ('CODE' eq ref $value) { + eval { + $value = $value->($meta,$value); + }; + if ($@) { + die($meta->attribute . ": " . $@); + } + } + } + } + } + return $value; +} + sub load_preference_list { my %params = @_; @@ -1431,7 +1516,7 @@ sub get_provisoning_voip_subscriber_first_int_attr_value { } } -sub api_preferences_defs{ +sub api_preferences_defs { my %params = @_; my $c = $params{c};