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