summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2011-07-18 20:53:10 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2011-07-18 20:53:10 +0000
commitf89483a206b4aea3a307000c5ed7c0e9da5bea93 (patch)
tree060d0e9b017fb58474b1c4bd5c8c5554ef5578a3
parente10198f0d5f3f0b7ba2f95a1fa1ae16abe89fb0d (diff)
downloadredmine-f89483a206b4aea3a307000c5ed7c0e9da5bea93.tar.gz
redmine-f89483a206b4aea3a307000c5ed7c0e9da5bea93.zip
REST API for reading attachments (#7671).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@6295 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r--app/controllers/attachments_controller.rb24
-rw-r--r--app/helpers/attachments_helper.rb13
-rw-r--r--app/views/attachments/show.api.rsb1
-rw-r--r--app/views/issues/show.api.rsb6
-rw-r--r--config/routes.rb1
-rw-r--r--test/integration/api_test/attachments_test.rb78
-rw-r--r--test/integration/api_test/issues_test.rb30
-rw-r--r--test/integration/routing_test.rb2
8 files changed, 144 insertions, 11 deletions
diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb
index 2a68a2a9a..b0e09cb80 100644
--- a/app/controllers/attachments_controller.rb
+++ b/app/controllers/attachments_controller.rb
@@ -20,17 +20,22 @@ class AttachmentsController < ApplicationController
before_filter :file_readable, :read_authorize, :except => :destroy
before_filter :delete_authorize, :only => :destroy
- verify :method => :post, :only => :destroy
+ accept_api_auth :show, :download
def show
- if @attachment.is_diff?
- @diff = File.new(@attachment.diskfile, "rb").read
- render :action => 'diff'
- elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
- @content = File.new(@attachment.diskfile, "rb").read
- render :action => 'file'
- else
- download
+ respond_to do |format|
+ format.html {
+ if @attachment.is_diff?
+ @diff = File.new(@attachment.diskfile, "rb").read
+ render :action => 'diff'
+ elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
+ @content = File.new(@attachment.diskfile, "rb").read
+ render :action => 'file'
+ else
+ download
+ end
+ }
+ format.api
end
end
@@ -46,6 +51,7 @@ class AttachmentsController < ApplicationController
end
+ verify :method => :post, :only => :destroy
def destroy
# Make sure association callbacks are called
@attachment.container.attachments.delete(@attachment)
diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb
index e6150a3b3..f7e4d8420 100644
--- a/app/helpers/attachments_helper.rb
+++ b/app/helpers/attachments_helper.rb
@@ -43,4 +43,17 @@ module AttachmentsHelper
str
end
end
+
+ def render_api_attachment(attachment, api)
+ api.attachment do
+ api.id attachment.id
+ api.filename attachment.filename
+ api.filesize attachment.filesize
+ api.content_type attachment.content_type
+ api.description attachment.description
+ api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false)
+ api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author
+ api.created_on attachment.created_on
+ end
+ end
end
diff --git a/app/views/attachments/show.api.rsb b/app/views/attachments/show.api.rsb
new file mode 100644
index 000000000..5a9f74a91
--- /dev/null
+++ b/app/views/attachments/show.api.rsb
@@ -0,0 +1 @@
+render_api_attachment(@attachment, api)
diff --git a/app/views/issues/show.api.rsb b/app/views/issues/show.api.rsb
index 9d98959a9..ccc3e8767 100644
--- a/app/views/issues/show.api.rsb
+++ b/app/views/issues/show.api.rsb
@@ -25,6 +25,12 @@ api.issue do
render_api_issue_children(@issue, api) if include_in_api_response?('children')
+ api.array :attachments do
+ @issue.attachments.each do |attachment|
+ render_api_attachment(attachment, api)
+ end
+ end if include_in_api_response?('attachments')
+
api.array :relations do
@relations.each do |relation|
api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay)
diff --git a/config/routes.rb b/config/routes.rb
index 3188c9fc4..17c36785f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -220,6 +220,7 @@ ActionController::Routing::Routes.draw do |map|
end
map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
+ map.connect 'attachments/:id.:format', :controller => 'attachments', :action => 'show', :id => /\d+/
map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
diff --git a/test/integration/api_test/attachments_test.rb b/test/integration/api_test/attachments_test.rb
new file mode 100644
index 000000000..a0c57ee38
--- /dev/null
+++ b/test/integration/api_test/attachments_test.rb
@@ -0,0 +1,78 @@
+# 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::AttachmentsTest < ActionController::IntegrationTest
+ fixtures :all
+
+ def setup
+ Setting.rest_api_enabled = '1'
+ Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
+ end
+
+ context "/attachments/:id" do
+ context "GET" do
+ should "return the attachment" do
+ get '/attachments/7.xml', {}, :authorization => credentials('jsmith')
+
+ assert_response :success
+ assert_equal 'application/xml', @response.content_type
+ assert_tag :tag => 'attachment',
+ :child => {
+ :tag => 'id',
+ :content => '7',
+ :sibling => {
+ :tag => 'filename',
+ :content => 'archive.zip',
+ :sibling => {
+ :tag => 'content_url',
+ :content => 'http://www.example.com/attachments/download/7/archive.zip'
+ }
+ }
+ }
+ end
+
+ should "deny access without credentials" do
+ get '/attachments/7.xml'
+
+ assert_response 401
+ end
+ end
+ end
+
+ context "/attachments/download/:id/:filename" do
+ context "GET" do
+ should "return the attachment content" do
+ get '/attachments/download/7/archive.zip', {}, :authorization => credentials('jsmith')
+
+ assert_response :success
+ assert_equal 'application/octet-stream', @response.content_type
+ end
+
+ should "deny access without credentials" do
+ get '/attachments/download/7/archive.zip'
+
+ assert_response 302
+ end
+ end
+ end
+
+ def credentials(user, password=nil)
+ ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
+ end
+end
diff --git a/test/integration/api_test/issues_test.rb b/test/integration/api_test/issues_test.rb
index bfcd63e2a..aca639556 100644
--- a/test/integration/api_test/issues_test.rb
+++ b/test/integration/api_test/issues_test.rb
@@ -1,5 +1,5 @@
# Redmine - project management software
-# Copyright (C) 2006-2010 Jean-Philippe Lang
+# 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
@@ -40,7 +40,8 @@ class ApiTest::IssuesTest < ActionController::IntegrationTest
:time_entries,
:journals,
:journal_details,
- :queries
+ :queries,
+ :attachments
def setup
Setting.rest_api_enabled = '1'
@@ -201,6 +202,31 @@ class ApiTest::IssuesTest < ActionController::IntegrationTest
end
end
+ context "with attachments" do
+ context ".xml" do
+ should "display attachments" do
+ get '/issues/3.xml?include=attachments'
+
+ assert_tag :tag => 'issue',
+ :child => {
+ :tag => 'attachments',
+ :children => {:count => 5},
+ :child => {
+ :tag => 'attachment',
+ :child => {
+ :tag => 'filename',
+ :content => 'source.rb',
+ :sibling => {
+ :tag => 'content_url',
+ :content => 'http://www.example.com/attachments/download/4/source.rb'
+ }
+ }
+ }
+ }
+ end
+ end
+ end
+
context "with subtasks" do
setup do
@c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb
index d25ed3d73..fd6ae632e 100644
--- a/test/integration/routing_test.rb
+++ b/test/integration/routing_test.rb
@@ -25,6 +25,8 @@ class RoutingTest < ActionController::IntegrationTest
context "attachments" do
should_route :get, "/attachments/1", :controller => 'attachments', :action => 'show', :id => '1'
+ should_route :get, "/attachments/1.xml", :controller => 'attachments', :action => 'show', :id => '1', :format => 'xml'
+ should_route :get, "/attachments/1.json", :controller => 'attachments', :action => 'show', :id => '1', :format => 'json'
should_route :get, "/attachments/1/filename.ext", :controller => 'attachments', :action => 'show', :id => '1', :filename => 'filename.ext'
should_route :get, "/attachments/download/1", :controller => 'attachments', :action => 'download', :id => '1'
should_route :get, "/attachments/download/1/filename.ext", :controller => 'attachments', :action => 'download', :id => '1', :filename => 'filename.ext'