Project

General

Profile

Patch #19116 » 0001-REST-API-add-files-REST-API.patch

Lucile Quirion, 2015-02-16 20:21

View differences:

app/controllers/files_controller.rb
20 20

  
21 21
  before_filter :find_project_by_project_id
22 22
  before_filter :authorize
23
  accept_api_auth :index, :create
23 24

  
24 25
  helper :sort
25 26
  include SortHelper
......
35 36
                     references(:attachments).reorder(sort_clause).find(@project.id)]
36 37
    @containers += @project.versions.includes(:attachments).
37 38
                    references(:attachments).reorder(sort_clause).to_a.sort.reverse
38
    render :layout => !request.xhr?
39
    respond_to do |format|
40
      format.html { render :layout => !request.xhr? }
41
      format.api
42
    end
43

  
39 44
  end
40 45

  
41 46
  def new
......
50 55
    if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added')
51 56
      Mailer.attachments_added(attachments[:files]).deliver
52 57
    end
53
    redirect_to project_files_path(@project)
58

  
59
    respond_to do |format|
60
      format.html { redirect_to project_files_path(@project) }
61
      format.api { render_api_ok }
62
    end
54 63
  end
55 64
end
app/views/files/index.api.rsb
1
api.array :files do
2
  @containers.each do |container|
3
    next if container.attachments.empty?
4
    if container.is_a?(Version)
5
      version_id = container.name
6
    end
7

  
8
    container.attachments.each do |file|
9
      api.file do
10
        api.id file.id
11

  
12
        api.filename file.filename
13
        api.author_id file.author_id
14
        api.description file.description
15
        api.content_type file.content_type
16

  
17
        api.created_on file.created_on
18
        api.filesize file.filesize
19
        api.digest file.digest
20

  
21
        api.downloads file.downloads
22
	api.version_id version_id unless version_id.nil?
23
      end
24
    end
25
  end
26
end
config/routes.rb
125 125
    get 'versions.:format', :to => 'versions#index'
126 126
    get 'roadmap', :to => 'versions#index', :format => false
127 127
    get 'versions', :to => 'versions#index'
128
    post 'versions/:version_id/files.:format' => 'files#create'
128 129

  
129 130
    resources :news, :except => [:show, :edit, :update, :destroy]
130 131
    resources :time_entries, :controller => 'timelog', :except => [:show, :edit, :update, :destroy] do
test/integration/api_test/api_routing_test.rb
32 32
    should_route 'GET /enumerations/issue_priorities' => 'enumerations#index', :type => 'issue_priorities'
33 33
  end
34 34

  
35
  def test_files
36
    should_route 'GET /projects/foo/files' => 'files#index', :project_id => 'foo'
37
    should_route 'POST /projects/foo/files' => 'files#create', :project_id => 'foo'
38
    should_route 'POST /projects/foo/versions/123/files' => 'files#create', :project_id => 'foo', :version_id => '123'
39
  end
40

  
35 41
  def test_groups
36 42
    should_route 'GET /groups' => 'groups#index'
37 43
    should_route 'POST /groups' => 'groups#create'
test/integration/api_test/files_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2015  Savoir-Faire Linux Inc.
3
# Author: Lucile Quirion <lucile.quirion@savoirfairelinux.com>
4
#
5
# This program is free software; you can redistribute it and/or
6
# modify it under the terms of the GNU General Public License
7
# as published by the Free Software Foundation; either version 2
8
# of the License, or (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18

  
19
require File.expand_path('../../../test_helper', __FILE__)
20

  
21
class Redmine::ApiTest::FilesTest < Redmine::ApiTest::Base
22
  fixtures :projects,
23
           :users,
24
           :members,
25
           :roles,
26
           :member_roles,
27
           :enabled_modules,
28
           :attachments,
29
           :versions
30

  
31
  test "GET /projects/:project_id/files.xml should return the list of uploaded files" do
32
    get '/projects/1/files.xml', {}, credentials('jsmith')
33
    assert_response :success
34
    assert_select 'files file id', :text => '8'
35
  end
36

  
37
  test "POST /projects/:project_id/files.json should create a file" do
38
    set_tmp_attachments_directory
39
    post '/uploads.xml', 'File content', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
40
    token = Attachment.last.token
41
    payload = <<-JSON
42
{ "attachments":
43
  { "file_1":
44
    {"token": "#{token}" }
45
  }
46
}
47
    JSON
48
    post '/projects/1/files.json', payload, {"CONTENT_TYPE" => 'application/json'}.merge(credentials('jsmith'))
49
    assert_response :success
50
    assert_equal 1, Attachment.last.container_id
51
    assert_equal "Project", Attachment.last.container_type
52
  end
53

  
54
  test "POST /projects/:project_id/files.xml should create a file" do
55
    set_tmp_attachments_directory
56
    post '/uploads.xml', 'File content', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
57
    token = Attachment.last.token
58
    payload = <<-XML
59
<attachments>
60
  <file_1>
61
    <token>#{token}</token>
62
  </file_1>
63
</attachments>
64
    XML
65
    post '/projects/1/files.xml', payload, {"CONTENT_TYPE" => 'application/xml'}.merge(credentials('jsmith'))
66
    assert_response :success
67
    assert_equal 1, Attachment.last.container_id
68
    assert_equal "Project", Attachment.last.container_type
69
  end
70

  
71
  test "POST /projects/:project_id/files.json should accept :filename, :description, :content_type as parameters" do
72
    set_tmp_attachments_directory
73
    post '/uploads.xml', 'File content', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
74
    token = Attachment.last.token
75
    payload = <<-JSON
76
{ "attachments":
77
  { "file_1":
78
    { "filename": "New filename",
79
      "description": "New description",
80
      "content_type": "application/txt",
81
      "token": "#{token}"
82
    }
83
  }
84
}
85
    JSON
86
    post '/projects/1/files.json', payload, {"CONTENT_TYPE" => 'application/json'}.merge(credentials('jsmith'))
87
    assert_response :success
88
    assert_equal "New filename", Attachment.last.filename
89
    assert_equal "New description", Attachment.last.description
90
    assert_equal "application/txt", Attachment.last.content_type
91
  end
92

  
93
  test "POST /projects/:project_id/versions/:version_id/files.json should attach an attachment to a version" do
94
    set_tmp_attachments_directory
95
    post '/uploads.xml', 'File content', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
96
    token = Attachment.last.token
97
    payload = <<-JSON
98
{ "attachments":
99
  { "1":
100
    { "token": "#{token}" }
101
  }
102
}
103
    JSON
104
    post '/projects/1/versions/3/files.json', payload, {"CONTENT_TYPE" => 'application/json'}.merge(credentials('jsmith'))
105
    assert_equal 3, Attachment.last.container_id
106
    assert_equal "Version", Attachment.last.container_type
107
  end
108

  
109
  test "POST /projects/:project_id/files.json should accept :version_id to attach the file to a version" do
110
    set_tmp_attachments_directory
111
    post '/uploads.xml', 'File content', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
112
    token = Attachment.last.token
113
    payload = <<-JSON
114
{ "version_id": 3,
115
  "attachments":
116
  { "1":
117
    { "filename": "New filename",
118
      "description": "New description",
119
      "token": "#{token}"
120
    }
121
  }
122
}
123
    JSON
124
    post '/projects/1/files.json', payload, {"CONTENT_TYPE" => 'application/json'}.merge(credentials('jsmith'))
125
    assert_equal 3, Attachment.last.container_id
126
    assert_equal "Version", Attachment.last.container_type
127
  end
128
end
(1-1/3)