##// END OF EJS Templates
REST API for reading attachments (#7671)....
Jean-Philippe Lang -
r6175:f89483a206b4
parent child
Show More
@@ -0,0 +1,1
1 render_api_attachment(@attachment, api)
@@ -0,0 +1,78
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.expand_path('../../../test_helper', __FILE__)
19
20 class ApiTest::AttachmentsTest < ActionController::IntegrationTest
21 fixtures :all
22
23 def setup
24 Setting.rest_api_enabled = '1'
25 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
26 end
27
28 context "/attachments/:id" do
29 context "GET" do
30 should "return the attachment" do
31 get '/attachments/7.xml', {}, :authorization => credentials('jsmith')
32
33 assert_response :success
34 assert_equal 'application/xml', @response.content_type
35 assert_tag :tag => 'attachment',
36 :child => {
37 :tag => 'id',
38 :content => '7',
39 :sibling => {
40 :tag => 'filename',
41 :content => 'archive.zip',
42 :sibling => {
43 :tag => 'content_url',
44 :content => 'http://www.example.com/attachments/download/7/archive.zip'
45 }
46 }
47 }
48 end
49
50 should "deny access without credentials" do
51 get '/attachments/7.xml'
52
53 assert_response 401
54 end
55 end
56 end
57
58 context "/attachments/download/:id/:filename" do
59 context "GET" do
60 should "return the attachment content" do
61 get '/attachments/download/7/archive.zip', {}, :authorization => credentials('jsmith')
62
63 assert_response :success
64 assert_equal 'application/octet-stream', @response.content_type
65 end
66
67 should "deny access without credentials" do
68 get '/attachments/download/7/archive.zip'
69
70 assert_response 302
71 end
72 end
73 end
74
75 def credentials(user, password=nil)
76 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
77 end
78 end
@@ -20,17 +20,22 class AttachmentsController < ApplicationController
20 before_filter :file_readable, :read_authorize, :except => :destroy
20 before_filter :file_readable, :read_authorize, :except => :destroy
21 before_filter :delete_authorize, :only => :destroy
21 before_filter :delete_authorize, :only => :destroy
22
22
23 verify :method => :post, :only => :destroy
23 accept_api_auth :show, :download
24
24
25 def show
25 def show
26 if @attachment.is_diff?
26 respond_to do |format|
27 @diff = File.new(@attachment.diskfile, "rb").read
27 format.html {
28 render :action => 'diff'
28 if @attachment.is_diff?
29 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
29 @diff = File.new(@attachment.diskfile, "rb").read
30 @content = File.new(@attachment.diskfile, "rb").read
30 render :action => 'diff'
31 render :action => 'file'
31 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
32 else
32 @content = File.new(@attachment.diskfile, "rb").read
33 download
33 render :action => 'file'
34 else
35 download
36 end
37 }
38 format.api
34 end
39 end
35 end
40 end
36
41
@@ -46,6 +51,7 class AttachmentsController < ApplicationController
46
51
47 end
52 end
48
53
54 verify :method => :post, :only => :destroy
49 def destroy
55 def destroy
50 # Make sure association callbacks are called
56 # Make sure association callbacks are called
51 @attachment.container.attachments.delete(@attachment)
57 @attachment.container.attachments.delete(@attachment)
@@ -43,4 +43,17 module AttachmentsHelper
43 str
43 str
44 end
44 end
45 end
45 end
46
47 def render_api_attachment(attachment, api)
48 api.attachment do
49 api.id attachment.id
50 api.filename attachment.filename
51 api.filesize attachment.filesize
52 api.content_type attachment.content_type
53 api.description attachment.description
54 api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false)
55 api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author
56 api.created_on attachment.created_on
57 end
58 end
46 end
59 end
@@ -25,6 +25,12 api.issue do
25
25
26 render_api_issue_children(@issue, api) if include_in_api_response?('children')
26 render_api_issue_children(@issue, api) if include_in_api_response?('children')
27
27
28 api.array :attachments do
29 @issue.attachments.each do |attachment|
30 render_api_attachment(attachment, api)
31 end
32 end if include_in_api_response?('attachments')
33
28 api.array :relations do
34 api.array :relations do
29 @relations.each do |relation|
35 @relations.each do |relation|
30 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)
36 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)
@@ -220,6 +220,7 ActionController::Routing::Routes.draw do |map|
220 end
220 end
221
221
222 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
222 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
223 map.connect 'attachments/:id.:format', :controller => 'attachments', :action => 'show', :id => /\d+/
223 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
224 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
224 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
225 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
225
226
@@ -1,5 +1,5
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
@@ -40,7 +40,8 class ApiTest::IssuesTest < ActionController::IntegrationTest
40 :time_entries,
40 :time_entries,
41 :journals,
41 :journals,
42 :journal_details,
42 :journal_details,
43 :queries
43 :queries,
44 :attachments
44
45
45 def setup
46 def setup
46 Setting.rest_api_enabled = '1'
47 Setting.rest_api_enabled = '1'
@@ -201,6 +202,31 class ApiTest::IssuesTest < ActionController::IntegrationTest
201 end
202 end
202 end
203 end
203
204
205 context "with attachments" do
206 context ".xml" do
207 should "display attachments" do
208 get '/issues/3.xml?include=attachments'
209
210 assert_tag :tag => 'issue',
211 :child => {
212 :tag => 'attachments',
213 :children => {:count => 5},
214 :child => {
215 :tag => 'attachment',
216 :child => {
217 :tag => 'filename',
218 :content => 'source.rb',
219 :sibling => {
220 :tag => 'content_url',
221 :content => 'http://www.example.com/attachments/download/4/source.rb'
222 }
223 }
224 }
225 }
226 end
227 end
228 end
229
204 context "with subtasks" do
230 context "with subtasks" do
205 setup do
231 setup do
206 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
232 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
@@ -25,6 +25,8 class RoutingTest < ActionController::IntegrationTest
25
25
26 context "attachments" do
26 context "attachments" do
27 should_route :get, "/attachments/1", :controller => 'attachments', :action => 'show', :id => '1'
27 should_route :get, "/attachments/1", :controller => 'attachments', :action => 'show', :id => '1'
28 should_route :get, "/attachments/1.xml", :controller => 'attachments', :action => 'show', :id => '1', :format => 'xml'
29 should_route :get, "/attachments/1.json", :controller => 'attachments', :action => 'show', :id => '1', :format => 'json'
28 should_route :get, "/attachments/1/filename.ext", :controller => 'attachments', :action => 'show', :id => '1', :filename => 'filename.ext'
30 should_route :get, "/attachments/1/filename.ext", :controller => 'attachments', :action => 'show', :id => '1', :filename => 'filename.ext'
29 should_route :get, "/attachments/download/1", :controller => 'attachments', :action => 'download', :id => '1'
31 should_route :get, "/attachments/download/1", :controller => 'attachments', :action => 'download', :id => '1'
30 should_route :get, "/attachments/download/1/filename.ext", :controller => 'attachments', :action => 'download', :id => '1', :filename => 'filename.ext'
32 should_route :get, "/attachments/download/1/filename.ext", :controller => 'attachments', :action => 'download', :id => '1', :filename => 'filename.ext'
General Comments 0
You need to be logged in to leave comments. Login now