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
This commit is contained in:
Jean-Philippe Lang 2010-12-11 13:13:49 +00:00
parent 67f1131a20
commit 00d50157d3
9 changed files with 109 additions and 19 deletions

View File

@ -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)

View File

@ -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|

View File

@ -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? }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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