##// END OF EJS Templates
Add support for updating attachments over REST API (#22356)....
Jean-Philippe Lang -
r15479:696c51085246
parent child
Show More
@@ -16,9 +16,10
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class AttachmentsController < ApplicationController
18 class AttachmentsController < ApplicationController
19 before_action :find_attachment, :only => [:show, :download, :thumbnail, :destroy]
19 before_action :find_attachment, :only => [:show, :download, :thumbnail, :update, :destroy]
20 before_action :find_editable_attachments, :only => [:edit_all, :update_all]
20 before_action :find_editable_attachments, :only => [:edit_all, :update_all]
21 before_action :file_readable, :read_authorize, :only => [:show, :download, :thumbnail]
21 before_action :file_readable, :read_authorize, :only => [:show, :download, :thumbnail]
22 before_action :update_authorize, :only => :update
22 before_action :delete_authorize, :only => :destroy
23 before_action :delete_authorize, :only => :destroy
23 before_action :authorize_global, :only => :upload
24 before_action :authorize_global, :only => :upload
24
25
@@ -122,6 +123,21 class AttachmentsController < ApplicationController
122 render :action => 'edit_all'
123 render :action => 'edit_all'
123 end
124 end
124
125
126 def update
127 @attachment.safe_attributes = params[:attachment]
128 saved = @attachment.save
129
130 respond_to do |format|
131 format.api {
132 if saved
133 render_api_ok
134 else
135 render_validation_errors(@attachment)
136 end
137 }
138 end
139 end
140
125 def destroy
141 def destroy
126 if @attachment.container.respond_to?(:init_journal)
142 if @attachment.container.respond_to?(:init_journal)
127 @attachment.container.init_journal(User.current)
143 @attachment.container.init_journal(User.current)
@@ -186,6 +202,10 class AttachmentsController < ApplicationController
186 @attachment.visible? ? true : deny_access
202 @attachment.visible? ? true : deny_access
187 end
203 end
188
204
205 def update_authorize
206 @attachment.editable? ? true : deny_access
207 end
208
189 def delete_authorize
209 def delete_authorize
190 @attachment.deletable? ? true : deny_access
210 @attachment.deletable? ? true : deny_access
191 end
211 end
@@ -19,6 +19,7 require "digest/md5"
19 require "fileutils"
19 require "fileutils"
20
20
21 class Attachment < ActiveRecord::Base
21 class Attachment < ActiveRecord::Base
22 include Redmine::SafeAttributes
22 belongs_to :container, :polymorphic => true
23 belongs_to :container, :polymorphic => true
23 belongs_to :author, :class_name => "User"
24 belongs_to :author, :class_name => "User"
24
25
@@ -56,6 +57,8 class Attachment < ActiveRecord::Base
56 after_rollback :delete_from_disk, :on => :create
57 after_rollback :delete_from_disk, :on => :create
57 after_commit :delete_from_disk, :on => :destroy
58 after_commit :delete_from_disk, :on => :destroy
58
59
60 safe_attributes 'filename', 'content_type', 'description'
61
59 # Returns an unsaved copy of the attachment
62 # Returns an unsaved copy of the attachment
60 def copy(attributes=nil)
63 def copy(attributes=nil)
61 copy = self.class.new
64 copy = self.class.new
@@ -293,7 +293,7 Rails.application.routes.draw do
293 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
293 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
294 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
294 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
295 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
295 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
296 resources :attachments, :only => [:show, :destroy]
296 resources :attachments, :only => [:show, :update, :destroy]
297 get 'attachments/:object_type/:object_id/edit', :to => 'attachments#edit_all', :as => :object_attachments_edit
297 get 'attachments/:object_type/:object_id/edit', :to => 'attachments#edit_all', :as => :object_attachments_edit
298 patch 'attachments/:object_type/:object_id', :to => 'attachments#update_all', :as => :object_attachments
298 patch 'attachments/:object_type/:object_id', :to => 'attachments#update_all', :as => :object_attachments
299
299
@@ -21,6 +21,7 class Redmine::ApiTest::ApiRoutingTest < Redmine::ApiTest::Routing
21
21
22 def test_attachments
22 def test_attachments
23 should_route 'GET /attachments/1' => 'attachments#show', :id => '1'
23 should_route 'GET /attachments/1' => 'attachments#show', :id => '1'
24 should_route 'PATCH /attachments/1' => 'attachments#update', :id => '1'
24 should_route 'POST /uploads' => 'attachments#upload'
25 should_route 'POST /uploads' => 'attachments#upload'
25 end
26 end
26
27
@@ -99,6 +99,29 class Redmine::ApiTest::AttachmentsTest < Redmine::ApiTest::Base
99 assert_nil Attachment.find_by_id(7)
99 assert_nil Attachment.find_by_id(7)
100 end
100 end
101
101
102 test "PATCH /attachments/:id.json should update the attachment" do
103 patch '/attachments/7.json',
104 {:attachment => {:filename => 'renamed.zip', :description => 'updated'}},
105 credentials('jsmith')
106
107 assert_response :ok
108 assert_equal 'application/json', response.content_type
109 attachment = Attachment.find(7)
110 assert_equal 'renamed.zip', attachment.filename
111 assert_equal 'updated', attachment.description
112 end
113
114 test "PATCH /attachments/:id.json with failure should return the errors" do
115 patch '/attachments/7.json',
116 {:attachment => {:filename => '', :description => 'updated'}},
117 credentials('jsmith')
118
119 assert_response 422
120 assert_equal 'application/json', response.content_type
121 json = ActiveSupport::JSON.decode(response.body)
122 assert_include "File cannot be blank", json['errors']
123 end
124
102 test "POST /uploads.xml should return the token" do
125 test "POST /uploads.xml should return the token" do
103 set_tmp_attachments_directory
126 set_tmp_attachments_directory
104 assert_difference 'Attachment.count' do
127 assert_difference 'Attachment.count' do
@@ -30,7 +30,7 class RoutingAttachmentsTest < Redmine::RoutingTest
30
30
31 should_route 'DELETE /attachments/1' => 'attachments#destroy', :id => '1'
31 should_route 'DELETE /attachments/1' => 'attachments#destroy', :id => '1'
32
32
33 should_route 'GET /attachments/issues/1/edit' => 'attachments#edit', :object_type => 'issues', :object_id => '1'
33 should_route 'GET /attachments/issues/1/edit' => 'attachments#edit_all', :object_type => 'issues', :object_id => '1'
34 should_route 'PATCH /attachments/issues/1' => 'attachments#update', :object_type => 'issues', :object_id => '1'
34 should_route 'PATCH /attachments/issues/1' => 'attachments#update_all', :object_type => 'issues', :object_id => '1'
35 end
35 end
36 end
36 end
General Comments 0
You need to be logged in to leave comments. Login now