TT#132650 /api/provisioning_templates CRUD rail

the /api/provisionintemplates rail provides the
operations to create, edit and delete "provisioning
templates" know from the "batch provisioning" feature
of admin panel.

these templates can also be defined in config.yml,
while it is however only possible to edit templates
stored in the database.

executing a template and/or uploading a .csv for bulk
execution will be available in a separate part.

Change-Id: If8627327270edfce5bca1be3b1f777c1bd44e90f
mr10.1
Rene Krenn 4 years ago
parent 51f548514a
commit b6e696621b

@ -0,0 +1,71 @@
package NGCP::Panel::Controller::API::ProvisioningTemplates;
use NGCP::Panel::Utils::Generic qw(:all);
use Sipwise::Base;
use boolean qw(true);
use Data::HAL qw();
use Data::HAL::Link qw();
use HTTP::Headers qw();
use HTTP::Status qw(:constants);
use NGCP::Panel::Utils::ProvisioningTemplates qw();
use NGCP::Panel::Utils::DateTime qw();
sub allowed_methods{
return [qw/GET POST OPTIONS HEAD/];
}
sub api_description {
return 'Manage "provisioning templates" for creating subscribers with batch provisioning.';
};
sub query_params {
return [
{
param => 'editable',
description => 'Filter for editable provisioning templates',
},
];
}
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::ProvisioningTemplates/;
sub resource_name{
return 'provisioningtemplates';
}
sub dispatch_path{
return '/api/provisioningtemplates/';
}
sub relation{
return 'http://purl.org/sipwise/ngcp-api/#rel-provisioningtemplates';
}
__PACKAGE__->set_config({
allowed_roles => [qw/admin reseller ccareadmin ccare/],
});
sub create_item {
my ($self, $c, $resource, $form, $process_extras) = @_;
$resource->{yaml} = NGCP::Panel::Utils::ProvisioningTemplates::dump_template($c,
$resource->{id},
$resource->{name},
delete $resource->{template},
);
$resource->{id} = undef;
$resource->{create_timestamp} = $resource->{modify_timestamp} = NGCP::Panel::Utils::DateTime::current_local;
my $item = $c->model('DB')->resultset('provisioning_templates')->create(
$resource
);
return $item;
}
1;

