TT#149459 improve and automate expand functionality

* add dictionary support for fields that are expanded
  if encountered in all endpoints, with a possibility
  to override it, if defined on the endpoint's field
  level
* move expand definitions from form fields into the
  Expand dictionary
* simplify the expand usage, it now operates only with the
  <x>_id fields that are returned and visible in the response
  (e.g. if reseller_id is returned, then ?expand=reseller_id),
  the returned expand object name is <expand_field_name>_expand
  the, so in case of ?expand=reseller_id, the returned object
  will be reseller_id_expand
* adapt Role/SystemContacts to work correctly with the expand
  functionality
* expanded fields are returned as <expanded_field_name>_expand

Change-Id: I4cab44ede9b40c70a95bbcedc81f58dd1f4e3b67
mr10.2
Kirill Solomko 4 years ago
parent 95e04a0db6
commit 8c556bbe36

@ -8,13 +8,8 @@ has_field 'reseller' => (
type => '+NGCP::Panel::Field::Reseller',
label => 'Reseller',
validate_when_empty => 1,
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Resellers',
id_field => 'reseller_id',
},
},
);
has_block 'fields' => (
tag => 'div',
class => [qw(modal-body)],

@ -9,10 +9,6 @@ has_field 'reseller' => (
element_attr => {
rel => ['tooltip'],
title => ['The reseller id this contact belongs to.'],
expand => {
class => 'NGCP::Panel::Role::API::Resellers',
id_field => 'reseller_id',
},
},
);

@ -9,11 +9,6 @@ has_field 'contact_id' => (
element_attr => {
rel => ['tooltip'],
title => ['The contact id this contract belongs to.'],
expand => {
class => 'NGCP::Panel::Role::API::CustomerContacts',
id_field => 'contact_id',
alias => 'contact',
},
},
);
@ -23,11 +18,6 @@ has_field 'billing_profile_id' => (
element_attr => {
rel => ['tooltip'],
title => ['The billing profile id used to charge this contract, which will become active immediately. This field is required if the profile definition mode is not defined or the \'id\' mode is used.'],
expand => {
class => 'NGCP::Panel::Role::API::BillingProfiles',
id_field => 'billing_profile_id',
alias => 'billing_profile',
},
},
);

@ -3,10 +3,22 @@ package NGCP::Panel::Form::Contract::ContractAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Contract::BaseAPI';
has_field 'contact_id' => (
type => 'PosInteger',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The contact id this contract belongs to.'],
expand => {
class => 'NGCP::Panel::Role::API::SystemContacts',
},
},
);
has_field 'billing_profile_definition' => (
type => 'Select',
#required => 1,
options => [
options => [
{ value => 'id', label => 'single: by \'billing_profile_id\' field' },
{ value => 'profiles', label => 'schedule: by \'billing_profiles\' field' },
],
@ -29,4 +41,4 @@ has_field 'type' => (
},
);
1;
1;

@ -9,10 +9,6 @@ has_field 'reseller' => (
element_attr => {
rel => ['tooltip'],
title => ['The reseller id to assign this domain to.'],
expand => {
class => 'NGCP::Panel::Role::API::Resellers',
id_field => 'reseller_id',
},
},
);

@ -0,0 +1,74 @@
package NGCP::Panel::Form::Expand;
use HTML::FormHandler::Moose;
use HTML::FormHandler::Widget::Wrapper::None;
extends 'HTML::FormHandler';
has '+widget_wrapper' => ( default => 'None' );
sub build_render_list {[]}
has_field 'billing_profile_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::BillingProfiles',
},
},
);
has_field 'contact_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::CustomerContacts',
},
},
);
has_field 'contract_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Contracts',
},
},
);
has_field 'customer_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Customers',
},
},
);
has_field 'domain_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Domains',
},
},
);
has_field 'reseller_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Resellers',
},
},
);
has_field 'subscriber_id' => (
type => 'PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Subscribers',
remove_fields => [qw(password webpassword)],
},
},
);
1;

@ -17,10 +17,6 @@ has_field 'contract' => (
element_attr => {
rel => ['tooltip'],
title => ['The contract used for this reseller.'],
expand => {
class => 'NGCP::Panel::Role::API::Contracts',
id_field => 'contract_id',
},
},
);

@ -91,10 +91,6 @@ has_field 'domain' => (
title => ['The domain name this subscriber belongs to.'],
},
},
expand => {
class => 'NGCP::Panel::Role::API::Domains',
id_field => 'domain_id',
},
},
);

