MT#8299 API: align PUT for pbxdevicemodels.

Use multipart/form-data as we do in POST.
gjungwirth/email_test
Andreas Granig 11 years ago
parent 6f50a2dac7
commit 996fd6000c

@ -15,13 +15,13 @@ require Catalyst::ActionRole::CheckTrailingSlash;
require Catalyst::ActionRole::HTTPMethods;
require Catalyst::ActionRole::RequireSSL;
# curl -v -X POST --user $USER --insecure -F front_image=@sandbox/spa504g-front.jpg -F mac_image=@sandbox/spa504g-back.jpg -F json='{"reseller_id":1, "vendor":"Cisco", "model":"SPA999", "linerange":[{"name": "Phone Keys", "num_lines":4, "can_private":true, "can_shared":true, "can_blf":true}]}' https://localhost:4443/api/pbxdevicemodels/
# curl -v -X POST --user $USER --insecure -F front_image=@sandbox/spa504g-front.jpg -F mac_image=@sandbox/spa504g-back.jpg -F json='{"reseller_id":1, "vendor":"Cisco", "model":"SPA999", "linerange":[{"name": "Phone Keys", "can_private":true, "can_shared":true, "can_blf":true, "keys":[{"labelpos":"top", "x":5110, "y":5120},{"labelpos":"top", "x":5310, "y":5320}]}]}' https://localhost:4443/api/pbxdevicemodels/
class_has 'api_description' => (
is => 'ro',
isa => 'Str',
default =>
'Specifies a model to be set in <a href="#pbxdeviceconfigs">PbxDeviceConfigs</a>.',
'Specifies a model to be set in <a href="#pbxdeviceconfigs">PbxDeviceConfigs</a>. Use a Content-Type "multipart/form-data", provide front_image and mac_image parts with the actual images, and an additional json part with the properties specified below, e.g.: <code>curl -X POST --user $USER -F front_image=@/path/to/front.png -F mac_image=@/path/to/mac.png -F json=\'{"reseller_id":...}\' https://example.org:1443/api/pbxdevicemodels/</code>',
);
class_has 'query_params' => (
@ -64,6 +64,38 @@ class_has 'query_params' => (
]},
);
class_has 'documentation_sample' => (
is => 'ro',
default => sub { {
vendor => "testvendor",
model => "testmodel",
reseller_id => 1,
sync_method => "GET",
sync_params => '[% server.uri %]/$MA',
sync_uri => 'http://[% client.ip %]/admin/resync',
linerange => [
{
name => "Phone Keys",
can_private => 1,
can_shared => 1,
can_blf => 1,
keys => [
{
x => 100,
y => 200,
labelpos => "left",
},
{
x => 100,
y => 300,
labelpos => "right",
},
],
},
],
} },
);
with 'NGCP::Panel::Role::API::PbxDeviceModels';

@ -101,7 +101,7 @@ sub PATCH :Allow {
my $item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, pbxdevicemodel => $item);
my $old_resource = { $item->get_inflated_columns };
my $old_resource = $self->resource_from_item($c, $item);
my $resource = $self->apply_patch($c, $old_resource, $json);
last unless $resource;
@ -137,13 +137,18 @@ sub PUT :Allow {
my $item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, pbxdevicemodel => $item);
my $resource = $self->get_valid_put_data(
c => $c,
id => $id,
media_type => 'application/json',
);
last unless $resource;
my $old_resource = { $item->get_inflated_columns };
last unless $self->forbid_link_header($c);
last unless $self->valid_media_type($c, 'multipart/form-data');
last unless $self->require_wellformed_json($c, 'application/json', $c->req->param('json'));
my $resource = JSON::from_json($c->req->param('json'));
$resource->{front_image} = $self->get_upload($c, 'front_image');
last unless $resource->{front_image};
# optional, don't set error
$resource->{mac_image} = $c->req->upload('mac_image');
my $old_resource = $self->resource_from_item($c, $item);
my $form = $self->get_form($c);
$item = $self->update_item($c, $item, $old_resource, $resource, $form);

