]> source.dussan.org Git - redmine.git/commitdiff
Restores object count and adds offset/limit attributes to API responses for paginated...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 11 Dec 2010 13:13:49 +0000 (13:13 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 11 Dec 2010 13:13:49 +0000 (13:13 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4489 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/controllers/application_controller.rb
app/controllers/issues_controller.rb
app/controllers/users_controller.rb
app/helpers/application_helper.rb
app/views/issues/index.api.rsb
app/views/users/index.api.rsb
lib/redmine/views/builders/structure.rb
lib/redmine/views/builders/xml.rb
test/integration/api_test/issues_test.rb

index cb6c1a06f96a9998a85cecc9ad2a31d20694f891..40bdda06bf014173e616dec651906a764996ce8f 100644 (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)
index b0c41ff29d27e6e62ab4ec73adc56d92957e02ef..474c68c9134c2064dfb558e88f3867dc4f144cf2 100644 (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|
index 131e6b12f80408ddb15d6d91592688af7c76332e..69ffcf2c203e156bbe7b6d03787631f034a71c01 100644 (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? }
index bd13b45082a85e07a3f32c1b6c733de7d863701f..8d4f90c7600592ee853180b8a69edd86ba23527b 100644 (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
index 75c61e0a476fc2bde218d93d608640779b53ad05..1ec2acc102561445a5f896e360236a5ebebf5371 100644 (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
index 722b44ac1ecca39c1e5fa02661cc1e2a138d5412..4265a4be416eaa0ae24b5ac3bcc669407740500f 100644 (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
index 22d86470f948e0ca240956cef01502c18e28dcec..65ba474729848772e221f63fccd2a097986ff06b 100644 (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)
index 41a767154488bea70cbf14ed06d00ddc61cefa17..1211a1b41669eea1509d34f1e3a1752dbccda3d7 100644 (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
index d3aa327f1692706b2e1467e8a7979a2f6f284054..a5bda05c1f8f08c0763cb84431b213732918c6bf 100644 (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