##// 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
@@ -1,87 +1,93
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class AttachmentsController < ApplicationController
19 19 before_filter :find_project
20 20 before_filter :file_readable, :read_authorize, :except => :destroy
21 21 before_filter :delete_authorize, :only => :destroy
22 22
23 verify :method => :post, :only => :destroy
23 accept_api_auth :show, :download
24 24
25 25 def show
26 if @attachment.is_diff?
27 @diff = File.new(@attachment.diskfile, "rb").read
28 render :action => 'diff'
29 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
30 @content = File.new(@attachment.diskfile, "rb").read
31 render :action => 'file'
32 else
33 download
26 respond_to do |format|
27 format.html {
28 if @attachment.is_diff?
29 @diff = File.new(@attachment.diskfile, "rb").read
30 render :action => 'diff'
31 elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
32 @content = File.new(@attachment.diskfile, "rb").read
33 render :action => 'file'
34 else
35 download
36 end
37 }
38 format.api
34 39 end
35 40 end
36 41
37 42 def download
38 43 if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project)
39 44 @attachment.increment_download
40 45 end
41 46
42 47 # images are sent inline
43 48 send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
44 49 :type => detect_content_type(@attachment),
45 50 :disposition => (@attachment.image? ? 'inline' : 'attachment')
46 51
47 52 end
48 53
54 verify :method => :post, :only => :destroy
49 55 def destroy
50 56 # Make sure association callbacks are called
51 57 @attachment.container.attachments.delete(@attachment)
52 58 redirect_to :back
53 59 rescue ::ActionController::RedirectBackError
54 60 redirect_to :controller => 'projects', :action => 'show', :id => @project
55 61 end
56 62
57 63 private
58 64 def find_project
59 65 @attachment = Attachment.find(params[:id])
60 66 # Show 404 if the filename in the url is wrong
61 67 raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
62 68 @project = @attachment.project
63 69 rescue ActiveRecord::RecordNotFound
64 70 render_404
65 71 end
66 72
67 73 # Checks that the file exists and is readable
68 74 def file_readable
69 75 @attachment.readable? ? true : render_404
70 76 end
71 77
72 78 def read_authorize
73 79 @attachment.visible? ? true : deny_access
74 80 end
75 81
76 82 def delete_authorize
77 83 @attachment.deletable? ? true : deny_access
78 84 end
79 85
80 86 def detect_content_type(attachment)
81 87 content_type = attachment.content_type
82 88 if content_type.blank?
83 89 content_type = Redmine::MimeType.of(attachment.filename)
84 90 end
85 91 content_type.to_s
86 92 end
87 93 end
@@ -1,46 +1,59
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module AttachmentsHelper
19 19 # Displays view/delete links to the attachments of the given object
20 20 # Options:
21 21 # :author -- author names are not displayed if set to false
22 22 def link_to_attachments(container, options = {})
23 23 options.assert_valid_keys(:author)
24 24
25 25 if container.attachments.any?
26 26 options = {:deletable => container.attachments_deletable?, :author => true}.merge(options)
27 27 render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options}
28 28 end
29 29 end
30 30
31 31 def to_utf8(str)
32 32 if str.respond_to?(:force_encoding)
33 33 str.force_encoding('UTF-8')
34 34 return str if str.valid_encoding?
35 35 else
36 36 return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
37 37 end
38 38
39 39 begin
40 40 Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
41 41 rescue Iconv::InvalidEncoding
42 42 # "UTF-8//IGNORE" is not supported on some OS
43 43 str
44 44 end
45 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 59 end
@@ -1,61 +1,67
1 1 api.issue do
2 2 api.id @issue.id
3 3 api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil?
4 4 api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil?
5 5 api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil?
6 6 api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil?
7 7 api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil?
8 8 api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil?
9 9 api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil?
10 10 api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil?
11 11 api.parent(:id => @issue.parent_id) unless @issue.parent.nil?
12 12
13 13 api.subject @issue.subject
14 14 api.description @issue.description
15 15 api.start_date @issue.start_date
16 16 api.due_date @issue.due_date
17 17 api.done_ratio @issue.done_ratio
18 18 api.estimated_hours @issue.estimated_hours
19 19 api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project)
20 20
21 21 render_api_custom_values @issue.custom_field_values, api
22 22
23 23 api.created_on @issue.created_on
24 24 api.updated_on @issue.updated_on
25 25
26 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 34 api.array :relations do
29 35 @relations.each do |relation|
30 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)
31 37 end
32 38 end if include_in_api_response?('relations') && @relations.present?
33 39
34 40 api.array :changesets do
35 41 @issue.changesets.each do |changeset|
36 42 api.changeset :revision => changeset.revision do
37 43 api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
38 44 api.comments changeset.comments
39 45 api.committed_on changeset.committed_on
40 46 end
41 47 end
42 48 end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project)
43 49
44 50 api.array :journals do
45 51 @issue.journals.each do |journal|
46 52 api.journal :id => journal.id do
47 53 api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
48 54 api.notes journal.notes
49 55 api.created_on journal.created_on
50 56 api.array :details do
51 57 journal.details.each do |detail|
52 58 api.detail :property => detail.property, :name => detail.prop_key do
53 59 api.old_value detail.old_value
54 60 api.new_value detail.value
55 61 end
56 62 end
57 63 end
58 64 end
59 65 end
60 66 end if include_in_api_response?('journals')
61 67 end
@@ -1,256 +1,257
1 1 ActionController::Routing::Routes.draw do |map|
2 2 # Add your own custom routes here.
3 3 # The priority is based upon order of creation: first created -> highest priority.
4 4
5 5 # Here's a sample route:
6 6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 7 # Keep in mind you can assign values other than :controller and :action
8 8
9 9 map.home '', :controller => 'welcome'
10 10
11 11 map.signin 'login', :controller => 'account', :action => 'login'
12 12 map.signout 'logout', :controller => 'account', :action => 'logout'
13 13
14 14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
15 15 map.connect 'help/:ctrl/:page', :controller => 'help'
16 16
17 17 map.with_options :controller => 'time_entry_reports', :action => 'report',:conditions => {:method => :get} do |time_report|
18 18 time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report'
19 19 time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report.:format'
20 20 time_report.connect 'projects/:project_id/time_entries/report'
21 21 time_report.connect 'projects/:project_id/time_entries/report.:format'
22 22 time_report.connect 'time_entries/report'
23 23 time_report.connect 'time_entries/report.:format'
24 24 end
25 25
26 26 map.bulk_edit_time_entry 'time_entries/bulk_edit',
27 27 :controller => 'timelog', :action => 'bulk_edit', :conditions => { :method => :get }
28 28 map.bulk_update_time_entry 'time_entries/bulk_edit',
29 29 :controller => 'timelog', :action => 'bulk_update', :conditions => { :method => :post }
30 30 map.time_entries_context_menu '/time_entries/context_menu',
31 31 :controller => 'context_menus', :action => 'time_entries'
32 32 # TODO: wasteful since this is also nested under issues, projects, and projects/issues
33 33 map.resources :time_entries, :controller => 'timelog'
34 34
35 35 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
36 36 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
37 37 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
38 38
39 39 map.with_options :controller => 'messages' do |messages_routes|
40 40 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
41 41 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
42 42 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
43 43 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
44 44 end
45 45 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
46 46 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
47 47 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
48 48 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
49 49 end
50 50 end
51 51
52 52 map.with_options :controller => 'boards' do |board_routes|
53 53 board_routes.with_options :conditions => {:method => :get} do |board_views|
54 54 board_views.connect 'projects/:project_id/boards', :action => 'index'
55 55 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
56 56 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
57 57 board_views.connect 'projects/:project_id/boards/:id.:format', :action => 'show'
58 58 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
59 59 end
60 60 board_routes.with_options :conditions => {:method => :post} do |board_actions|
61 61 board_actions.connect 'projects/:project_id/boards', :action => 'new'
62 62 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
63 63 end
64 64 end
65 65
66 66 map.with_options :controller => 'documents' do |document_routes|
67 67 document_routes.with_options :conditions => {:method => :get} do |document_views|
68 68 document_views.connect 'projects/:project_id/documents', :action => 'index'
69 69 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
70 70 document_views.connect 'documents/:id', :action => 'show'
71 71 document_views.connect 'documents/:id/edit', :action => 'edit'
72 72 end
73 73 document_routes.with_options :conditions => {:method => :post} do |document_actions|
74 74 document_actions.connect 'projects/:project_id/documents', :action => 'new'
75 75 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
76 76 end
77 77 end
78 78
79 79 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
80 80 map.resources :queries, :only => [:index]
81 81
82 82 # Misc issue routes. TODO: move into resources
83 83 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues'
84 84 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
85 85 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
86 86 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
87 87 map.bulk_edit_issue 'issues/bulk_edit', :controller => 'issues', :action => 'bulk_edit', :conditions => { :method => :get }
88 88 map.bulk_update_issue 'issues/bulk_edit', :controller => 'issues', :action => 'bulk_update', :conditions => { :method => :post }
89 89 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
90 90 map.connect '/issues/:id/destroy', :controller => 'issues', :action => 'destroy', :conditions => { :method => :post } # legacy
91 91
92 92 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
93 93 gantts_routes.connect '/projects/:project_id/issues/gantt'
94 94 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
95 95 gantts_routes.connect '/issues/gantt.:format'
96 96 end
97 97
98 98 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
99 99 calendars_routes.connect '/projects/:project_id/issues/calendar'
100 100 calendars_routes.connect '/issues/calendar'
101 101 end
102 102
103 103 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
104 104 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
105 105 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
106 106 end
107 107
108 108 # Following two routes conflict with the resources because #index allows POST
109 109 map.connect '/issues', :controller => 'issues', :action => 'index', :conditions => { :method => :post }
110 110 map.connect '/issues/create', :controller => 'issues', :action => 'index', :conditions => { :method => :post }
111 111
112 112 map.resources :issues, :member => { :edit => :post }, :collection => {} do |issues|
113 113 issues.resources :time_entries, :controller => 'timelog'
114 114 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
115 115 end
116 116
117 117 map.resources :issues, :path_prefix => '/projects/:project_id', :collection => { :create => :post } do |issues|
118 118 issues.resources :time_entries, :controller => 'timelog'
119 119 end
120 120
121 121 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
122 122
123 123 map.with_options :controller => 'users' do |users|
124 124 users.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil, :conditions => {:method => :get}
125 125
126 126 users.with_options :conditions => {:method => :post} do |user_actions|
127 127 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
128 128 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
129 129 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
130 130 end
131 131 end
132 132
133 133 map.resources :users, :member => {
134 134 :edit_membership => :post,
135 135 :destroy_membership => :post
136 136 }
137 137
138 138 # For nice "roadmap" in the url for the index action
139 139 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
140 140
141 141 map.all_news 'news', :controller => 'news', :action => 'index'
142 142 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
143 143 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
144 144 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
145 145 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
146 146
147 147 map.resources :projects, :member => {
148 148 :copy => [:get, :post],
149 149 :settings => :get,
150 150 :modules => :post,
151 151 :archive => :post,
152 152 :unarchive => :post
153 153 } do |project|
154 154 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
155 155 project.resources :files, :only => [:index, :new, :create]
156 156 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
157 157 project.resources :news, :shallow => true
158 158 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id'
159 159
160 160 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
161 161 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
162 162 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
163 163 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
164 164 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
165 165 project.resources :wiki, :except => [:new, :create], :member => {
166 166 :rename => [:get, :post],
167 167 :history => :get,
168 168 :preview => :any,
169 169 :protect => :post,
170 170 :add_attachment => :post
171 171 }, :collection => {
172 172 :export => :get,
173 173 :date_index => :get
174 174 }
175 175
176 176 end
177 177
178 178 # Destroy uses a get request to prompt the user before the actual DELETE request
179 179 map.project_destroy_confirm 'projects/:id/destroy', :controller => 'projects', :action => 'destroy', :conditions => {:method => :get}
180 180
181 181 # TODO: port to be part of the resources route(s)
182 182 map.with_options :controller => 'projects' do |project_mapper|
183 183 project_mapper.with_options :conditions => {:method => :get} do |project_views|
184 184 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
185 185 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
186 186 end
187 187 end
188 188
189 189 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
190 190 activity.connect 'projects/:id/activity'
191 191 activity.connect 'projects/:id/activity.:format'
192 192 activity.connect 'activity', :id => nil
193 193 activity.connect 'activity.:format', :id => nil
194 194 end
195 195
196 196
197 197 map.with_options :controller => 'issue_categories' do |categories|
198 198 categories.connect 'projects/:project_id/issue_categories/new', :action => 'new'
199 199 end
200 200
201 201 map.with_options :controller => 'repositories' do |repositories|
202 202 repositories.with_options :conditions => {:method => :get} do |repository_views|
203 203 repository_views.connect 'projects/:id/repository', :action => 'show'
204 204 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
205 205 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
206 206 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
207 207 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
208 208 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
209 209 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
210 210 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
211 211 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
212 212 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
213 213 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
214 214 # TODO: why the following route is required?
215 215 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
216 216 repository_views.connect 'projects/:id/repository/:action/*path'
217 217 end
218 218
219 219 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
220 220 end
221 221
222 222 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
223 map.connect 'attachments/:id.:format', :controller => 'attachments', :action => 'show', :id => /\d+/
223 224 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
224 225 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
225 226
226 227 map.resources :groups
227 228
228 229 #left old routes at the bottom for backwards compat
229 230 map.connect 'projects/:project_id/queries/:action', :controller => 'queries'
230 231 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
231 232 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
232 233 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
233 234 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
234 235 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
235 236 map.connect 'projects/:project_id/news/:action', :controller => 'news'
236 237 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
237 238 map.with_options :controller => 'repositories' do |omap|
238 239 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
239 240 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
240 241 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
241 242 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
242 243 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
243 244 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
244 245 end
245 246
246 247 map.with_options :controller => 'sys' do |sys|
247 248 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
248 249 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
249 250 end
250 251
251 252 # Install the default route as the lowest priority.
252 253 map.connect ':controller/:action/:id'
253 254 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
254 255 # Used for OpenID
255 256 map.root :controller => 'account', :action => 'login'
256 257 end
@@ -1,521 +1,547
1 1 # Redmine - project management software
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 21 fixtures :projects,
22 22 :users,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :issues,
27 27 :issue_statuses,
28 28 :versions,
29 29 :trackers,
30 30 :projects_trackers,
31 31 :issue_categories,
32 32 :enabled_modules,
33 33 :enumerations,
34 34 :attachments,
35 35 :workflows,
36 36 :custom_fields,
37 37 :custom_values,
38 38 :custom_fields_projects,
39 39 :custom_fields_trackers,
40 40 :time_entries,
41 41 :journals,
42 42 :journal_details,
43 :queries
43 :queries,
44 :attachments
44 45
45 46 def setup
46 47 Setting.rest_api_enabled = '1'
47 48 end
48 49
49 50 context "/index.xml" do
50 51 # Use a private project to make sure auth is really working and not just
51 52 # only showing public issues.
52 53 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
53 54
54 55 should "contain metadata" do
55 56 get '/issues.xml'
56 57
57 58 assert_tag :tag => 'issues',
58 59 :attributes => {
59 60 :type => 'array',
60 61 :total_count => assigns(:issue_count),
61 62 :limit => 25,
62 63 :offset => 0
63 64 }
64 65 end
65 66
66 67 context "with offset and limit" do
67 68 should "use the params" do
68 69 get '/issues.xml?offset=2&limit=3'
69 70
70 71 assert_equal 3, assigns(:limit)
71 72 assert_equal 2, assigns(:offset)
72 73 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
73 74 end
74 75 end
75 76
76 77 context "with nometa param" do
77 78 should "not contain metadata" do
78 79 get '/issues.xml?nometa=1'
79 80
80 81 assert_tag :tag => 'issues',
81 82 :attributes => {
82 83 :type => 'array',
83 84 :total_count => nil,
84 85 :limit => nil,
85 86 :offset => nil
86 87 }
87 88 end
88 89 end
89 90
90 91 context "with nometa header" do
91 92 should "not contain metadata" do
92 93 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
93 94
94 95 assert_tag :tag => 'issues',
95 96 :attributes => {
96 97 :type => 'array',
97 98 :total_count => nil,
98 99 :limit => nil,
99 100 :offset => nil
100 101 }
101 102 end
102 103 end
103 104 end
104 105
105 106 context "/index.json" do
106 107 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
107 108 end
108 109
109 110 context "/index.xml with filter" do
110 111 should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5")
111 112
112 113 should "show only issues with the status_id" do
113 114 get '/issues.xml?status_id=5'
114 115 assert_tag :tag => 'issues',
115 116 :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}),
116 117 :only => { :tag => 'issue' } }
117 118 end
118 119 end
119 120
120 121 context "/index.json with filter" do
121 122 should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5")
122 123
123 124 should "show only issues with the status_id" do
124 125 get '/issues.json?status_id=5'
125 126
126 127 json = ActiveSupport::JSON.decode(response.body)
127 128 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
128 129 assert_equal 3, status_ids_used.length
129 130 assert status_ids_used.all? {|id| id == 5 }
130 131 end
131 132
132 133 end
133 134
134 135 # Issue 6 is on a private project
135 136 context "/issues/6.xml" do
136 137 should_allow_api_authentication(:get, "/issues/6.xml")
137 138 end
138 139
139 140 context "/issues/6.json" do
140 141 should_allow_api_authentication(:get, "/issues/6.json")
141 142 end
142 143
143 144 context "GET /issues/:id" do
144 145 context "with journals" do
145 146 context ".xml" do
146 147 should "display journals" do
147 148 get '/issues/1.xml?include=journals'
148 149
149 150 assert_tag :tag => 'issue',
150 151 :child => {
151 152 :tag => 'journals',
152 153 :attributes => { :type => 'array' },
153 154 :child => {
154 155 :tag => 'journal',
155 156 :attributes => { :id => '1'},
156 157 :child => {
157 158 :tag => 'details',
158 159 :attributes => { :type => 'array' },
159 160 :child => {
160 161 :tag => 'detail',
161 162 :attributes => { :name => 'status_id' },
162 163 :child => {
163 164 :tag => 'old_value',
164 165 :content => '1',
165 166 :sibling => {
166 167 :tag => 'new_value',
167 168 :content => '2'
168 169 }
169 170 }
170 171 }
171 172 }
172 173 }
173 174 }
174 175 end
175 176 end
176 177 end
177 178
178 179 context "with custom fields" do
179 180 context ".xml" do
180 181 should "display custom fields" do
181 182 get '/issues/3.xml'
182 183
183 184 assert_tag :tag => 'issue',
184 185 :child => {
185 186 :tag => 'custom_fields',
186 187 :attributes => { :type => 'array' },
187 188 :child => {
188 189 :tag => 'custom_field',
189 190 :attributes => { :id => '1'},
190 191 :child => {
191 192 :tag => 'value',
192 193 :content => 'MySQL'
193 194 }
194 195 }
195 196 }
196 197
197 198 assert_nothing_raised do
198 199 Hash.from_xml(response.body).to_xml
199 200 end
200 201 end
201 202 end
202 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 230 context "with subtasks" do
205 231 setup do
206 232 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
207 233 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
208 234 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
209 235 end
210 236
211 237 context ".xml" do
212 238 should "display children" do
213 239 get '/issues/1.xml?include=children'
214 240
215 241 assert_tag :tag => 'issue',
216 242 :child => {
217 243 :tag => 'children',
218 244 :children => {:count => 2},
219 245 :child => {
220 246 :tag => 'issue',
221 247 :attributes => {:id => @c1.id.to_s},
222 248 :child => {
223 249 :tag => 'subject',
224 250 :content => 'child c1',
225 251 :sibling => {
226 252 :tag => 'children',
227 253 :children => {:count => 1},
228 254 :child => {
229 255 :tag => 'issue',
230 256 :attributes => {:id => @c3.id.to_s}
231 257 }
232 258 }
233 259 }
234 260 }
235 261 }
236 262 end
237 263
238 264 context ".json" do
239 265 should "display children" do
240 266 get '/issues/1.json?include=children'
241 267
242 268 json = ActiveSupport::JSON.decode(response.body)
243 269 assert_equal([
244 270 {
245 271 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
246 272 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
247 273 },
248 274 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
249 275 ],
250 276 json['issue']['children'])
251 277 end
252 278 end
253 279 end
254 280 end
255 281 end
256 282
257 283 context "POST /issues.xml" do
258 284 should_allow_api_authentication(:post,
259 285 '/issues.xml',
260 286 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
261 287 {:success_code => :created})
262 288
263 289 should "create an issue with the attributes" do
264 290 assert_difference('Issue.count') do
265 291 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
266 292 end
267 293
268 294 issue = Issue.first(:order => 'id DESC')
269 295 assert_equal 1, issue.project_id
270 296 assert_equal 2, issue.tracker_id
271 297 assert_equal 3, issue.status_id
272 298 assert_equal 'API test', issue.subject
273 299
274 300 assert_response :created
275 301 assert_equal 'application/xml', @response.content_type
276 302 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
277 303 end
278 304 end
279 305
280 306 context "POST /issues.xml with failure" do
281 307 should_allow_api_authentication(:post,
282 308 '/issues.xml',
283 309 {:issue => {:project_id => 1}},
284 310 {:success_code => :unprocessable_entity})
285 311
286 312 should "have an errors tag" do
287 313 assert_no_difference('Issue.count') do
288 314 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
289 315 end
290 316
291 317 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
292 318 end
293 319 end
294 320
295 321 context "POST /issues.json" do
296 322 should_allow_api_authentication(:post,
297 323 '/issues.json',
298 324 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
299 325 {:success_code => :created})
300 326
301 327 should "create an issue with the attributes" do
302 328 assert_difference('Issue.count') do
303 329 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
304 330 end
305 331
306 332 issue = Issue.first(:order => 'id DESC')
307 333 assert_equal 1, issue.project_id
308 334 assert_equal 2, issue.tracker_id
309 335 assert_equal 3, issue.status_id
310 336 assert_equal 'API test', issue.subject
311 337 end
312 338
313 339 end
314 340
315 341 context "POST /issues.json with failure" do
316 342 should_allow_api_authentication(:post,
317 343 '/issues.json',
318 344 {:issue => {:project_id => 1}},
319 345 {:success_code => :unprocessable_entity})
320 346
321 347 should "have an errors element" do
322 348 assert_no_difference('Issue.count') do
323 349 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
324 350 end
325 351
326 352 json = ActiveSupport::JSON.decode(response.body)
327 353 assert json['errors'].include?(['subject', "can't be blank"])
328 354 end
329 355 end
330 356
331 357 # Issue 6 is on a private project
332 358 context "PUT /issues/6.xml" do
333 359 setup do
334 360 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
335 361 @headers = { :authorization => credentials('jsmith') }
336 362 end
337 363
338 364 should_allow_api_authentication(:put,
339 365 '/issues/6.xml',
340 366 {:issue => {:subject => 'API update', :notes => 'A new note'}},
341 367 {:success_code => :ok})
342 368
343 369 should "not create a new issue" do
344 370 assert_no_difference('Issue.count') do
345 371 put '/issues/6.xml', @parameters, @headers
346 372 end
347 373 end
348 374
349 375 should "create a new journal" do
350 376 assert_difference('Journal.count') do
351 377 put '/issues/6.xml', @parameters, @headers
352 378 end
353 379 end
354 380
355 381 should "add the note to the journal" do
356 382 put '/issues/6.xml', @parameters, @headers
357 383
358 384 journal = Journal.last
359 385 assert_equal "A new note", journal.notes
360 386 end
361 387
362 388 should "update the issue" do
363 389 put '/issues/6.xml', @parameters, @headers
364 390
365 391 issue = Issue.find(6)
366 392 assert_equal "API update", issue.subject
367 393 end
368 394
369 395 end
370 396
371 397 context "PUT /issues/3.xml with custom fields" do
372 398 setup do
373 399 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
374 400 @headers = { :authorization => credentials('jsmith') }
375 401 end
376 402
377 403 should "update custom fields" do
378 404 assert_no_difference('Issue.count') do
379 405 put '/issues/3.xml', @parameters, @headers
380 406 end
381 407
382 408 issue = Issue.find(3)
383 409 assert_equal '150', issue.custom_value_for(2).value
384 410 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
385 411 end
386 412 end
387 413
388 414 context "PUT /issues/6.xml with failed update" do
389 415 setup do
390 416 @parameters = {:issue => {:subject => ''}}
391 417 @headers = { :authorization => credentials('jsmith') }
392 418 end
393 419
394 420 should_allow_api_authentication(:put,
395 421 '/issues/6.xml',
396 422 {:issue => {:subject => ''}}, # Missing subject should fail
397 423 {:success_code => :unprocessable_entity})
398 424
399 425 should "not create a new issue" do
400 426 assert_no_difference('Issue.count') do
401 427 put '/issues/6.xml', @parameters, @headers
402 428 end
403 429 end
404 430
405 431 should "not create a new journal" do
406 432 assert_no_difference('Journal.count') do
407 433 put '/issues/6.xml', @parameters, @headers
408 434 end
409 435 end
410 436
411 437 should "have an errors tag" do
412 438 put '/issues/6.xml', @parameters, @headers
413 439
414 440 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
415 441 end
416 442 end
417 443
418 444 context "PUT /issues/6.json" do
419 445 setup do
420 446 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
421 447 @headers = { :authorization => credentials('jsmith') }
422 448 end
423 449
424 450 should_allow_api_authentication(:put,
425 451 '/issues/6.json',
426 452 {:issue => {:subject => 'API update', :notes => 'A new note'}},
427 453 {:success_code => :ok})
428 454
429 455 should "not create a new issue" do
430 456 assert_no_difference('Issue.count') do
431 457 put '/issues/6.json', @parameters, @headers
432 458 end
433 459 end
434 460
435 461 should "create a new journal" do
436 462 assert_difference('Journal.count') do
437 463 put '/issues/6.json', @parameters, @headers
438 464 end
439 465 end
440 466
441 467 should "add the note to the journal" do
442 468 put '/issues/6.json', @parameters, @headers
443 469
444 470 journal = Journal.last
445 471 assert_equal "A new note", journal.notes
446 472 end
447 473
448 474 should "update the issue" do
449 475 put '/issues/6.json', @parameters, @headers
450 476
451 477 issue = Issue.find(6)
452 478 assert_equal "API update", issue.subject
453 479 end
454 480
455 481 end
456 482
457 483 context "PUT /issues/6.json with failed update" do
458 484 setup do
459 485 @parameters = {:issue => {:subject => ''}}
460 486 @headers = { :authorization => credentials('jsmith') }
461 487 end
462 488
463 489 should_allow_api_authentication(:put,
464 490 '/issues/6.json',
465 491 {:issue => {:subject => ''}}, # Missing subject should fail
466 492 {:success_code => :unprocessable_entity})
467 493
468 494 should "not create a new issue" do
469 495 assert_no_difference('Issue.count') do
470 496 put '/issues/6.json', @parameters, @headers
471 497 end
472 498 end
473 499
474 500 should "not create a new journal" do
475 501 assert_no_difference('Journal.count') do
476 502 put '/issues/6.json', @parameters, @headers
477 503 end
478 504 end
479 505
480 506 should "have an errors attribute" do
481 507 put '/issues/6.json', @parameters, @headers
482 508
483 509 json = ActiveSupport::JSON.decode(response.body)
484 510 assert json['errors'].include?(['subject', "can't be blank"])
485 511 end
486 512 end
487 513
488 514 context "DELETE /issues/1.xml" do
489 515 should_allow_api_authentication(:delete,
490 516 '/issues/6.xml',
491 517 {},
492 518 {:success_code => :ok})
493 519
494 520 should "delete the issue" do
495 521 assert_difference('Issue.count',-1) do
496 522 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
497 523 end
498 524
499 525 assert_nil Issue.find_by_id(6)
500 526 end
501 527 end
502 528
503 529 context "DELETE /issues/1.json" do
504 530 should_allow_api_authentication(:delete,
505 531 '/issues/6.json',
506 532 {},
507 533 {:success_code => :ok})
508 534
509 535 should "delete the issue" do
510 536 assert_difference('Issue.count',-1) do
511 537 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
512 538 end
513 539
514 540 assert_nil Issue.find_by_id(6)
515 541 end
516 542 end
517 543
518 544 def credentials(user, password=nil)
519 545 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
520 546 end
521 547 end
@@ -1,395 +1,397
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RoutingTest < ActionController::IntegrationTest
21 21 context "activities" do
22 22 should_route :get, "/activity", :controller => 'activities', :action => 'index', :id => nil
23 23 should_route :get, "/activity.atom", :controller => 'activities', :action => 'index', :id => nil, :format => 'atom'
24 24 end
25 25
26 26 context "attachments" do
27 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 30 should_route :get, "/attachments/1/filename.ext", :controller => 'attachments', :action => 'show', :id => '1', :filename => 'filename.ext'
29 31 should_route :get, "/attachments/download/1", :controller => 'attachments', :action => 'download', :id => '1'
30 32 should_route :get, "/attachments/download/1/filename.ext", :controller => 'attachments', :action => 'download', :id => '1', :filename => 'filename.ext'
31 33 end
32 34
33 35 context "boards" do
34 36 should_route :get, "/projects/world_domination/boards", :controller => 'boards', :action => 'index', :project_id => 'world_domination'
35 37 should_route :get, "/projects/world_domination/boards/new", :controller => 'boards', :action => 'new', :project_id => 'world_domination'
36 38 should_route :get, "/projects/world_domination/boards/44", :controller => 'boards', :action => 'show', :project_id => 'world_domination', :id => '44'
37 39 should_route :get, "/projects/world_domination/boards/44.atom", :controller => 'boards', :action => 'show', :project_id => 'world_domination', :id => '44', :format => 'atom'
38 40 should_route :get, "/projects/world_domination/boards/44/edit", :controller => 'boards', :action => 'edit', :project_id => 'world_domination', :id => '44'
39 41
40 42 should_route :post, "/projects/world_domination/boards/new", :controller => 'boards', :action => 'new', :project_id => 'world_domination'
41 43 should_route :post, "/projects/world_domination/boards/44/edit", :controller => 'boards', :action => 'edit', :project_id => 'world_domination', :id => '44'
42 44 should_route :post, "/projects/world_domination/boards/44/destroy", :controller => 'boards', :action => 'destroy', :project_id => 'world_domination', :id => '44'
43 45
44 46 end
45 47
46 48 context "documents" do
47 49 should_route :get, "/projects/567/documents", :controller => 'documents', :action => 'index', :project_id => '567'
48 50 should_route :get, "/projects/567/documents/new", :controller => 'documents', :action => 'new', :project_id => '567'
49 51 should_route :get, "/documents/22", :controller => 'documents', :action => 'show', :id => '22'
50 52 should_route :get, "/documents/22/edit", :controller => 'documents', :action => 'edit', :id => '22'
51 53
52 54 should_route :post, "/projects/567/documents/new", :controller => 'documents', :action => 'new', :project_id => '567'
53 55 should_route :post, "/documents/567/edit", :controller => 'documents', :action => 'edit', :id => '567'
54 56 should_route :post, "/documents/567/destroy", :controller => 'documents', :action => 'destroy', :id => '567'
55 57 end
56 58
57 59 context "issues" do
58 60 # REST actions
59 61 should_route :get, "/issues", :controller => 'issues', :action => 'index'
60 62 should_route :get, "/issues.pdf", :controller => 'issues', :action => 'index', :format => 'pdf'
61 63 should_route :get, "/issues.atom", :controller => 'issues', :action => 'index', :format => 'atom'
62 64 should_route :get, "/issues.xml", :controller => 'issues', :action => 'index', :format => 'xml'
63 65 should_route :get, "/projects/23/issues", :controller => 'issues', :action => 'index', :project_id => '23'
64 66 should_route :get, "/projects/23/issues.pdf", :controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf'
65 67 should_route :get, "/projects/23/issues.atom", :controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom'
66 68 should_route :get, "/projects/23/issues.xml", :controller => 'issues', :action => 'index', :project_id => '23', :format => 'xml'
67 69 should_route :get, "/issues/64", :controller => 'issues', :action => 'show', :id => '64'
68 70 should_route :get, "/issues/64.pdf", :controller => 'issues', :action => 'show', :id => '64', :format => 'pdf'
69 71 should_route :get, "/issues/64.atom", :controller => 'issues', :action => 'show', :id => '64', :format => 'atom'
70 72 should_route :get, "/issues/64.xml", :controller => 'issues', :action => 'show', :id => '64', :format => 'xml'
71 73
72 74 should_route :get, "/projects/23/issues/new", :controller => 'issues', :action => 'new', :project_id => '23'
73 75 should_route :post, "/projects/23/issues", :controller => 'issues', :action => 'create', :project_id => '23'
74 76 should_route :post, "/issues.xml", :controller => 'issues', :action => 'create', :format => 'xml'
75 77
76 78 should_route :get, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64'
77 79 # TODO: Should use PUT
78 80 should_route :post, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64'
79 81 should_route :put, "/issues/1.xml", :controller => 'issues', :action => 'update', :id => '1', :format => 'xml'
80 82
81 83 # TODO: Should use DELETE
82 84 should_route :post, "/issues/64/destroy", :controller => 'issues', :action => 'destroy', :id => '64'
83 85 should_route :delete, "/issues/1.xml", :controller => 'issues', :action => 'destroy', :id => '1', :format => 'xml'
84 86
85 87 # Extra actions
86 88 should_route :get, "/projects/23/issues/64/copy", :controller => 'issues', :action => 'new', :project_id => '23', :copy_from => '64'
87 89
88 90 should_route :get, "/issues/move/new", :controller => 'issue_moves', :action => 'new'
89 91 should_route :post, "/issues/move", :controller => 'issue_moves', :action => 'create'
90 92
91 93 should_route :post, "/issues/1/quoted", :controller => 'journals', :action => 'new', :id => '1'
92 94
93 95 should_route :get, "/issues/calendar", :controller => 'calendars', :action => 'show'
94 96 should_route :get, "/projects/project-name/issues/calendar", :controller => 'calendars', :action => 'show', :project_id => 'project-name'
95 97
96 98 should_route :get, "/issues/gantt", :controller => 'gantts', :action => 'show'
97 99 should_route :get, "/issues/gantt.pdf", :controller => 'gantts', :action => 'show', :format => 'pdf'
98 100 should_route :get, "/projects/project-name/issues/gantt", :controller => 'gantts', :action => 'show', :project_id => 'project-name'
99 101 should_route :get, "/projects/project-name/issues/gantt.pdf", :controller => 'gantts', :action => 'show', :project_id => 'project-name', :format => 'pdf'
100 102
101 103 should_route :get, "/issues/auto_complete", :controller => 'auto_completes', :action => 'issues'
102 104
103 105 should_route :get, "/issues/preview/123", :controller => 'previews', :action => 'issue', :id => '123'
104 106 should_route :post, "/issues/preview/123", :controller => 'previews', :action => 'issue', :id => '123'
105 107 should_route :get, "/issues/context_menu", :controller => 'context_menus', :action => 'issues'
106 108 should_route :post, "/issues/context_menu", :controller => 'context_menus', :action => 'issues'
107 109
108 110 should_route :get, "/issues/changes", :controller => 'journals', :action => 'index'
109 111
110 112 should_route :get, "/issues/bulk_edit", :controller => 'issues', :action => 'bulk_edit'
111 113 should_route :post, "/issues/bulk_edit", :controller => 'issues', :action => 'bulk_update'
112 114 end
113 115
114 116 context "issue categories" do
115 117 should_route :get, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test'
116 118
117 119 should_route :post, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test'
118 120 end
119 121
120 122 context "issue relations" do
121 123 should_route :get, "/issues/1/relations", :controller => 'issue_relations', :action => 'index', :issue_id => '1'
122 124 should_route :get, "/issues/1/relations.xml", :controller => 'issue_relations', :action => 'index', :issue_id => '1', :format => 'xml'
123 125 should_route :get, "/issues/1/relations.json", :controller => 'issue_relations', :action => 'index', :issue_id => '1', :format => 'json'
124 126
125 127 should_route :post, "/issues/1/relations", :controller => 'issue_relations', :action => 'create', :issue_id => '1'
126 128 should_route :post, "/issues/1/relations.xml", :controller => 'issue_relations', :action => 'create', :issue_id => '1', :format => 'xml'
127 129 should_route :post, "/issues/1/relations.json", :controller => 'issue_relations', :action => 'create', :issue_id => '1', :format => 'json'
128 130
129 131 should_route :get, "/relations/23", :controller => 'issue_relations', :action => 'show', :id => '23'
130 132 should_route :get, "/relations/23.xml", :controller => 'issue_relations', :action => 'show', :id => '23', :format => 'xml'
131 133 should_route :get, "/relations/23.json", :controller => 'issue_relations', :action => 'show', :id => '23', :format => 'json'
132 134
133 135 should_route :delete, "/relations/23", :controller => 'issue_relations', :action => 'destroy', :id => '23'
134 136 should_route :delete, "/relations/23.xml", :controller => 'issue_relations', :action => 'destroy', :id => '23', :format => 'xml'
135 137 should_route :delete, "/relations/23.json", :controller => 'issue_relations', :action => 'destroy', :id => '23', :format => 'json'
136 138 end
137 139
138 140 context "issue reports" do
139 141 should_route :get, "/projects/567/issues/report", :controller => 'reports', :action => 'issue_report', :id => '567'
140 142 should_route :get, "/projects/567/issues/report/assigned_to", :controller => 'reports', :action => 'issue_report_details', :id => '567', :detail => 'assigned_to'
141 143 end
142 144
143 145 context "members" do
144 146 should_route :post, "/projects/5234/members/new", :controller => 'members', :action => 'new', :id => '5234'
145 147 end
146 148
147 149 context "messages" do
148 150 should_route :get, "/boards/22/topics/2", :controller => 'messages', :action => 'show', :id => '2', :board_id => '22'
149 151 should_route :get, "/boards/lala/topics/new", :controller => 'messages', :action => 'new', :board_id => 'lala'
150 152 should_route :get, "/boards/lala/topics/22/edit", :controller => 'messages', :action => 'edit', :id => '22', :board_id => 'lala'
151 153
152 154 should_route :post, "/boards/lala/topics/new", :controller => 'messages', :action => 'new', :board_id => 'lala'
153 155 should_route :post, "/boards/lala/topics/22/edit", :controller => 'messages', :action => 'edit', :id => '22', :board_id => 'lala'
154 156 should_route :post, "/boards/22/topics/555/replies", :controller => 'messages', :action => 'reply', :id => '555', :board_id => '22'
155 157 should_route :post, "/boards/22/topics/555/destroy", :controller => 'messages', :action => 'destroy', :id => '555', :board_id => '22'
156 158 end
157 159
158 160 context "news" do
159 161 should_route :get, "/news", :controller => 'news', :action => 'index'
160 162 should_route :get, "/news.atom", :controller => 'news', :action => 'index', :format => 'atom'
161 163 should_route :get, "/news.xml", :controller => 'news', :action => 'index', :format => 'xml'
162 164 should_route :get, "/news.json", :controller => 'news', :action => 'index', :format => 'json'
163 165 should_route :get, "/projects/567/news", :controller => 'news', :action => 'index', :project_id => '567'
164 166 should_route :get, "/projects/567/news.atom", :controller => 'news', :action => 'index', :format => 'atom', :project_id => '567'
165 167 should_route :get, "/projects/567/news.xml", :controller => 'news', :action => 'index', :format => 'xml', :project_id => '567'
166 168 should_route :get, "/projects/567/news.json", :controller => 'news', :action => 'index', :format => 'json', :project_id => '567'
167 169 should_route :get, "/news/2", :controller => 'news', :action => 'show', :id => '2'
168 170 should_route :get, "/projects/567/news/new", :controller => 'news', :action => 'new', :project_id => '567'
169 171 should_route :get, "/news/234", :controller => 'news', :action => 'show', :id => '234'
170 172 should_route :get, "/news/567/edit", :controller => 'news', :action => 'edit', :id => '567'
171 173 should_route :get, "/news/preview", :controller => 'previews', :action => 'news'
172 174
173 175 should_route :post, "/projects/567/news", :controller => 'news', :action => 'create', :project_id => '567'
174 176 should_route :post, "/news/567/comments", :controller => 'comments', :action => 'create', :id => '567'
175 177
176 178 should_route :put, "/news/567", :controller => 'news', :action => 'update', :id => '567'
177 179
178 180 should_route :delete, "/news/567", :controller => 'news', :action => 'destroy', :id => '567'
179 181 should_route :delete, "/news/567/comments/15", :controller => 'comments', :action => 'destroy', :id => '567', :comment_id => '15'
180 182 end
181 183
182 184 context "projects" do
183 185 should_route :get, "/projects", :controller => 'projects', :action => 'index'
184 186 should_route :get, "/projects.atom", :controller => 'projects', :action => 'index', :format => 'atom'
185 187 should_route :get, "/projects.xml", :controller => 'projects', :action => 'index', :format => 'xml'
186 188 should_route :get, "/projects/new", :controller => 'projects', :action => 'new'
187 189 should_route :get, "/projects/test", :controller => 'projects', :action => 'show', :id => 'test'
188 190 should_route :get, "/projects/1.xml", :controller => 'projects', :action => 'show', :id => '1', :format => 'xml'
189 191 should_route :get, "/projects/4223/settings", :controller => 'projects', :action => 'settings', :id => '4223'
190 192 should_route :get, "/projects/4223/settings/members", :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members'
191 193 should_route :get, "/projects/33/files", :controller => 'files', :action => 'index', :project_id => '33'
192 194 should_route :get, "/projects/33/files/new", :controller => 'files', :action => 'new', :project_id => '33'
193 195 should_route :get, "/projects/33/roadmap", :controller => 'versions', :action => 'index', :project_id => '33'
194 196 should_route :get, "/projects/33/activity", :controller => 'activities', :action => 'index', :id => '33'
195 197 should_route :get, "/projects/33/activity.atom", :controller => 'activities', :action => 'index', :id => '33', :format => 'atom'
196 198
197 199 should_route :post, "/projects", :controller => 'projects', :action => 'create'
198 200 should_route :post, "/projects.xml", :controller => 'projects', :action => 'create', :format => 'xml'
199 201 should_route :post, "/projects/33/files", :controller => 'files', :action => 'create', :project_id => '33'
200 202 should_route :post, "/projects/64/archive", :controller => 'projects', :action => 'archive', :id => '64'
201 203 should_route :post, "/projects/64/unarchive", :controller => 'projects', :action => 'unarchive', :id => '64'
202 204
203 205 should_route :put, "/projects/64/enumerations", :controller => 'project_enumerations', :action => 'update', :project_id => '64'
204 206 should_route :put, "/projects/4223", :controller => 'projects', :action => 'update', :id => '4223'
205 207 should_route :put, "/projects/1.xml", :controller => 'projects', :action => 'update', :id => '1', :format => 'xml'
206 208
207 209 should_route :delete, "/projects/64", :controller => 'projects', :action => 'destroy', :id => '64'
208 210 should_route :delete, "/projects/1.xml", :controller => 'projects', :action => 'destroy', :id => '1', :format => 'xml'
209 211 should_route :delete, "/projects/64/enumerations", :controller => 'project_enumerations', :action => 'destroy', :project_id => '64'
210 212 end
211 213
212 214 context "queries" do
213 215 should_route :get, "/queries.xml", :controller => 'queries', :action => 'index', :format => 'xml'
214 216 should_route :get, "/queries.json", :controller => 'queries', :action => 'index', :format => 'json'
215 217
216 218 should_route :get, "/queries/new", :controller => 'queries', :action => 'new'
217 219 should_route :get, "/projects/redmine/queries/new", :controller => 'queries', :action => 'new', :project_id => 'redmine'
218 220
219 221 should_route :post, "/queries/new", :controller => 'queries', :action => 'new'
220 222 should_route :post, "/projects/redmine/queries/new", :controller => 'queries', :action => 'new', :project_id => 'redmine'
221 223 end
222 224
223 225 context "repositories" do
224 226 should_route :get, "/projects/redmine/repository", :controller => 'repositories', :action => 'show', :id => 'redmine'
225 227 should_route :get, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine'
226 228 should_route :get, "/projects/redmine/repository/revisions", :controller => 'repositories', :action => 'revisions', :id => 'redmine'
227 229 should_route :get, "/projects/redmine/repository/revisions.atom", :controller => 'repositories', :action => 'revisions', :id => 'redmine', :format => 'atom'
228 230 should_route :get, "/projects/redmine/repository/revisions/2457", :controller => 'repositories', :action => 'revision', :id => 'redmine', :rev => '2457'
229 231 should_route :get, "/projects/redmine/repository/revisions/2457/diff", :controller => 'repositories', :action => 'diff', :id => 'redmine', :rev => '2457'
230 232 should_route :get, "/projects/redmine/repository/revisions/2457/diff.diff", :controller => 'repositories', :action => 'diff', :id => 'redmine', :rev => '2457', :format => 'diff'
231 233 should_route :get, "/projects/redmine/repository/diff/path/to/file.c", :controller => 'repositories', :action => 'diff', :id => 'redmine', :path => %w[path to file.c]
232 234 should_route :get, "/projects/redmine/repository/revisions/2/diff/path/to/file.c", :controller => 'repositories', :action => 'diff', :id => 'redmine', :path => %w[path to file.c], :rev => '2'
233 235 should_route :get, "/projects/redmine/repository/browse/path/to/file.c", :controller => 'repositories', :action => 'browse', :id => 'redmine', :path => %w[path to file.c]
234 236 should_route :get, "/projects/redmine/repository/entry/path/to/file.c", :controller => 'repositories', :action => 'entry', :id => 'redmine', :path => %w[path to file.c]
235 237 should_route :get, "/projects/redmine/repository/revisions/2/entry/path/to/file.c", :controller => 'repositories', :action => 'entry', :id => 'redmine', :path => %w[path to file.c], :rev => '2'
236 238 should_route :get, "/projects/redmine/repository/raw/path/to/file.c", :controller => 'repositories', :action => 'entry', :id => 'redmine', :path => %w[path to file.c], :format => 'raw'
237 239 should_route :get, "/projects/redmine/repository/revisions/2/raw/path/to/file.c", :controller => 'repositories', :action => 'entry', :id => 'redmine', :path => %w[path to file.c], :rev => '2', :format => 'raw'
238 240 should_route :get, "/projects/redmine/repository/annotate/path/to/file.c", :controller => 'repositories', :action => 'annotate', :id => 'redmine', :path => %w[path to file.c]
239 241 should_route :get, "/projects/redmine/repository/changes/path/to/file.c", :controller => 'repositories', :action => 'changes', :id => 'redmine', :path => %w[path to file.c]
240 242 should_route :get, "/projects/redmine/repository/statistics", :controller => 'repositories', :action => 'stats', :id => 'redmine'
241 243
242 244
243 245 should_route :post, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine'
244 246 end
245 247
246 248 context "timelogs (global)" do
247 249 should_route :get, "/time_entries", :controller => 'timelog', :action => 'index'
248 250 should_route :get, "/time_entries.csv", :controller => 'timelog', :action => 'index', :format => 'csv'
249 251 should_route :get, "/time_entries.atom", :controller => 'timelog', :action => 'index', :format => 'atom'
250 252 should_route :get, "/time_entries/new", :controller => 'timelog', :action => 'new'
251 253 should_route :get, "/time_entries/22/edit", :controller => 'timelog', :action => 'edit', :id => '22'
252 254
253 255 should_route :post, "/time_entries", :controller => 'timelog', :action => 'create'
254 256
255 257 should_route :put, "/time_entries/22", :controller => 'timelog', :action => 'update', :id => '22'
256 258
257 259 should_route :delete, "/time_entries/55", :controller => 'timelog', :action => 'destroy', :id => '55'
258 260 end
259 261
260 262 context "timelogs (scoped under project)" do
261 263 should_route :get, "/projects/567/time_entries", :controller => 'timelog', :action => 'index', :project_id => '567'
262 264 should_route :get, "/projects/567/time_entries.csv", :controller => 'timelog', :action => 'index', :project_id => '567', :format => 'csv'
263 265 should_route :get, "/projects/567/time_entries.atom", :controller => 'timelog', :action => 'index', :project_id => '567', :format => 'atom'
264 266 should_route :get, "/projects/567/time_entries/new", :controller => 'timelog', :action => 'new', :project_id => '567'
265 267 should_route :get, "/projects/567/time_entries/22/edit", :controller => 'timelog', :action => 'edit', :id => '22', :project_id => '567'
266 268
267 269 should_route :post, "/projects/567/time_entries", :controller => 'timelog', :action => 'create', :project_id => '567'
268 270
269 271 should_route :put, "/projects/567/time_entries/22", :controller => 'timelog', :action => 'update', :id => '22', :project_id => '567'
270 272
271 273 should_route :delete, "/projects/567/time_entries/55", :controller => 'timelog', :action => 'destroy', :id => '55', :project_id => '567'
272 274 end
273 275
274 276 context "timelogs (scoped under issues)" do
275 277 should_route :get, "/issues/234/time_entries", :controller => 'timelog', :action => 'index', :issue_id => '234'
276 278 should_route :get, "/issues/234/time_entries.csv", :controller => 'timelog', :action => 'index', :issue_id => '234', :format => 'csv'
277 279 should_route :get, "/issues/234/time_entries.atom", :controller => 'timelog', :action => 'index', :issue_id => '234', :format => 'atom'
278 280 should_route :get, "/issues/234/time_entries/new", :controller => 'timelog', :action => 'new', :issue_id => '234'
279 281 should_route :get, "/issues/234/time_entries/22/edit", :controller => 'timelog', :action => 'edit', :id => '22', :issue_id => '234'
280 282
281 283 should_route :post, "/issues/234/time_entries", :controller => 'timelog', :action => 'create', :issue_id => '234'
282 284
283 285 should_route :put, "/issues/234/time_entries/22", :controller => 'timelog', :action => 'update', :id => '22', :issue_id => '234'
284 286
285 287 should_route :delete, "/issues/234/time_entries/55", :controller => 'timelog', :action => 'destroy', :id => '55', :issue_id => '234'
286 288 end
287 289
288 290 context "timelogs (scoped under project and issues)" do
289 291 should_route :get, "/projects/ecookbook/issues/234/time_entries", :controller => 'timelog', :action => 'index', :issue_id => '234', :project_id => 'ecookbook'
290 292 should_route :get, "/projects/ecookbook/issues/234/time_entries.csv", :controller => 'timelog', :action => 'index', :issue_id => '234', :project_id => 'ecookbook', :format => 'csv'
291 293 should_route :get, "/projects/ecookbook/issues/234/time_entries.atom", :controller => 'timelog', :action => 'index', :issue_id => '234', :project_id => 'ecookbook', :format => 'atom'
292 294 should_route :get, "/projects/ecookbook/issues/234/time_entries/new", :controller => 'timelog', :action => 'new', :issue_id => '234', :project_id => 'ecookbook'
293 295 should_route :get, "/projects/ecookbook/issues/234/time_entries/22/edit", :controller => 'timelog', :action => 'edit', :id => '22', :issue_id => '234', :project_id => 'ecookbook'
294 296
295 297 should_route :post, "/projects/ecookbook/issues/234/time_entries", :controller => 'timelog', :action => 'create', :issue_id => '234', :project_id => 'ecookbook'
296 298
297 299 should_route :put, "/projects/ecookbook/issues/234/time_entries/22", :controller => 'timelog', :action => 'update', :id => '22', :issue_id => '234', :project_id => 'ecookbook'
298 300
299 301 should_route :delete, "/projects/ecookbook/issues/234/time_entries/55", :controller => 'timelog', :action => 'destroy', :id => '55', :issue_id => '234', :project_id => 'ecookbook'
300 302 end
301 303
302 304 context "time_entry_reports" do
303 305 should_route :get, "/time_entries/report", :controller => 'time_entry_reports', :action => 'report'
304 306 should_route :get, "/projects/567/time_entries/report", :controller => 'time_entry_reports', :action => 'report', :project_id => '567'
305 307 should_route :get, "/projects/567/time_entries/report.csv", :controller => 'time_entry_reports', :action => 'report', :project_id => '567', :format => 'csv'
306 308 end
307 309
308 310 context "users" do
309 311 should_route :get, "/users", :controller => 'users', :action => 'index'
310 312 should_route :get, "/users.xml", :controller => 'users', :action => 'index', :format => 'xml'
311 313 should_route :get, "/users/44", :controller => 'users', :action => 'show', :id => '44'
312 314 should_route :get, "/users/44.xml", :controller => 'users', :action => 'show', :id => '44', :format => 'xml'
313 315 should_route :get, "/users/current", :controller => 'users', :action => 'show', :id => 'current'
314 316 should_route :get, "/users/current.xml", :controller => 'users', :action => 'show', :id => 'current', :format => 'xml'
315 317 should_route :get, "/users/new", :controller => 'users', :action => 'new'
316 318 should_route :get, "/users/444/edit", :controller => 'users', :action => 'edit', :id => '444'
317 319 should_route :get, "/users/222/edit/membership", :controller => 'users', :action => 'edit', :id => '222', :tab => 'membership'
318 320
319 321 should_route :post, "/users", :controller => 'users', :action => 'create'
320 322 should_route :post, "/users.xml", :controller => 'users', :action => 'create', :format => 'xml'
321 323 should_route :post, "/users/123/memberships", :controller => 'users', :action => 'edit_membership', :id => '123'
322 324 should_route :post, "/users/123/memberships/55", :controller => 'users', :action => 'edit_membership', :id => '123', :membership_id => '55'
323 325 should_route :post, "/users/567/memberships/12/destroy", :controller => 'users', :action => 'destroy_membership', :id => '567', :membership_id => '12'
324 326
325 327 should_route :put, "/users/444", :controller => 'users', :action => 'update', :id => '444'
326 328 should_route :put, "/users/444.xml", :controller => 'users', :action => 'update', :id => '444', :format => 'xml'
327 329
328 330 should_route :delete, "/users/44", :controller => 'users', :action => 'destroy', :id => '44'
329 331 should_route :delete, "/users/44.xml", :controller => 'users', :action => 'destroy', :id => '44', :format => 'xml'
330 332 end
331 333
332 334 context "versions" do
333 335 # /projects/foo/versions is /projects/foo/roadmap
334 336 should_route :get, "/projects/foo/versions.xml", :controller => 'versions', :action => 'index', :project_id => 'foo', :format => 'xml'
335 337 should_route :get, "/projects/foo/versions.json", :controller => 'versions', :action => 'index', :project_id => 'foo', :format => 'json'
336 338
337 339 should_route :get, "/projects/foo/versions/new", :controller => 'versions', :action => 'new', :project_id => 'foo'
338 340
339 341 should_route :post, "/projects/foo/versions", :controller => 'versions', :action => 'create', :project_id => 'foo'
340 342 should_route :post, "/projects/foo/versions.xml", :controller => 'versions', :action => 'create', :project_id => 'foo', :format => 'xml'
341 343 should_route :post, "/projects/foo/versions.json", :controller => 'versions', :action => 'create', :project_id => 'foo', :format => 'json'
342 344
343 345 should_route :get, "/versions/1", :controller => 'versions', :action => 'show', :id => '1'
344 346 should_route :get, "/versions/1.xml", :controller => 'versions', :action => 'show', :id => '1', :format => 'xml'
345 347 should_route :get, "/versions/1.json", :controller => 'versions', :action => 'show', :id => '1', :format => 'json'
346 348
347 349 should_route :get, "/versions/1/edit", :controller => 'versions', :action => 'edit', :id => '1'
348 350
349 351 should_route :put, "/versions/1", :controller => 'versions', :action => 'update', :id => '1'
350 352 should_route :put, "/versions/1.xml", :controller => 'versions', :action => 'update', :id => '1', :format => 'xml'
351 353 should_route :put, "/versions/1.json", :controller => 'versions', :action => 'update', :id => '1', :format => 'json'
352 354
353 355 should_route :delete, "/versions/1", :controller => 'versions', :action => 'destroy', :id => '1'
354 356 should_route :delete, "/versions/1.xml", :controller => 'versions', :action => 'destroy', :id => '1', :format => 'xml'
355 357 should_route :delete, "/versions/1.json", :controller => 'versions', :action => 'destroy', :id => '1', :format => 'json'
356 358
357 359 should_route :put, "/projects/foo/versions/close_completed", :controller => 'versions', :action => 'close_completed', :project_id => 'foo'
358 360 should_route :post, "/versions/1/status_by", :controller => 'versions', :action => 'status_by', :id => '1'
359 361 end
360 362
361 363 context "wiki (singular, project's pages)" do
362 364 should_route :get, "/projects/567/wiki", :controller => 'wiki', :action => 'show', :project_id => '567'
363 365 should_route :get, "/projects/567/wiki/lalala", :controller => 'wiki', :action => 'show', :project_id => '567', :id => 'lalala'
364 366 should_route :get, "/projects/567/wiki/my_page/edit", :controller => 'wiki', :action => 'edit', :project_id => '567', :id => 'my_page'
365 367 should_route :get, "/projects/1/wiki/CookBook_documentation/history", :controller => 'wiki', :action => 'history', :project_id => '1', :id => 'CookBook_documentation'
366 368 should_route :get, "/projects/1/wiki/CookBook_documentation/diff", :controller => 'wiki', :action => 'diff', :project_id => '1', :id => 'CookBook_documentation'
367 369 should_route :get, "/projects/1/wiki/CookBook_documentation/diff/2", :controller => 'wiki', :action => 'diff', :project_id => '1', :id => 'CookBook_documentation', :version => '2'
368 370 should_route :get, "/projects/1/wiki/CookBook_documentation/diff/2/vs/1", :controller => 'wiki', :action => 'diff', :project_id => '1', :id => 'CookBook_documentation', :version => '2', :version_from => '1'
369 371 should_route :get, "/projects/1/wiki/CookBook_documentation/annotate/2", :controller => 'wiki', :action => 'annotate', :project_id => '1', :id => 'CookBook_documentation', :version => '2'
370 372 should_route :get, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :project_id => '22', :id => 'ladida'
371 373 should_route :get, "/projects/567/wiki/index", :controller => 'wiki', :action => 'index', :project_id => '567'
372 374 should_route :get, "/projects/567/wiki/date_index", :controller => 'wiki', :action => 'date_index', :project_id => '567'
373 375 should_route :get, "/projects/567/wiki/export", :controller => 'wiki', :action => 'export', :project_id => '567'
374 376
375 377 should_route :post, "/projects/567/wiki/CookBook_documentation/preview", :controller => 'wiki', :action => 'preview', :project_id => '567', :id => 'CookBook_documentation'
376 378 should_route :post, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :project_id => '22', :id => 'ladida'
377 379 should_route :post, "/projects/22/wiki/ladida/protect", :controller => 'wiki', :action => 'protect', :project_id => '22', :id => 'ladida'
378 380 should_route :post, "/projects/22/wiki/ladida/add_attachment", :controller => 'wiki', :action => 'add_attachment', :project_id => '22', :id => 'ladida'
379 381
380 382 should_route :put, "/projects/567/wiki/my_page", :controller => 'wiki', :action => 'update', :project_id => '567', :id => 'my_page'
381 383
382 384 should_route :delete, "/projects/22/wiki/ladida", :controller => 'wiki', :action => 'destroy', :project_id => '22', :id => 'ladida'
383 385 end
384 386
385 387 context "wikis (plural, admin setup)" do
386 388 should_route :get, "/projects/ladida/wiki/destroy", :controller => 'wikis', :action => 'destroy', :id => 'ladida'
387 389
388 390 should_route :post, "/projects/ladida/wiki", :controller => 'wikis', :action => 'edit', :id => 'ladida'
389 391 should_route :post, "/projects/ladida/wiki/destroy", :controller => 'wikis', :action => 'destroy', :id => 'ladida'
390 392 end
391 393
392 394 context "administration panel" do
393 395 should_route :get, "/admin/projects", :controller => 'admin', :action => 'projects'
394 396 end
395 397 end
General Comments 0
You need to be logged in to leave comments. Login now