@ -303,10 +303,11 @@ sub devmod_edit :Chained('devmod_base') :PathPart('edit') :Args(0) :Does(ACL) :A
}
$params->{reseller}{id} = delete $params->{reseller_id};
$params = $params->merge($c->session->{created_objects});
$c->stash(edit_model => 1); # to make front_image optional
if($c->user->is_superuser) {
$form = NGCP::Panel::Form::Device::ModelAdmin->new;
$form = NGCP::Panel::Form::Device::ModelAdmin->new(ctx => $c);
} else {
$form = NGCP::Panel::Form::Device::Model->new;
$form = NGCP::Panel::Form::Device::Model->new(ctx => $c);
}
if($posted) {
$c->req->params->{front_image} = $c->req->upload('front_image');

@ -252,5 +252,16 @@ has_block 'actions' => (
render_list => [qw/save/],
);
sub field_list {
my ($self) = @_;
my $c = $self->ctx;
return unless($c);
if($c->stash->{edit_model}) {
$self->field('front_image')->required(0);
}
}
1;
# vim: set tabstop=4 expandtab:

@ -13,11 +13,12 @@ use Data::HAL::Link qw();
use HTTP::Status qw(:constants);
use JSON qw();
use File::Type;
use Data::Dumper;
use NGCP::Panel::Form::Device::ModelAPI;
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::Device::ModelAPI->new($c);
return NGCP::Panel::Form::Device::ModelAPI->new(ctx => $c);
}
sub hal_from_item {
@ -66,14 +67,21 @@ sub resource_from_item {
$resource{linerange} = [];
foreach my $range($item->autoprov_device_line_ranges->all) {
my $r = { $range->get_inflated_columns };
foreach my $f(qw/device_id/) {
foreach my $f(qw/device_id num_lines/) {
delete $r->{$f};
}
$r->{id} = int($r->{id});
$r->{num_lines} = int($r->{num_lines});
foreach my $f(qw/can_private can_shared can_blf/) {
$r->{$f} = $r->{$f} ? JSON::true : JSON::false;
}
$r->{keys} = [];
foreach my $key($range->annotations->all) {
push @{ $r->{keys} }, {
x => int($key->x),
y => int($key->y),
labelpos => $key->position,
};
}
push @{ $resource{linerange} }, $r;
}
@ -134,12 +142,45 @@ sub update_item {
return;
}
my $ft = File::Type->new();
if($resource->{front_image}) {
my $front_image = delete $resource->{front_image};
$resource->{front_image} = $front_image->slurp;
$resource->{front_image_type} = $ft->mime_type($resource->{front_image});
}
if($resource->{mac_image}) {
my $front_image = delete $resource->{mac_image};
$resource->{mac_image} = $front_image->slurp;
$resource->{mac_image_type} = $ft->mime_type($resource->{mac_image});
}
$item->update($resource);
my @existing_range = ();
my $range_rs = $item->autoprov_device_line_ranges;
foreach my $range(@{ $linerange }) {
next unless(defined $range);
unless(ref $range eq "HASH") {
$c->log->error("all elements in linerange must be hashes, but this is " . ref $range . ": " . Dumper $range);
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid range definition inside linerange parameter, all must be hash");
return;
}
foreach my $elem(qw/can_private can_shared can_blf keys/) {
unless(exists $range->{$elem}) {
$c->log->error("missing mandatory attribute '$elem' in a linerange element");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid range definition inside linerange parameter, missing attribute '$elem'");
return;
}
}
unless(ref $range->{keys} eq "ARRAY") {
$c->log->error("linerange.keys must be array");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid linerange.keys parameter, must be array");
last;
}
$range->{num_lines} = @{ $range->{keys} }; # backward compatibility
my $keys = delete $range->{keys};
my $old_range;
if(defined $range->{id}) {
# should be an existing range, do update
@ -158,6 +199,21 @@ sub update_item {
# new range
$old_range = $range_rs->create($range);
}
$old_range->annotations->delete;
my $i = 0;
foreach my $label(@{ $keys }) {
unless(ref $label eq "HASH") {
$c->log->error("all elements in linerange must be hashes, but this is " . ref $range . ": " . Dumper $range);
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid range definition inside linerange parameter, all must be hash");
return;
}
$label->{line_index} = $i++;
$label->{position} = delete $label->{labelpos};
$old_range->annotations->create($label);
}
push @existing_range, $old_range->id; # mark as valid (delete others later)
# delete field device line assignments with are out-of-range or use a

Loading…
Cancel
Save