From 10d7bc6b73eb851c121e3e074de6c80d6d6a3ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 21 Aug 2015 12:38:48 +0200 Subject: [PATCH] Paged listing group endpoint --- app/controllers/carto/api/group_presenter.rb | 20 +++++++ .../carto/api/groups_controller.rb | 33 ++++++++++ app/models/carto/group.rb | 2 + app/models/carto/organization.rb | 1 + app/models/carto/paged_model.rb | 15 +++++ config/routes.rb | 3 + spec/factories/groups.rb | 6 ++ .../api/database_groups_controller_spec.rb | 2 +- .../carto/api/groups_controller_spec.rb | 60 +++++++++++++++++++ 9 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 app/controllers/carto/api/group_presenter.rb create mode 100644 app/controllers/carto/api/groups_controller.rb create mode 100644 app/models/carto/paged_model.rb create mode 100644 spec/requests/carto/api/groups_controller_spec.rb diff --git a/app/controllers/carto/api/group_presenter.rb b/app/controllers/carto/api/group_presenter.rb new file mode 100644 index 0000000000..5c7eb9dfac --- /dev/null +++ b/app/controllers/carto/api/group_presenter.rb @@ -0,0 +1,20 @@ +module Carto + module Api + class GroupPresenter + + def initialize(group) + @group = group + end + + def to_poro + { + id: @group.id, + organization_id: @group.organization_id, + name: @group.name, + display_name: @group.display_name + } + end + + end + end +end diff --git a/app/controllers/carto/api/groups_controller.rb b/app/controllers/carto/api/groups_controller.rb new file mode 100644 index 0000000000..0a67a298ae --- /dev/null +++ b/app/controllers/carto/api/groups_controller.rb @@ -0,0 +1,33 @@ +# encoding: utf-8 + +require_relative 'paged_searcher' + +module Carto + module Api + + class GroupsController < ::Api::ApplicationController + include PagedSearcher + + before_filter :load_organization + + def index + page, per_page, order = page_per_page_order_params + + render_jsonp({ + groups: Carto::PagedModel.paged_association(@organization.groups, page, per_page, order).map { |g| Carto::Api::GroupPresenter.new(g).to_poro }, + total_entries: @organization.groups.count, + total_org_entries: @organization.groups.count + }, 200) + end + + private + + def load_organization + @organization = Carto::Organization.where(id: params['organization_id']).first + render json: { errors: "Organization #{params['organization_id']} not found" }, status: 404 unless @organization + end + + end + + end +end diff --git a/app/models/carto/group.rb b/app/models/carto/group.rb index f6df051b8f..bb2bd23855 100644 --- a/app/models/carto/group.rb +++ b/app/models/carto/group.rb @@ -2,9 +2,11 @@ require 'active_record' require_dependency 'cartodb/errors' +require_relative 'paged_model' module Carto class Group < ActiveRecord::Base + include PagedModel belongs_to :organization, class_name: Carto::Organization has_many :users_group, dependent: :destroy, class_name: Carto::UsersGroup diff --git a/app/models/carto/organization.rb b/app/models/carto/organization.rb index e94350468d..b650df5aed 100644 --- a/app/models/carto/organization.rb +++ b/app/models/carto/organization.rb @@ -5,6 +5,7 @@ module Carto has_many :users, inverse_of: :organization, order: :username belongs_to :owner, class_name: Carto::User + has_many :groups, inverse_of: :organization, order: :display_name def self.find_by_database_name(database_name) Carto::Organization diff --git a/app/models/carto/paged_model.rb b/app/models/carto/paged_model.rb new file mode 100644 index 0000000000..a43f5376f0 --- /dev/null +++ b/app/models/carto/paged_model.rb @@ -0,0 +1,15 @@ +module Carto + module PagedModel + + def paged(page = 1, per_page = 20, order = nil) + self.paged_association(self, page, per_page, order) + end + + def self.paged_association(association, page = 1, per_page = 20, order = nil) + paged = association.offset((page - 1) * per_page).limit(per_page) + paged = paged.order(order) unless order.nil? + paged + end + + end +end diff --git a/config/routes.rb b/config/routes.rb index 670a65879d..67f4b3a50f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -350,6 +350,9 @@ CartoDB::Application.routes.draw do # Organization (new endpoint that deprecates old, unused one, so v1) get '(/user/:user_domain)(/u/:user_domain)/api/v1/organization/:id/users' => 'organizations#users', as: :api_v1_organization_users, constraints: { id: /[^\/]+/ } + # Groups + get '(/user/:user_domain)(/u/:user_domain)/api/v1/organization/:organization_id/groups' => 'groups#index', as: :api_v1_organization_groups, constraints: { organization_id: /[^\/]+/ } + # Databases (organization) groups # Note: url doesn't contain org_id because this needs to be triggered from the SQL API post '(/user/:user_domain)(/u/:user_domain)/api/v1/databases/:database_name/groups' => 'database_groups#create', as: :api_v1_databases_group_create diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb index d6775ccda0..260f500a82 100644 --- a/spec/factories/groups.rb +++ b/spec/factories/groups.rb @@ -8,4 +8,10 @@ FactoryGirl.define do database_role 'database_role' end + factory :random_group, :class => Carto::Group do |g| + name { "g_#{String.random(4)}" } + display_name { "Group #{g.name}" } + database_role { "database_role_#{g.name}" } + end + end diff --git a/spec/requests/carto/api/database_groups_controller_spec.rb b/spec/requests/carto/api/database_groups_controller_spec.rb index d600e5850d..7623b6084c 100644 --- a/spec/requests/carto/api/database_groups_controller_spec.rb +++ b/spec/requests/carto/api/database_groups_controller_spec.rb @@ -19,7 +19,7 @@ describe Carto::Api::DatabaseGroupsController do end it "Throws 401 error without http auth" do - post api_v1_databases_group_create_url(database_name: @carto_organization.database_name), {}, @no_auth_headers + post api_v1_databases_group_create_url(user_domain: @org_user_owner.username, database_name: @carto_organization.database_name), {}, @no_auth_headers response.status.should == 401 end diff --git a/spec/requests/carto/api/groups_controller_spec.rb b/spec/requests/carto/api/groups_controller_spec.rb new file mode 100644 index 0000000000..cb99db57f6 --- /dev/null +++ b/spec/requests/carto/api/groups_controller_spec.rb @@ -0,0 +1,60 @@ +# encoding: utf-8 + +require_relative '../../../spec_helper' +require_relative '../../../../app/controllers/carto/api/database_groups_controller' + +describe Carto::Api::GroupsController do + include_context 'organization with users helper' + + describe 'Groups editor management' do + + before(:all) do + @carto_organization = Carto::Organization.find(@organization.id) + @group_1 = FactoryGirl.create(:random_group, display_name: 'g_1', organization: @carto_organization) + @group_1_json = { 'id' => @group_1.id, 'organization_id' => @group_1.organization_id, 'name' => @group_1.name, 'display_name' => @group_1.display_name } + @group_2 = FactoryGirl.create(:random_group, display_name: 'g_2', organization: @carto_organization) + @group_2_json = { 'id' => @group_2.id, 'organization_id' => @group_2.organization_id, 'name' => @group_2.name, 'display_name' => @group_2.display_name } + @group_3 = FactoryGirl.create(:random_group, display_name: 'g_3', organization: @carto_organization) + @group_3_json = { 'id' => @group_3.id, 'organization_id' => @group_3.organization_id, 'name' => @group_3.name, 'display_name' => @group_3.display_name } + @no_auth_headers = {'CONTENT_TYPE' => 'application/json', :format => "json" } + end + + after(:all) do + @group_1.destroy + @group_2.destroy + @group_3.destroy + end + + it '#index returns 401 without authentication' do + get_json api_v1_organization_groups_url(user_domain: @org_user_owner.username, organization_id: @carto_organization.id), {}, @no_auth_headers do |response| + response.status.should == 401 + end + end + + it '#index returns groups with pagination metadata' do + get_json api_v1_organization_groups_url(user_domain: @org_user_owner.username, organization_id: @carto_organization.id, api_key: @org_user_owner.api_key), {}, @no_auth_headers do |response| + response.status.should == 200 + expected_response = { + groups: [ @group_1_json, @group_2_json, @group_3_json ], + total_entries: 3, + total_org_entries: 3 + } + response.body.should == expected_response + end + end + + it '#index returns paginated groups with pagination metadata' do + get_json api_v1_organization_groups_url(user_domain: @org_user_owner.username, organization_id: @carto_organization.id, api_key: @org_user_owner.api_key), { page: 2, per_page: 1, order: 'display_name' }, @no_auth_headers do |response| + response.status.should == 200 + expected_response = { + groups: [ @group_2_json ], + total_entries: 3, + total_org_entries: 3 + } + response.body.should == expected_response + end + end + + end + +end