TT#23771 fix /api/subscriberregistration logic

* Fix item update: a new reloaded item is correctly fetched
      fom the db
    * Fix Location header: path and item id are correctly delivered
      with the header
    * Fix xmlrpc ul.add call params:
        - correct params order
        - "expires" param value is properly calculated

cherry-picked to mr5.5 (see TT#38607)

Change-Id: I194b6bab9cb0d295e0a350e6317f7ddbcebdc021
(cherry picked from commit dbb62078e1)
changes/26/21926/2
Kirill Solomko 7 years ago committed by Gerhard Jungwirth
parent 724d3f0483
commit c4ed417c7e

@ -101,7 +101,7 @@ sub OPTIONS :Allow {
sub PATCH :Allow {
my ($self, $c, $id) = @_;
my $guard = $c->model('DB')->txn_scope_guard;
{
my $preference = $self->require_preference($c);
last unless $preference;
@ -113,22 +113,35 @@ sub PATCH :Allow {
);
last unless $json;
my $item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, subscriberregistration => $item);
my $form = $self->get_form($c);
my $old_resource = $self->resource_from_item($c, $item, $form);
my $resource = $self->apply_patch($c, $old_resource, $json);
last unless $form;
my ($item, $old_resource, $resource);
my ($guard, $txn_ok) = ($c->model('DB')->txn_scope_guard, 0);
{
$item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, subscriberregistration => $item);
$old_resource = $self->resource_from_item($c, $item, $form);
$resource = $self->apply_patch($c, $old_resource, $json);
last unless $resource;
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
last unless $item;
$guard->commit;
$txn_ok = 1;
}
last unless $txn_ok;
$item = $self->fetch_item($c, $resource, $form, $item);
last unless $item;
if ('minimal' eq $preference) {
$c->response->status(HTTP_NO_CONTENT);
$c->response->header(Preference_Applied => 'return=minimal');
$c->response->header(Location => sprintf('/%s%d', $c->request->path, $item->id));
$c->response->header(Location => sprintf('%s%d', $self->dispatch_path, $item->id));
$c->response->body(q());
} else {
my $hal = $self->hal_from_item($c, $item, $form);
@ -137,40 +150,54 @@ sub PATCH :Allow {
), $hal->as_json);
$c->response->headers($response->headers);
$c->response->header(Preference_Applied => 'return=representation');
$c->response->header(Location => sprintf('/%s%d', $c->request->path, $item->id));
$c->response->header(Location => sprintf('%s%d', $self->dispatch_path, $item->id));
$c->response->body($response->content);
}
}
return;
}
sub PUT :Allow {
my ($self, $c, $id) = @_;
my $guard = $c->model('DB')->txn_scope_guard;
{
my $preference = $self->require_preference($c);
last unless $preference;
my $item = $self->item_by_id($c, $id);
my $form = $self->get_form($c);
last unless $form;
my ($item, $old_resource, $resource);
my ($guard, $txn_ok) = ($c->model('DB')->txn_scope_guard, 0);
{
$item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, subscriberregistration => $item);
my $resource = $self->get_valid_put_data(
$old_resource = $self->resource_from_item($c, $item, $form);
$resource = $self->get_valid_put_data(
c => $c,
id => $id,
media_type => 'application/json',
);
last unless $resource;
my $form = $self->get_form($c);
my $old_resource = $self->resource_from_item($c, $item, $form);
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
last unless $item;
$guard->commit;
$txn_ok = 1;
}
last unless $txn_ok;
$item = $self->fetch_item($c, $resource, $form, $item);
last unless $item;
if ('minimal' eq $preference) {
$c->response->status(HTTP_NO_CONTENT);
$c->response->header(Preference_Applied => 'return=minimal');
$c->response->header(Location => sprintf('/%s%d', $c->request->path, $item->id));
$c->response->header(Location => sprintf('%s%d', $self->dispatch_path, $item->id));
$c->response->body(q());
} else {
my $hal = $self->hal_from_item($c, $item, $form);
@ -179,10 +206,11 @@ sub PUT :Allow {
), $hal->as_json);
$c->response->headers($response->headers);
$c->response->header(Preference_Applied => 'return=representation');
$c->response->header(Location => sprintf('/%s%d', $c->request->path, $item->id));
$c->response->header(Location => sprintf('%s%d', $self->dispatch_path, $item->id));
$c->response->body($response->content);
}
}
return;
}

