From: Jean-Philippe Lang Date: Sat, 11 Dec 2010 13:13:49 +0000 (+0000) Subject: Restores object count and adds offset/limit attributes to API responses for paginated... X-Git-Tag: 1.1.0~107 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=00d50157d3d6ee8a12cf41d74c0a4e0da7fc9c35;p=redmine.git Restores object count and adds offset/limit attributes to API responses for paginated collections (#6140). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4489 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cb6c1a06f..40bdda06b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -349,6 +349,23 @@ class ApplicationController < ActionController::Base per_page end + def api_offset_and_limit + offset = nil + if params[:offset].present? + offset = params[:offset].to_i + if offset < 0 + offset = 0 + end + end + limit = params[:limit].to_i + if limit < 1 + limit = 25 + elsif limit > 100 + limit = 100 + end + [offset, limit] + end + # qvalues http header parser # code taken from webrick def parse_qvalues(value) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index b0c41ff29..474c68c91 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -65,21 +65,24 @@ class IssuesController < ApplicationController sort_update(@query.sortable_columns) if @query.valid? - limit = case params[:format] + case params[:format] when 'csv', 'pdf' - Setting.issues_export_limit.to_i + @limit = Setting.issues_export_limit.to_i when 'atom' - Setting.feeds_limit.to_i + @limit = Setting.feeds_limit.to_i + when 'xml', 'json' + @offset, @limit = api_offset_and_limit else - per_page_option + @limit = per_page_option end @issue_count = @query.issue_count - @issue_pages = Paginator.new self, @issue_count, limit, params['page'] + @issue_pages = Paginator.new self, @issue_count, @limit, params['page'] + @offset ||= @issue_pages.current.offset @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], :order => sort_clause, - :offset => @issue_pages.current.offset, - :limit => limit) + :offset => @offset, + :limit => @limit) @issue_count_by_group = @query.issue_count_by_group respond_to do |format| diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 131e6b12f..69ffcf2c2 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -30,6 +30,13 @@ class UsersController < ApplicationController sort_init 'login', 'asc' sort_update %w(login firstname lastname mail admin created_on last_login_on) + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + @status = params[:status] ? params[:status].to_i : 1 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) @@ -39,13 +46,13 @@ class UsersController < ApplicationController end @user_count = User.count(:conditions => c.conditions) - @user_pages = Paginator.new self, @user_count, - per_page_option, - params['page'] - @users = User.find :all,:order => sort_clause, + @user_pages = Paginator.new self, @user_count, @limit, params['page'] + @offset ||= @user_pages.current.offset + @users = User.find :all, + :order => sort_clause, :conditions => c.conditions, - :limit => @user_pages.items_per_page, - :offset => @user_pages.current.offset + :limit => @limit, + :offset => @offset respond_to do |format| format.html { render :layout => !request.xhr? } diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bd13b4508..8d4f90c76 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -877,6 +877,18 @@ module ApplicationHelper @included_in_api_response.include?(arg.to_s) end + # Returns options or nil if nometa param or X-Redmine-Nometa header + # was set in the request + def api_meta(options) + if params[:nometa].present? || request.headers['X-Redmine-Nometa'] + # compatibility mode for activeresource clients that raise + # an error when unserializing an array with attributes + nil + else + options + end + end + private def wiki_helper diff --git a/app/views/issues/index.api.rsb b/app/views/issues/index.api.rsb index 75c61e0a4..1ec2acc10 100644 --- a/app/views/issues/index.api.rsb +++ b/app/views/issues/index.api.rsb @@ -1,4 +1,4 @@ -api.array :issues do +api.array :issues, api_meta(:total_count => @issue_count, :offset => @offset, :limit => @limit) do @issues.each do |issue| api.issue do api.id issue.id diff --git a/app/views/users/index.api.rsb b/app/views/users/index.api.rsb index 722b44ac1..4265a4be4 100644 --- a/app/views/users/index.api.rsb +++ b/app/views/users/index.api.rsb @@ -1,4 +1,4 @@ -api.array :users do +api.array :users, api_meta(:total_count => @user_count, :offset => @offset, :limit => @limit) do @users.each do |user| api.user do api.id user.id diff --git a/lib/redmine/views/builders/structure.rb b/lib/redmine/views/builders/structure.rb index 22d86470f..65ba47472 100644 --- a/lib/redmine/views/builders/structure.rb +++ b/lib/redmine/views/builders/structure.rb @@ -25,11 +25,12 @@ module Redmine @struct = [{}] end - def array(tag, &block) + def array(tag, options={}, &block) @struct << [] block.call(self) ret = @struct.pop @struct.last[tag] = ret + @struct.last.merge!(options) if options end def method_missing(sym, *args, &block) diff --git a/lib/redmine/views/builders/xml.rb b/lib/redmine/views/builders/xml.rb index 41a767154..1211a1b41 100644 --- a/lib/redmine/views/builders/xml.rb +++ b/lib/redmine/views/builders/xml.rb @@ -37,7 +37,7 @@ module Redmine end def array(name, options={}, &block) - __send__ name, options.merge(:type => 'array'), &block + __send__ name, (options || {}).merge(:type => 'array'), &block end end end diff --git a/test/integration/api_test/issues_test.rb b/test/integration/api_test/issues_test.rb index d3aa327f1..a5bda05c1 100644 --- a/test/integration/api_test/issues_test.rb +++ b/test/integration/api_test/issues_test.rb @@ -46,10 +46,60 @@ class ApiTest::IssuesTest < ActionController::IntegrationTest Setting.rest_api_enabled = '1' end - # Use a private project to make sure auth is really working and not just - # only showing public issues. context "/index.xml" do + # Use a private project to make sure auth is really working and not just + # only showing public issues. should_allow_api_authentication(:get, "/projects/private-child/issues.xml") + + should "contain metadata" do + get '/issues.xml' + + assert_tag :tag => 'issues', + :attributes => { + :type => 'array', + :total_count => assigns(:issue_count), + :limit => 25, + :offset => 0 + } + end + + context "with offset and limit" do + should "use the params" do + get '/issues.xml?offset=2&limit=3' + + assert_equal 3, assigns(:limit) + assert_equal 2, assigns(:offset) + assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}} + end + end + + context "with nometa param" do + should "not contain metadata" do + get '/issues.xml?nometa=1' + + assert_tag :tag => 'issues', + :attributes => { + :type => 'array', + :total_count => nil, + :limit => nil, + :offset => nil + } + end + end + + context "with nometa header" do + should "not contain metadata" do + get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'} + + assert_tag :tag => 'issues', + :attributes => { + :type => 'array', + :total_count => nil, + :limit => nil, + :offset => nil + } + end + end end context "/index.json" do