@ -62,14 +62,6 @@ has_block 'fields' => (
has_field 'subscriber_id' => (
type => '+NGCP::Panel::Field::PosInteger',
element_attr => {
expand => {
class => 'NGCP::Panel::Role::API::Subscribers',
alias => 'subscriber',
id_field => 'subscriber_id',
remove_fields => [qw(password webpassword)],
},
},
);
sub validate_slots_destination {

@ -13,12 +13,6 @@ has_field 'customer_id' => (
element_attr => {
rel => ['tooltip'],
title => ['The contract used for this subscriber.'],
expand => {
class => 'NGCP::Panel::Role::API::Customers',
alias => 'customer',
id_field => 'customer_id',
fetch => 0,
},
},
);

@ -1331,28 +1331,30 @@ sub expand_field {
$subfield = $2;
}
return unless $resource->{$field};
$found = 1;
my $expand_form = NGCP::Panel::Form::get("NGCP::Panel::Form::Expand", $c);
my ($attr, $expand);
my $f_field = $resource_form->field($field);
unless ($f_field) { # lookup by alias
foreach my $a_field ($resource_form->fields) {
my $expand = $a_field->element_attr->{expand} // next;
my $alias = $expand->{alias} // next;
if ($alias eq $field) {
$f_field = $a_field;
last;
}
}
if ($f_field) {
$attr = $f_field->element_attr;
$expand = $attr->{expand};
}
return unless $f_field;
$found = 1;
my $attr = $f_field->element_attr;
my $expand = $attr->{expand} // return;
my $alias = $expand->{alias} // $f_field->name;
my $class = $expand->{class} // return;
my $id_field = $expand->{id_field} // return;
my $fetch = $expand->{fetch} // 0;
my $id = $resource->{$id_field} // return;
my $form = $class->get_form($c) // return;
unless ($expand) { # use default field expand if specified
$f_field = $expand_form->field($field) // return;
$attr = $f_field->element_attr // return;
$expand = $attr->{expand} // return;
}
my $id = $resource->{$field};
my $to = $expand->{to} // $field . '_expand';
my $class = $expand->{class} // return;
my $form = $class->get_form($c) // return;
my $item = $class->item_by_id($c, $id) // return;
my $item_res = $class->resource_from_item($c, $item, $form);
my $data = $class->post_process_hal_resource($c, $item, $item_res, $form);
@ -1361,12 +1363,10 @@ sub expand_field {
delete @{$data}{@{$remove_fields}};
}
$resource->{$alias} = $fetch && $data->{$id_field}
? $data->{$id_field}
: $resource->{$alias};
$resource->{$to} = $data;
if ($subfield) {
$found = $self->expand_field($c, $resource->{$alias}, $form, $subfield);
$found = $self->expand_field($c, $resource->{$to}, $form, $subfield);
}
return defined $found;

@ -26,10 +26,33 @@ sub get_form {
return NGCP::Panel::Form::get("NGCP::Panel::Form::Contact::Reseller", $c);
}
sub resource_from_item {
my ($self, $c, $item, $form) = @_;
my %resource = $item->get_inflated_columns;
$resource{country}{id} = delete $resource{country};
$resource{timezone}{name} = delete $resource{timezone};
$form //= $self->get_form($c);
$self->validate_form(
c => $c,
resource => \%resource,
form => $form,
run => 0,
);
$resource{id} = int($item->id);
$resource{country} = $resource{country}{id};
$resource{timezone} = $resource{timezone}{name};
return \%resource;
}
sub hal_from_contact {
my ($self, $c, $contact, $form) = @_;
my %resource = $contact->get_inflated_columns;
my $resource = $self->resource_from_item($c, $contact, $form);
my $hal = Data::HAL->new(
links => [
@ -48,25 +71,8 @@ sub hal_from_contact {
relation => 'ngcp:'.$self->resource_name,
);
$resource{country}{id} = delete $resource{country};
$resource{timezone}{name} = delete $resource{timezone};
$form //= $self->get_form($c);
# TODO: i'd expect reseller to be removed automatically
delete $resource{reseller_id};
$self->validate_form(
c => $c,
resource => \%resource,
form => $form,
run => 0,
);
$resource{country} = $resource{country}{id};
$resource{timezone} = $resource{timezone}{name};
$resource{id} = int($contact->id);
$self->expand_fields($c, \%resource);
$hal->resource({%resource});
$self->expand_fields($c, $resource);
$hal->resource($resource);
return $hal;
}

Loading…
Cancel
Save