@ -143,6 +143,16 @@ sub subscriber_from_id {
return $sub;
}
sub _item_by_aor {
my ($self, $c, $sub, $contact) = @_;
return $self->item_rs($c)->search({
'me.contact' => $contact,
'me.username' => $sub->provisioning_voip_subscriber->username,
'me.domain' => $sub->provisioning_voip_subscriber->domain->domain,
})->first;
}
sub update_item {
my ($self, $c, $item, $old_resource, $resource, $form, $create) = @_;
@ -157,13 +167,14 @@ sub update_item {
);
my $sub = $self->subscriber_from_id($c, $resource->{subscriber_id});
return unless($sub);
return unless $sub;
unless($create) {
$self->delete_item($c, $item);
}
my $cflags = 0;
$cflags |= 64 if($form->values->{nat});
NGCP::Panel::Utils::Kamailio::create_location($c,
$sub->provisioning_voip_subscriber,
$form->values->{contact},
@ -172,28 +183,39 @@ sub update_item {
0, # flags
$cflags
);
my $item_reloaded;
{
NGCP::Panel::Utils::Kamailio::flush($c);
my $rs = $self->item_rs($c);
$item_reloaded = $rs->search({
'me.contact' => $form->values->{contact},
'me.username' => $sub->provisioning_voip_subscriber->username,
'me.domain' => $sub->provisioning_voip_subscriber->domain->domain,
})->first;
}
if($create) {
$item = $item_reloaded;
}else{
# we need to reload it since we changed the content via an external
# xmlrpc call
$item->discard_changes;
if($item_reloaded){
$item = $item_reloaded;
return $item;
}
sub fetch_item {
my ($self, $c, $resource, $form, $old_item) = @_;
return unless $form;
my $sub = $self->subscriber_from_id($c, $resource->{subscriber_id});
return unless $sub;
my $item;
my $flush_timeout = 5;
while ($flush_timeout) {
$item = $self->_item_by_aor($c, $sub, $form->values->{contact});
if ($item && (!$old_item || $item->id != $old_item->id)) {
last;
}
$item = undef;
$flush_timeout--;
last unless $flush_timeout;
sleep 1;
}
unless ($item) {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Could not find a new registration entry in the db, that might be caused by the kamailio flush mechanism, where the item has been updated successfully");
return;
}
return $item;
}

@ -47,11 +47,18 @@ sub create_location {
my $aor = get_aor($c, $prov_subscriber);
my $path = $c->config->{sip}->{path} || '<sip:127.0.0.1:5060;lr>';
if($expires) {
if ($expires) {
$expires = NGCP::Panel::Utils::DateTime::from_string($expires)->epoch;
$expires //= 0;
$expires -= time();
# "expires" is required to be an integer but it is not a timestamp
# <=0: 1970-01-01 00:00:00
# 1: now
# >=1: now + seconds to the future
} else {
$expires = 4294967295;
}
$expires = 0 if $expires < 0;
$flags //= 0;
$cflags //= 0;
my $dispatcher = NGCP::Panel::Utils::XMLDispatcher->new;
@ -63,12 +70,12 @@ sub create_location {
<param><value><string>location</string></value></param>
<param><value><string>$aor</string></value></param>
<param><value><string>$contact</string></value></param>
<param><value><int>0</int></value></param>
<param><value><int>$expires</int></value></param>
<param><value><double>$q</double></value></param>
<param><value><string><![CDATA[$path]]></string></value></param>
<param><value><int>$flags</int></value></param>
<param><value><int>$cflags</int></value></param>
<param><value><int>$expires</int></value></param>
<param><value><int>0</int></value></param>
</params>
</methodCall>
EOF

Loading…
Cancel
Save