Order tenants list in reply in heirarchic order
Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/c9181f24 Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/c9181f24 Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/c9181f24 Branch: refs/heads/master Commit: c9181f247714297d0e4f7bb0a9683a56fa97070c Parents: a1bf58f Author: nir-sopher <[email protected]> Authored: Thu Jun 1 16:00:28 2017 +0300 Committer: Jeremy Mitchell <[email protected]> Committed: Tue Jul 18 12:12:31 2017 -0600 ---------------------------------------------------------------------- traffic_ops/app/lib/API/Tenant.pm | 22 ++++--- traffic_ops/app/lib/UI/TenantUtils.pm | 97 ++++++++++++++++++++++++++++++ traffic_ops/app/t/api/1.2/tenant.t | 21 +++++-- 3 files changed, 128 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c9181f24/traffic_ops/app/lib/API/Tenant.pm ---------------------------------------------------------------------- diff --git a/traffic_ops/app/lib/API/Tenant.pm b/traffic_ops/app/lib/API/Tenant.pm index 3bcdd0f..79795a4 100644 --- a/traffic_ops/app/lib/API/Tenant.pm +++ b/traffic_ops/app/lib/API/Tenant.pm @@ -17,6 +17,7 @@ package API::Tenant; # use UI::Utils; +use UI::TenantUtils; use Mojo::Base 'Mojolicious::Controller'; use Data::Dumper; @@ -26,30 +27,30 @@ use MojoPlugins::Response; my $finfo = __FILE__ . ":"; sub getTenantName { - my $self = shift; + my $self = shift; my $tenant_id = shift; return defined($tenant_id) ? $self->db->resultset('Tenant')->search( { id => $tenant_id } )->get_column('name')->single() : "n/a"; } sub isRootTenant { - my $self = shift; + my $self = shift; my $tenant_id = shift; return !defined($self->db->resultset('Tenant')->search( { id => $tenant_id } )->get_column('parent_id')->single()); } sub index { my $self = shift; - my @data = (); - my %idnames; - my $orderby = $self->param('orderby') || "name"; + my %idnames; my $rs_data = $self->db->resultset("Tenant")->search(); while ( my $row = $rs_data->next ) { $idnames{ $row->id } = $row->name; } - my $rs_data = $self->db->resultset("Tenant")->search( undef, {order_by => 'me.' . $orderby } ); - while ( my $row = $rs_data->next ) { + my @data = (); + my $tenantUtils = UI::TenantUtils->new($self); + my @tenants_list = $tenantUtils->get_hierarchic_tenants_list(); + foreach my $row (@tenants_list) { push( @data, { "id" => $row->id, @@ -122,6 +123,8 @@ sub update { } if ( !defined( $params->{parentId}) && !$self->isRootTenant($id) ) { + # Cannot turn a simple tenant to a root tenant. + # Practically there is no problem with doing so, but it is to risky to be done by mistake. return $self->alert("Parent Id is required."); } @@ -134,12 +137,12 @@ sub update { if ( !$params->{active} && $self->isRootTenant($id)) { return $self->alert("Root user cannot be in-active."); } - if ( !defined($params->{parentId}) && !isRootTenant($id) ) { return $self->alert("Only the \"root\" tenant can have no parent."); } + #operation my $values = { name => $params->{name}, active => $params->{active}, @@ -185,6 +188,8 @@ sub create { return $self->alert("Tenant name is required."); } + #not allowing to create additional root tenants. + #there is no real problem with that, but no real use also my $parent_id = $params->{parentId}; if ( !defined($parent_id) ) { return $self->alert("Parent Id is required."); @@ -248,6 +253,7 @@ sub delete { if ( !defined($tenant) ) { return $self->not_found(); } + my $name = $self->db->resultset('Tenant')->search( { id => $id } )->get_column('name')->single(); my $existing_child = $self->db->resultset('Tenant')->search( { parent_id => $id }, {order_by => 'me.name' } )->get_column('name')->first(); http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c9181f24/traffic_ops/app/lib/UI/TenantUtils.pm ---------------------------------------------------------------------- diff --git a/traffic_ops/app/lib/UI/TenantUtils.pm b/traffic_ops/app/lib/UI/TenantUtils.pm new file mode 100644 index 0000000..253c588 --- /dev/null +++ b/traffic_ops/app/lib/UI/TenantUtils.pm @@ -0,0 +1,97 @@ +package UI::TenantUtils; +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +use NetAddr::IP; +use Data::Dumper; +use Switch; +use UI::Utils; + + +sub new { + my $class = shift; + my $self = { + context => shift, + user_tenant_id => -1, + tenants_dict => undef, + root_tenants => undef, + }; + return bless $self, $class; +} + +sub get_hierarchic_tenants_list { + my $self = shift; + my $tree_root = shift; + + $self->_init_tenants_if_needed(); + + my @stack = (); + if (defined($tree_root)){ + push (@stack, $tree_root); + } + else { + push (@stack, reverse(@{$self->{root_tenants}})); + } + + my @result = (); + while (@stack) { + my $tenant_id = pop @stack; + push (@result, $self->{tenants_dict}->{$tenant_id}{row}); + push (@stack, reverse(@{$self->{tenants_dict}->{$tenant_id}{children}})); + } + + return @result; +} + +############################################################## + +sub _init_tenants { + my $self = shift; + my $tenants_table = $self->{context}->db->resultset("Tenant")->search( undef, { order_by => "id" }); + + my @ordered_by_id = (); + $self->{tenants_dict} = {}; + while ( my $row = $tenants_table->next ) { + push (@ordered_by_id, $row->id); + $self->{tenants_dict}->{$row->id} = { + row => $row, + parent => $row->parent_id, + children => (), + } + } + + $self->{root_tenants} = (); + foreach my $key (@ordered_by_id) { + my $value = $self->{tenants_dict}->{$key}; + my $parent = $value->{parent}; + if (!defined($parent)) + { + push @{ $self->{root_tenants} }, $key; + } + else{ + push @{ $self->{tenants_dict}->{$parent}{children} }, $key; + } + } +} + +sub _init_tenants_if_needed { + my $self = shift; + if (!defined($self->{tenants_dict})) { + $self->_init_tenants(); + } +} + +1; http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c9181f24/traffic_ops/app/t/api/1.2/tenant.t ---------------------------------------------------------------------- diff --git a/traffic_ops/app/t/api/1.2/tenant.t b/traffic_ops/app/t/api/1.2/tenant.t index 986f919..5d671ba 100644 --- a/traffic_ops/app/t/api/1.2/tenant.t +++ b/traffic_ops/app/t/api/1.2/tenant.t @@ -35,7 +35,7 @@ my $t = Test::Mojo->new('TrafficOps'); Test::TestHelper->unload_core_data($schema); Test::TestHelper->load_core_data($schema); -ok $t->post_ok( '/login', => form => { u => Test::TestHelper::ADMIN_USER, p => Test::TestHelper::ADMIN_USER_PASSWORD } )->status_is(302) +ok $t->post_ok( '/login', => form => { u => Test::TestHelper::ADMIN_ROOT_USER, p => Test::TestHelper::ADMIN_ROOT_USER_PASSWORD } )->status_is(302) ->or( sub { diag $t->tx->res->content->asset->{content}; } ), 'Should login?'; #verifying the basic cfg @@ -63,7 +63,12 @@ ok $t->post_ok('/api/1.2/tenants' => {Accept => 'application/json'} => json => { ok $t->post_ok('/api/1.2/tenants' => {Accept => 'application/json'} => json => { "name" => "tenantB" })->status_is(400); +#now getting it excepted +ok $t->post_ok('/api/1.2/tenants' => {Accept => 'application/json'} => json => { + "name" => "tenantB", "parentId" => $root_tenant_id })->status_is(200); + my $tenantA_id = &get_tenant_id('tenantA'); +my $tenantB_id = &get_tenant_id('tenantB'); #rename, and move to active ok $t->put_ok('/api/1.2/tenants/' . $tenantA_id => {Accept => 'application/json'} => json => { "name" => "tenantA2", "active" => 1, "parentId" => $root_tenant_id @@ -140,17 +145,25 @@ ok $t->post_ok('/api/1.2/tenants' => {Accept => 'application/json'} => json => { ->json_is( "/response/parentId" => $tenantA_id) , 'Does the tenant details return?'; +my $tenantD_id = &get_tenant_id('tenantD'); +my $tenantE_id = &get_tenant_id('tenantE'); + +-#list tenants- verify heirachic order +$t->get_ok("/api/1.2/tenants")->status_is(200)->json_is( "/response/0/id", $root_tenant_id ) + ->json_is( "/response/1/id", $tenantA_id) + ->json_is( "/response/2/id", $tenantD_id) + ->json_is( "/response/3/id", $tenantE_id) + ->json_is( "/response/4/id", $tenantB_id)->or( sub { diag $t->tx->res->content->asset->{content}; } );; + #cannot delete a tenant that have children ok $t->delete_ok('/api/1.2/tenants/' . $tenantA_id)->status_is(400) ->json_is( "/alerts/0/text" => "Tenant 'tenantA2' has children tenant(s): e.g 'tenantD'. Please update these tenants and retry." ) ->or( sub { diag $t->tx->res->content->asset->{content}; } ); -my $tenantD_id = &get_tenant_id('tenantD'); -my $tenantE_id = &get_tenant_id('tenantE'); - ok $t->delete_ok('/api/1.2/tenants/' . $tenantE_id)->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } ); ok $t->delete_ok('/api/1.2/tenants/' . $tenantD_id)->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } ); ok $t->delete_ok('/api/1.2/tenants/' . $tenantA_id)->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } ); +ok $t->delete_ok('/api/1.2/tenants/' . $tenantB_id)->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } ); #cannot delete a tenant that have a delivery-service ok $t->delete_ok('/api/1.2/tenants/' . 10**9)->status_is(400)
