From ee9d4fab2fcf249cea7a75f7073be66b4411e5b6 Mon Sep 17 00:00:00 2001
From: Andreas Granig <agranig@sipwise.com>
Date: Thu, 19 Dec 2013 17:35:52 +0100
Subject: [PATCH] MT#5349 API: Implement PUT/PATCH on special dprefs

For sound sets, allowed ips etc the update needs special treatment.
---
 lib/NGCP/Panel/Role/API/DomainPreferences.pm | 174 +++++++++++++++++--
 1 file changed, 155 insertions(+), 19 deletions(-)

diff --git a/lib/NGCP/Panel/Role/API/DomainPreferences.pm b/lib/NGCP/Panel/Role/API/DomainPreferences.pm
index c21379bf57..232f1b4b71 100644
--- a/lib/NGCP/Panel/Role/API/DomainPreferences.pm
+++ b/lib/NGCP/Panel/Role/API/DomainPreferences.pm
@@ -50,7 +50,8 @@ sub get_resource {
 
     my $prefs = $item->provisioning_voip_domain->voip_dom_preferences->search({
     }, {
-        join => 'attribute'
+        join => 'attribute',
+        order_by => { '-asc' => 'id' },
     });
 
     my $resource;
@@ -92,7 +93,8 @@ sub get_resource {
                 # TODO: HAL link to rewrite rule set? Also/instead set id?
             }
 
-            when(/^(adm_)?sound_set$/) {
+            when(/^(contract_)?sound_set$/) {
+                # TODO: not applicable for domains, but for subs, check for contract_id!
                 my $set = $c->model('DB')->resultset('voip_sound_sets')->find({
                     id => $pref->value,
                 });
@@ -111,6 +113,8 @@ sub get_resource {
                 $pref_name =~ s/_grp$//;
                 my $sets = $c->model('DB')->resultset('voip_allowed_ip_groups')->search({
                     group_id => $pref->value,
+                }, {
+                    order_by => { -asc => 'id' },
                 });
                 foreach my $set($sets->all) {
                     $resource->{$pref_name} = []
@@ -200,6 +204,9 @@ sub update_item {
                     $rs->delete_all;
                 }
             }
+
+            # TODO: also go over special cases (rewrite_rule_set) and delete them
+            # if not available in $resource
         } catch($e) {
             $c->log->error("failed to clear preference for domain '".$item->domain."': $e");
             $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error.");
@@ -218,6 +225,9 @@ sub update_item {
             $c->log->debug("removing unknown dom_preference '$pref' from update");
             next;
         }
+        $rs = $rs->search(undef, {
+            order_by => { '-asc' => 'id' },
+        });
 
         # TODO: can't we get this via $rs->search_related or $rs->related_resultset?
         my $meta = $c->model('DB')->resultset('voip_preferences')->find({
@@ -229,9 +239,6 @@ sub update_item {
             return;
         }
 
-        # TODO: special handling for different prefs (sound set, rewrite rule etc)
-        # TODO: check for valid enum values below!
-
         try {
             my $vtype = ref $resource->{$pref};
             if($meta->max_occur == 1 && $vtype ne "") {
@@ -244,18 +251,137 @@ sub update_item {
                 return;
             }
 
-            if($meta->max_occur != 1) {
-                $rs->delete_all;
-                foreach my $v(@{ $resource->{$pref} }) {
-                    return unless $self->check_pref_value($c, $meta, $v);
-                    $rs->create({ value => $v });
+            given($pref) {
+                $c->log->debug("+++++++++++++ checking preference $pref for update");
+                when(/^rewrite_rule_set$/) {
+
+                    my $rwr_set = $c->model('DB')->resultset('voip_rewrite_rule_sets')->find({
+                        name => $resource->{$pref},
+                        reseller_id => $item->domain_resellers->first->reseller_id,
+                    });
+                    
+                    unless($rwr_set) {
+                        $c->log->error("no rewrite rule set '".$resource->{$pref}."' for reseller id ".$item->domain_resellers->first->reseller_id." found");
+                        $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown rewrite_rule_set '".$resource->{$pref}."'");
+                        return;
+                    }
+
+                    foreach my $k(qw/caller_in_dpid callee_in_dpid caller_out_dpid callee_out_dpid/) {
+                        my $rs = NGCP::Panel::Utils::Preferences::get_dom_preference_rs(
+                            c => $c,
+                            attribute => 'rewrite_'.$k,
+                            prov_domain => $item->provisioning_voip_domain,
+                        );
+                        if($rs->first) {
+                            $rs->first->update({ value => $rwr_set->$k });
+                        } else {
+                            $rs->create({ value => $rwr_set->$k });
+                        }
+                    }
+                }
+
+                when(/^(adm_)?ncos$/) {
+                    my $pref_name = $pref . "_id";
+                    my $ncos = $c->model('DB')->resultset('ncos_levels')->find({
+                        level => $resource->{$pref},
+                        reseller_id => $item->domain_resellers->first->reseller_id,
+                    });
+                    unless($ncos) {
+                        $c->log->error("no ncos level '".$resource->{$pref}."' for reseller id ".$item->domain_resellers->first->reseller_id." found");
+                        $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown ncos_level '".$resource->{$pref}."'");
+                        return;
+                    }
+                    my $rs = NGCP::Panel::Utils::Preferences::get_dom_preference_rs(
+                        c => $c,
+                        attribute => $pref_name,
+                        prov_domain => $item->provisioning_voip_domain,
+                    );
+                    if($rs->first) {
+                        $rs->first->update({ value => $ncos->id });
+                    } else {
+                        $rs->create({ value => $ncos->id });
+                    }
+                }
+
+                when(/^(contract_)?sound_set$/) {
+                    # TODO: not applicable for domains, but for subs, check for contract_id!
+                    my $set = $c->model('DB')->resultset('voip_sound_sets')->find({
+                        name => $resource->{$pref},
+                        reseller_id => $item->domain_resellers->first->reseller_id,
+                    });
+                    unless($set) {
+                        $c->log->error("no $pref '".$resource->{$pref}."' for reseller id ".$item->domain_resellers->first->reseller_id." found");
+                        $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown $pref'".$resource->{$pref}."'");
+                        return;
+                    }
+                    my $rs = NGCP::Panel::Utils::Preferences::get_dom_preference_rs(
+                        c => $c,
+                        attribute => $pref,
+                        prov_domain => $item->provisioning_voip_domain,
+                    );
+                    if($rs->first) {
+                        $rs->first->update({ value => $set->id });
+                    } else {
+                        $rs->create({ value => $set->id });
+                    }
+                }
+
+                when(/^(man_)?allowed_ips$/) {
+                    my $pref_name = $pref . "_grp";
+                    my $aig_rs;
+                    my $seq;
+                    my $rs = NGCP::Panel::Utils::Preferences::get_dom_preference_rs(
+                        c => $c,
+                        attribute => $pref_name,
+                        prov_domain => $item->provisioning_voip_domain,
+                    );
+                    if($rs->first) {
+                        $aig_rs = $c->model('DB')->resultset('voip_allowed_ip_groups')->search({
+                            group_id => $rs->first->value
+                        });
+                        $aig_rs->delete_all;
+                    } else {
+                        my $aig_seq = $c->model('DB')->resultset('voip_aig_sequence')->search({},{
+                            for => 'update',
+                        });
+                        unless($aig_seq->first) {
+                            $seq = 1;
+                            $aig_seq->create({ id => $seq });
+                        } else {
+                            $seq = $aig_seq->first->id + 1;
+                            $aig_seq->first->update({ id => $seq });
+                        }
+                        $aig_rs = $c->model('DB')->resultset('voip_allowed_ip_groups')->search({
+                            group_id => $seq
+                        });
+                    }
+
+                    foreach my $ip(@{ $resource->{$pref} }) {
+                        # TODO: check for valid ipv4/v6
+                        $aig_rs->create({ ipnet => $ip });
+                    }
+
+                    unless($rs->first) {
+                        $rs->create({ value => $seq });
+                    }
+                }
+
+                default {
+
+                    if($meta->max_occur != 1) {
+                        $rs->delete_all;
+                        foreach my $v(@{ $resource->{$pref} }) {
+                            return unless $self->check_pref_value($c, $meta, $v);
+                            $rs->create({ value => $v });
+                        }
+                    } elsif($rs->first) {
+                        return unless $self->check_pref_value($c, $meta, $resource->{$pref});
+                        $rs->first->update({ value => $resource->{$pref} });
+                    } else {
+                        return unless $self->check_pref_value($c, $meta, $resource->{$pref});
+                        $rs->create({ value => $resource->{$pref} });
+                    }
                 }
-            } elsif($rs->first) {
-                return unless $self->check_pref_value($c, $meta, $resource->{$pref});
-                $rs->first->update({ value => $resource->{$pref} });
-            } else {
-                return unless $self->check_pref_value($c, $meta, $resource->{$pref});
-                $rs->create({ value => $resource->{$pref} });
             }
         } catch($e) {
             $c->log->error("failed to update preference for domain '".$item->domain."': $e");
@@ -267,7 +393,6 @@ sub update_item {
     return $item;
 }
 
-# TODO: check for valid ENUM values!
 sub check_pref_value {
     my ($self, $c, $meta, $value) = @_;
     my $err;
@@ -279,18 +404,29 @@ sub check_pref_value {
         return;
     }
 
-
     given($meta->data_type) {
         when("int") { $err = 1 unless $value->is_int }
         when("boolean") { $err = 1 unless JSON::is_bool($value) }
     }
-
     if($err) {
         $c->log->error("preference '".$meta->attribute."' has invalid value data type, expected '".$meta->data_type."'");
         $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid data type for element in preference '".$meta->attribute."', expected '".$meta->data_type."'");
         return;
     }
 
+    if($meta->data_type eq "enum") {
+        my $enum = $c->model('DB')->resultset('voip_preferences_enum')->find({
+            preference_id => $meta->id,
+            dom_pref => 1,
+            value => $value,
+        });
+        unless($enum) {
+            $c->log->error("preference '".$meta->attribute."' has invalid enum value '".$value."'");
+            $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid enum value in preference '".$meta->attribute."'");
+            return;
+        }
+    }
+
     return 1;
 }