From d48ea908761d6489640e39667034d6e43524aaa7 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Wed, 6 Jul 2011 16:57:04 +0000 Subject: [PATCH] Makes custom queries available through the REST API (#5737). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@6186 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/queries_controller.rb | 26 +++++++++-- app/models/query.rb | 12 ++++- app/views/queries/index.api.rsb | 10 +++++ config/routes.rb | 1 + test/integration/api_test/queries_test.rb | 55 +++++++++++++++++++++++ test/integration/routing_test.rb | 3 ++ test/unit/query_test.rb | 10 +++++ 7 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 app/views/queries/index.api.rsb create mode 100644 test/integration/api_test/queries_test.rb diff --git a/app/controllers/queries_controller.rb b/app/controllers/queries_controller.rb index 60f3b445f..601ad85d1 100644 --- a/app/controllers/queries_controller.rb +++ b/app/controllers/queries_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,9 +17,29 @@ class QueriesController < ApplicationController menu_item :issues - before_filter :find_query, :except => :new + before_filter :find_query, :except => [:new, :index] before_filter :find_optional_project, :only => :new + accept_key_auth :index + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @query_count = Query.visible.count + @query_pages = Paginator.new self, @query_count, @limit, params['page'] + @queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name") + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + def new @query = Query.new(params[:query]) @query.project = params[:query_is_for_all] ? nil : @project diff --git a/app/models/query.rb b/app/models/query.rb index 786751c8c..a6fbe9b94 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -146,6 +146,16 @@ class Query < ActiveRecord::Base ] cattr_reader :available_columns + named_scope :visible, lambda {|*args| + user = args.shift || User.current + base = Project.allowed_to_condition(user, :view_issues, *args) + user_id = user.logged? ? user.id : 0 + { + :conditions => ["(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id], + :include => :project + } + } + def initialize(attributes = nil) super attributes self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } @@ -168,7 +178,7 @@ class Query < ActiveRecord::Base # Returns true if the query is visible to +user+ or the current user. def visible?(user=User.current) - self.is_public? || self.user_id == user.id + (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id) end def editable_by?(user) diff --git a/app/views/queries/index.api.rsb b/app/views/queries/index.api.rsb new file mode 100644 index 000000000..800b4964e --- /dev/null +++ b/app/views/queries/index.api.rsb @@ -0,0 +1,10 @@ +api.array :queries, api_meta(:total_count => @query_count, :offset => @offset, :limit => @limit) do + @queries.each do |query| + api.query do + api.id query.id + api.name query.name + api.is_public query.is_public + api.project_id query.project_id + end + end +end diff --git a/config/routes.rb b/config/routes.rb index dfac70dc5..3188c9fc4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -77,6 +77,7 @@ ActionController::Routing::Routes.draw do |map| end map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move' + map.resources :queries, :only => [:index] # Misc issue routes. TODO: move into resources map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues' diff --git a/test/integration/api_test/queries_test.rb b/test/integration/api_test/queries_test.rb new file mode 100644 index 000000000..154472e19 --- /dev/null +++ b/test/integration/api_test/queries_test.rb @@ -0,0 +1,55 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../test_helper', __FILE__) + +class ApiTest::QueriesTest < ActionController::IntegrationTest + fixtures :all + + def setup + Setting.rest_api_enabled = '1' + end + + context "/queries" do + context "GET" do + + should "return queries" do + get '/queries.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'queries', + :attributes => {:type => 'array'}, + :child => { + :tag => 'query', + :child => { + :tag => 'id', + :content => '4', + :sibling => { + :tag => 'name', + :content => 'Public query for all projects' + } + } + } + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index c78f4082b..d25ed3d73 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -210,6 +210,9 @@ class RoutingTest < ActionController::IntegrationTest end context "queries" do + should_route :get, "/queries.xml", :controller => 'queries', :action => 'index', :format => 'xml' + should_route :get, "/queries.json", :controller => 'queries', :action => 'index', :format => 'json' + should_route :get, "/queries/new", :controller => 'queries', :action => 'new' should_route :get, "/projects/redmine/queries/new", :controller => 'queries', :action => 'new', :project_id => 'redmine' diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index 27a0a37e7..646e4099f 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -417,6 +417,16 @@ class QueryTest < ActiveSupport::TestCase assert !q.editable_by?(manager) assert !q.editable_by?(developer) end + + def test_visible_scope + query_ids = Query.visible(User.anonymous).map(&:id) + + assert query_ids.include?(1), 'public query on public project was not visible' + assert query_ids.include?(4), 'public query for all projects was not visible' + assert !query_ids.include?(2), 'private query on public project was visible' + assert !query_ids.include?(3), 'private query for all projects was visible' + assert !query_ids.include?(7), 'public query on private project was visible' + end context "#available_filters" do setup do