@ -0,0 +1,289 @@
package NGCP::Panel::Controller::API::ProvisioningTemplatesItem;
use NGCP::Panel::Utils::Generic qw(:all);
use Sipwise::Base;
use HTTP::Headers qw();
use HTTP::Status qw(:constants);
use NGCP::Panel::Utils::ValidateJSON qw();
require Catalyst::ActionRole::ACL;
require NGCP::Panel::Role::HTTPMethods;
require Catalyst::ActionRole::RequireSSL;
use Scalar::Util qw/blessed/;
sub allowed_methods{
return [qw/GET OPTIONS HEAD PATCH PUT DELETE/];
}
use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::ProvisioningTemplates/;
sub resource_name{
return 'provisioningtemplates';
}
sub dispatch_path{
return '/api/provisioningtemplates/';
}
sub relation{
return 'http://purl.org/sipwise/ngcp-api/#rel-provisioningtemplates';
}
sub journal_query_params {
my($self,$query_params) = @_;
return $self->get_journal_query_params($query_params);
}
sub get_journal_methods{
return [qw/handle_item_base_journal handle_journals_get handle_journalsitem_get handle_journals_options handle_journalsitem_options handle_journals_head handle_journalsitem_head/];
}
__PACKAGE__->set_config({
action_add => {
item_base => {
Chained => '/',
PathPart => 'api/' . __PACKAGE__->resource_name,
CaptureArgs => 1,
},
item_get => {
Chained => 'item_base',
PathPart => '',
Args => 0,
Method => 'GET',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_options => {
Chained => 'item_base',
PathPart => '',
Args => 0,
Method => 'OPTIONS',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_head => {
Chained => 'item_base',
PathPart => '',
Args => 0,
Method => 'HEAD',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_put => {
Chained => 'item_base',
PathPart => '',
Args => 0,
Method => 'PUT',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_patch => {
Chained => 'item_base',
PathPart => '',
Args => 0,
Method => 'PATCH',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_delete => {
Chained => 'item_base',
PathPart => '',
Args => 0,
Method => 'DELETE',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_get_reseller => {
Chained => 'item_base',
PathPart => '',
Args => 1,
Method => 'GET',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_options_reseller => {
Chained => 'item_base',
PathPart => '',
Args => 1,
Method => 'OPTIONS',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_head_reseller => {
Chained => 'item_base',
PathPart => '',
Args => 1,
Method => 'HEAD',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_put_reseller => {
Chained => 'item_base',
PathPart => '',
Args => 1,
Method => 'PUT',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_patch_reseller => {
Chained => 'item_base',
PathPart => '',
Args => 1,
Method => 'PATCH',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
item_delete_reseller => {
Chained => 'item_base',
PathPart => '',
Args => 1,
Method => 'DELETE',
ACLDetachTo => '/api/root/invalid_user',
AllowedRole => [qw/admin reseller ccareadmin ccare/],
Does => [qw(ACL RequireSSL)]
},
}
});
sub item_base {
my ($self,$c,$reseller) = @_;
$c->stash->{id} = $reseller;
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return;
}
sub item_get {
my ($self,$c) = @_;
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->get($c,$c->stash->{id});
}
sub item_get_reseller {
my ($self,$c,$name) = @_;
$c->stash->{id} = $self->get_id($c->stash->{id},$name);
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->get($c,$c->stash->{id});
}
sub item_options {
my ($self,$c) = @_;
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->options($c,$c->stash->{id});
}
sub item_options_reseller {
my ($self,$c,$name) = @_;
$c->stash->{id} = $self->get_id($c->stash->{id},$name);
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->options($c,$c->stash->{id});
}
sub item_head {
my ($self,$c) = @_;
$c->forward('item_get');
$c->response->body(q());
return;
}
sub item_head_reseller {
my ($self,$c,$name) = @_;
$c->forward('item_get_reseller');
$c->response->body(q());
return;
}
sub item_put {
my ($self,$c) = @_;
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->put($c,$c->stash->{id});
}
sub item_put_reseller {
my ($self,$c,$name) = @_;
$c->stash->{id} = $self->get_id($c->stash->{id},$name);
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->put($c,$c->stash->{id});
}
sub item_patch {
my ($self,$c) = @_;
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->patch($c,$c->stash->{id});
}
sub item_patch_reseller {
my ($self,$c,$name) = @_;
$c->stash->{id} = $self->get_id($c->stash->{id},$name);
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->patch($c,$c->stash->{id});
}
sub item_delete {
my ($self,$c) = @_;
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->delete($c,$c->stash->{id});
}
sub item_delete_reseller {
my ($self,$c,$name) = @_;
$c->stash->{id} = $self->get_id($c->stash->{id},$name);
#$c->log->debug((caller(0))[3] . ": " . $c->stash->{id});
return $self->delete($c,$c->stash->{id});
}
sub update_item_model {
my($self, $c, $item, $old_resource, $resource, $form, $process_extras) = @_;
$resource->{yaml} = NGCP::Panel::Utils::ProvisioningTemplates::dump_template($c,
$resource->{id},
$resource->{name},
delete $resource->{template},
);
$resource->{id} = $item->id;
$resource->{modify_timestamp} = NGCP::Panel::Utils::DateTime::current_local;
$item->update($resource);
return $item;
}
sub delete_item {
my($self, $c, $item) = @_;
if ($item
and not blessed($item)) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Provisioning template cannot be deleted");
return;
}
$item->delete();
return 1;
}
1;

@ -0,0 +1,15 @@
package NGCP::Panel::Form::ProvisioningTemplate::AdminAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::ProvisioningTemplate::ResellerAPI';
has_field 'reseller' => (
type => '+NGCP::Panel::Field::Reseller',
required => 1,
element_attr => {
rel => ['tooltip'],
title => ['The reseller id this template belongs to.']
},
);
1;

@ -4,6 +4,8 @@ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
use HTML::FormHandler::Widget::Block::Bootstrap;
use NGCP::Panel::Utils::ProvisioningTemplates qw();
use NGCP::Panel::Utils::Generic qw(trim);
use Storable qw();
@ -134,15 +136,11 @@ sub validate_yaml {
my ($self, $field) = @_;
eval {
my $data = YAML::XS::Load($field->value);
die('not a hash') unless 'HASH' eq ref $data;
foreach my $section (qw/contract subscriber/) {
die("section '$section' required") unless exists $data->{$section};
die("section '$section' is not a hash") unless 'HASH' eq ref $data->{$section};
}
my $data = NGCP::Panel::Utils::ProvisioningTemplates::parse_template(undef, undef, undef, $field->value);
NGCP::Panel::Utils::ProvisioningTemplates::validate_template($data);
};
if ($@) {
$field->add_error($@);
$field->add_error(trim($@));
}
}
@ -164,13 +162,12 @@ sub validate {
my $reseller;
$reseller = $c->model('DB')->resultset('resellers')->find($resource->{reseller_id}) if $resource->{reseller_id};
my $template = $field->value;
$template = ($reseller->name . '/' . $template) if $reseller;
#$c->log->warn("test: ".$template);
if (not defined $c->stash->{old_name}
or $c->stash->{old_name} ne $template) {
$field->add_error("a provisioning template with name '" . $field->value . "' already exists")
if exists $c->stash->{provisioning_templates}->{$template};
eval {
NGCP::Panel::Utils::ProvisioningTemplates::validate_template_name($c,
$field->value,$c->stash->{old_name},$reseller);
};
if ($@) {
$field->add_error(trim($@));
}
}

@ -0,0 +1,75 @@
package NGCP::Panel::Form::ProvisioningTemplate::ResellerAPI;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
use Storable qw();
has_field 'id' => (
type => 'Hidden'
);
has_field 'name' => (
type => 'Text',
required => 1,
maxlength => 255,
element_attr => {
rel => ['tooltip'],
title => ['A unique template name.']
},
);
has_field 'description' => (
type => 'Text',
label => 'Description',
required => 1,
maxlength => 255,
element_attr => {
rel => ['tooltip'],
title => ['Arbitrary text.'],
},
);
has_field 'lang' => (
type => 'Select',
label => 'Calculated fields',
options => [
{ value => 'js', label => 'JavaScript' },
{ value => 'perl', label => 'Perl' },
],
element_attr => {
rel => ['tooltip'],
title => ['Which scripting language used in the template.']
},
);
has_field 'template' => (
type => 'Compound',
required => 1,
label => 'Template',
element_attr => {
rel => ['tooltip'],
title => ['The template definition.'],
},
);
has_field 'create_timestamp' => (
type => '+NGCP::Panel::Field::DateTime',
required => 0,
readonly => 1,
element_attr => {
rel => ['tooltip'],
title => ['The datetime (YYYY-MM-DD HH:mm:ss) of the creation.']
},
);
has_field 'modify_timestamp' => (
type => '+NGCP::Panel::Field::DateTime',
required => 0,
readonly => 1,
element_attr => {
rel => ['tooltip'],
title => ['The datetime (YYYY-MM-DD HH:mm:ss) of the modification.']
},
);
1;

@ -6,6 +6,7 @@ use parent qw/NGCP::Panel::Role::Journal/;
use NGCP::Panel::Utils::Generic qw(:all);
use boolean qw(true);
use URI::Escape qw(uri_escape);
use Safe::Isa qw($_isa $_can);
use Storable qw();
use JSON qw();
@ -1244,7 +1245,7 @@ sub hal_from_item {
href => $self->apply_mandatory_parameters($c, 'item', sprintf(
"%s%s",
$self->dispatch_path,
$self->get_item_id($c, $item)
uri_escape($self->get_item_id($c, $item))
), $item, $resource, $params),
),
Data::HAL::Link->new(
@ -1252,11 +1253,11 @@ sub hal_from_item {
href => $self->apply_mandatory_parameters($c, 'item', sprintf(
"/api/%s/%s",
$self->resource_name,
$self->get_item_id($c, $item)
uri_escape($self->get_item_id($c, $item))
), $item, $resource, $params)
),
@$links,
$self->get_journal_relation_link($c, $self->get_item_id($c, $item)),
$self->get_journal_relation_link($c, uri_escape($self->get_item_id($c, $item))),
],
relation => 'ngcp:'.$self->resource_name,
);

@ -0,0 +1,253 @@
package NGCP::Panel::Role::API::ProvisioningTemplates;
use NGCP::Panel::Utils::Generic qw(:all);
use Sipwise::Base;
use parent 'NGCP::Panel::Role::API';
use boolean qw(true);
use Data::HAL qw();
use Data::HAL::Link qw();
use HTTP::Status qw(:constants);
use Scalar::Util qw/blessed/;
use JSON qw();
use NGCP::Panel::Utils::ProvisioningTemplates qw();
use NGCP::Panel::Utils::API qw();
use NGCP::Panel::Utils::Generic qw(trim);
sub _item_rs {
my ($self, $c) = @_;
unless ($c->stash->{provisioning_templates}) {
NGCP::Panel::Utils::ProvisioningTemplates::load_template_map($c);
}
my $editable;
if (length($c->req->param('editable'))) {
if ('1' eq $c->req->param('editable')
or 'true' eq lc($c->req->param('editable'))) {
$editable = 1;
} elsif ('0' eq $c->req->param('editable')
or 'false' eq lc($c->req->param('editable'))) {
$editable = 0;
}
}
my @result = ();
foreach my $id (keys %{$c->stash->{provisioning_templates}}) {
my $template = $c->stash->{provisioning_templates}->{$id};
my $include = 1;
if (defined $editable) {
if ($editable) {
$include &= ($template->{static} ? 0 : 1);
} else {
$include &= ($template->{static} ? 1 : 0);
}
}
push(@result,$self->item_by_id($c,$id)) if $include;
}
return \@result;
}
sub get_id {
my ($self,$reseller_name,$name) = @_;
my $id = '';
$id .= ($reseller_name . '/') if length($reseller_name);
$id .= $name;
return $id;
}
sub get_item_id {
my($self, $c, $item, $resource, $form, $params) = @_;
return unless defined $item;
if (blessed($item)) {
return $self->get_id(($item->reseller ? $item->reseller->name : undef), $item->name);
} else {
return unless scalar keys %$item;
my $reseller_name;
if (exists $item->{reseller}) {
$reseller_name = $item->{reseller};
} else {
my $reseller;
$reseller = $c->model('DB')->resultset('resellers')->find(
$item->{reseller_id}) if $item->{reseller_id};
$reseller_name = $reseller->name if $reseller;
}
return $self->get_id($reseller_name, $item->{name});
}
}
sub valid_id {
my ($self, $c, $id) = @_;
return 1 if length($id);
$self->error($c, HTTP_BAD_REQUEST, "Invalid id in request URI");
return;
}
sub get_form {
my ($self, $c) = @_;
if ($c->user->is_superuser) {
return NGCP::Panel::Form::get("NGCP::Panel::Form::ProvisioningTemplate::AdminAPI", $c);
} else {
return NGCP::Panel::Form::get("NGCP::Panel::Form::ProvisioningTemplate::ResellerAPI", $c);
}
}
sub resource_from_item {
my ($self, $c, $item) = @_;
my %resource;
if (blessed($item)) {
%resource = $item->get_inflated_columns;
if ($c->req->param('format')) {
if (grep { $_ eq lc($c->req->param('format')); } qw(yml yaml)) {
$resource{template} = delete $resource{yaml};
} elsif ('json' eq lc($c->req->param('format'))) {
eval {
$resource{template} = _template_as_json(NGCP::Panel::Utils::ProvisioningTemplates::parse_template($c, $resource{id}, $resource{name}, delete $resource{yaml}));
};
}
} else {
eval {
$resource{template} = NGCP::Panel::Utils::ProvisioningTemplates::parse_template($c, $resource{id}, $resource{name}, delete $resource{yaml});
};
}
} else {
%resource = ();
$resource{name} = $item->{name};
$resource{description} = $item->{description};
$resource{lang} = $item->{lang};
$resource{id} = $self->get_item_id($c,$item);
$resource{reseller_id} = undef;
#delete $resource{reseller};
$resource{template} = $item;
delete @{$item}{qw(id reseller static)};
if ($c->req->param('format')) {
if (grep { $_ eq lc($c->req->param('format')); } qw(yml yaml)) {
eval {
$resource{template} = NGCP::Panel::Utils::ProvisioningTemplates::dump_template($c, $resource{id}, $resource{name}, $resource{template});
};
} elsif ('json' eq lc($c->req->param('format'))) {
$resource{template} = _template_as_json($resource{template});
}
}
}
return \%resource;
}
sub _template_as_json {
my $template = shift;
return JSON::to_json($template, {
allow_nonref => 1, allow_blessed => 1,
canonical => 1, utf8 => 1,
convert_blessed => 1, pretty => 1 });
}
sub _template_from_json {
my $template = shift;
return JSON::from_json($template, { utf8 => 1 });
}
sub item_by_id {
my ($self, $c, $id) = @_;
return unless length($id);
unless ($c->stash->{provisioning_templates}) {
NGCP::Panel::Utils::ProvisioningTemplates::load_template_map($c);
}
my $item = $c->stash->{provisioning_templates}->{$id};
if ($item and $item->{id}) {
$item = $c->model('DB')->resultset('provisioning_templates')->find($item->{id});
}
return $item;
}
sub check_resource {
my($self, $c, $item, $old_resource, $resource, $form) = @_;
if ($item
and not blessed($item)) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Provisioning template cannot be updated");
return;
}
NGCP::Panel::Utils::API::apply_resource_reseller_id($c,$resource);
return unless NGCP::Panel::Utils::API::check_resource_reseller_id($self,$c,$resource,$old_resource);
eval {
my $reseller;
$reseller = $c->model('DB')->resultset('resellers')->find(
$resource->{reseller_id}) if $resource->{reseller_id};
NGCP::Panel::Utils::ProvisioningTemplates::validate_template_name($c,
$resource->{name},($old_resource ? $old_resource->{name} : undef),
$reseller);
};
if ($@) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY,trim($@));
return;
}
eval {
if ($c->req->param('format')) {
if (grep { $_ eq lc($c->req->param('format')); } qw(yml yaml)) {
$resource->{template} = NGCP::Panel::Utils::ProvisioningTemplates::parse_template($c, $resource->{id}, $resource->{name}, $resource->{template});
} elsif ('json' eq lc($c->req->param('format'))) {
$resource->{template} = _template_from_json($resource->{template});
}
}
NGCP::Panel::Utils::ProvisioningTemplates::validate_template($resource->{template});
};
if ($@) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY,trim($@));
return;
}
return 1;
}
sub process_form_resource {
my($self, $c, $item, $old_resource, $resource, $form) = @_;
NGCP::Panel::Utils::API::apply_resource_reseller_id($c,$resource);
return $resource;
}
sub get_journal_item_hal {
my ($self, $c, $item, $params) = @_;
my ($hal,$id) = $self->SUPER::get_journal_item_hal($c, $item, $params);
$hal->{id} = $item->id if $hal;
return ($hal,($hal ? $hal->{id} : undef));
}
1;

@ -255,7 +255,7 @@ sub post {
resource_media_type => $method_config->{ResourceContentType},
);
last unless $resource;
my ($item,$data_processed_result,$hal);
my ($item,$data_processed_result,$hal,$id);
if (!$non_json_data || !$data) {
delete $resource->{purge_existing};
last unless $self->pre_process_form_resource($c, undef, undef, $resource, $form, $process_extras);
@ -272,8 +272,9 @@ sub post {
$item = $self->create_item($c, $resource, $form, $process_extras);
last unless $item || $self->get_config('no_item_created');
$hal = $self->get_journal_item_hal($c, $item, { form => $form });
last unless $self->add_journal_item_hal($c, { hal => $hal });
($hal, $id) = $self->get_journal_item_hal($c, $item, { form => $form });
last unless $self->add_journal_item_hal($c, { hal => $hal, ($id ? ( id => $id, ) : ()) });
} else {
try {
#$processed_ok(array), $processed_failed(array), $info, $error

@ -279,8 +279,10 @@ sub patch {
($item, $form, $process_extras) = $self->update_item($c, $item, $old_resource, $resource, $form, $process_extras );
last unless $item;
my $hal = $self->get_journal_item_hal($c, $item, { form => $form });
last unless $self->add_journal_item_hal($c, { hal => $hal });
my $hal;
($hal,$id) = $self->get_journal_item_hal($c, $item, { form => $form });
$c->log->debug("halid: $hal->{id}");
last unless $self->add_journal_item_hal($c, { hal => $hal, ($id ? ( id => $id, ) : ()) });
$self->complete_transaction($c);
$self->post_process_commit($c, 'patch', $item, $old_resource, $resource, $form, $process_extras);
@ -345,9 +347,10 @@ sub put {
};
}
my $hal = $self->get_journal_item_hal($c, $item, { form => $form });
last unless $self->add_journal_item_hal($c, { hal => $hal });
my $hal;
($hal,$id) = $self->get_journal_item_hal($c, $item, { form => $form });
last unless $self->add_journal_item_hal($c, { hal => $hal, ($id ? ( id => $id, ) : ()) });
$self->complete_transaction($c);
$self->post_process_commit($c, 'put', $item, $old_resource, $resource, $form, $process_extras);
$self->return_representation($c,
@ -370,10 +373,11 @@ sub delete { ## no critic (ProhibitBuiltinHomonyms)
my $item = $self->item_by_id_valid($c, $id);
last unless $item;
my $hal = $self->get_journal_item_hal($c, $item);
my $hal;
($hal,$id) = $self->get_journal_item_hal($c, $item);
#here we left space for information that checking failed and we decided not to delete item
if ($self->delete_item($c, $item)) {
$self->add_journal_item_hal($c, { hal => $hal });
$self->add_journal_item_hal($c, { hal => $hal, ($id ? ( id => $id, ) : ()) });
} else {
return;
}

@ -54,7 +54,7 @@ sub get_journal_item_hal {
if ($cfg->{operation_enabled}) {
$item->discard_changes;
#we may pass resource inparams to don't perform expensive get_resource_from_item operation
return $self->hal_from_item($c, $item, $form, $params);
return ($self->hal_from_item($c, $item, $form, $params),undef);
}
return;
}
@ -70,7 +70,7 @@ sub add_journal_item_hal {
#we may pass resource inparams to don't perform expensive get_resource_from_item operation
$hal = $self->hal_from_item($c, $item, $form, $params);
}
return NGCP::Panel::Utils::Journal::add_journal_item_hal($self, $c, $operation, $hal);
return NGCP::Panel::Utils::Journal::add_journal_item_hal($self, $c, $operation, $params);
} else {
return 1;
}

@ -14,16 +14,15 @@ my $collections_files_cache;
sub check_resource_reseller_id {
my($api, $c, $resource, $old_resource) = @_;
my $reseller;
if( $resource->{reseller_id}
&& (( ! $old_resource ) || $old_resource->{reseller_id} != $resource->{reseller_id} )) {
$reseller = $c->model('DB')->resultset('resellers')->find($resource->{reseller_id});
my $reseller = $c->model('DB')->resultset('resellers')->find($resource->{reseller_id});
unless( $reseller ) {
$api->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid 'reseller_id'");
return;
}
}
return $reseller;
return 1;
}
sub apply_resource_reseller_id {

@ -7,9 +7,9 @@ use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = 1.00;
@ISA = qw(Exporter);
@EXPORT = ();
@EXPORT_OK = qw(is_int is_integer is_decimal merge compare is_false is_true get_inflated_columns_all hash2obj mime_type_to_extension extension_to_mime_type array_to_map escape_js);
%EXPORT_TAGS = ( DEFAULT => [qw(&is_int &is_integer &is_decimal &merge &compare &is_false &is_true &mime_type_to_extension &extension_to_mime_type &array_to_map &escape_js)],
all => [qw(&is_int &is_integer &is_decimal &merge &compare &is_false &is_true &get_inflated_columns_all &hash2obj &mime_type_to_extension &extension_to_mime_type &array_to_map &escape_js)]);
@EXPORT_OK = qw(is_int is_integer is_decimal merge compare is_false is_true get_inflated_columns_all hash2obj mime_type_to_extension extension_to_mime_type array_to_map escape_js trim);
%EXPORT_TAGS = ( DEFAULT => [qw(&is_int &is_integer &is_decimal &merge &compare &is_false &is_true &mime_type_to_extension &extension_to_mime_type &array_to_map &escape_js &trim)],
all => [qw(&is_int &is_integer &is_decimal &merge &compare &is_false &is_true &get_inflated_columns_all &hash2obj &mime_type_to_extension &extension_to_mime_type &array_to_map &escape_js &trim)]);
use Hash::Merge;
use Data::Compare qw//;
@ -222,4 +222,10 @@ sub escape_js {
return $str;
}
sub trim {
my $value = shift;
$value =~ s/^\s+|\s+$//g;
return $value;
}
1;

@ -110,13 +110,13 @@ sub load_template_map {
foreach my $db_template ($rs->all) {
my $template = { $db_template->get_inflated_columns };
eval {
%$template = ( %{YAML::XS::Load($template->{yaml})}, %$template );
%$template = ( %{parse_template($c, $template->{id}, $template->{name}, $template->{yaml})}, %$template );
#use Data::Dumper;
#$c->log->error(Dumper($template));
delete $template->{yaml};
};
if ($@) {
$c->log->error("error parsing provisioning_template id $template->{id} '$template->{name}': " . $@);
die $@;
next;
}
$template->{static} = 0;
@ -131,6 +131,68 @@ sub load_template_map {
}
sub validate_template {
my ($data,$prefix) = @_;
$prefix //= 'template: ';
die($prefix . "not a hash\n") unless 'HASH' eq ref $data;
foreach my $section (qw/contract subscriber/) {
die($prefix . "section '$section' required\n") unless exists $data->{$section};
die($prefix . "section '$section' is not a hash\n") unless 'HASH' eq ref $data->{$section};
}
}
sub validate_template_name {
my ($c,$name,$old_name,$reseller,$old_reseller) = @_;
unless ($name =~ /^[a-zA-Z0-9 -]+$/) {
die("template name contains invalid characters\n");
}
#$c->log->warn("test: ".$template);
if (not defined $old_name
or $old_name ne $name) {
unless ($c->stash->{provisioning_templates}) {
load_template_map($c);
}
die("a provisioning template with name '" . $name . "' already exists\n")
if exists $c->stash->{provisioning_templates}->{$reseller ? ($reseller->name . '/' . $name) : $name};
}
}
sub dump_template {
my ($c,$id,$name,$template) = @_;
my $yaml;
eval {
$yaml = YAML::XS::Dump($template);
};
if ($@) {
$c->log->error("error parsing provisioning_template id $id '$name': " . $@) if $c;
die($@);
}
return $yaml;
}
sub parse_template {
my ($c,$id,$name,$yaml) = @_;
my $template;
#die ("yaml: " . $yaml);
eval {
$template = YAML::XS::Load($yaml);
};
if ($@) {
$c->log->error("error parsing provisioning_template id $id '$name': " . $@) if $c;
die($@);
}
return $template;
}
sub create_provisioning_template_form {
my %params = @_;
@ -925,7 +987,7 @@ sub _init_contract_preferences_context {
sub _init_registrations_context {
my ($c, $context, $schema, $template) = @_;
foreach my $template_registration (@{_force_array($template->{registrations})}) {
my %registration = ();
foreach my $col (keys %$template_registration) {

@ -140,6 +140,7 @@ $ua = Test::Collection->new()->ua();
profilepackages => 1,
profilepreferencedefs => 1,
profilepreferences => 1,
provisioningtemplates => 1,
reminders => 1,
resellers => 1,
resellerbrandinglogos => 1,

Loading…
Cancel
Save