@@ -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